105 int buflen;
106 strncpy(buf, _mount_point, MAXPATHLEN);
107 buf[MAXPATHLEN-1] = '\0';
108 buflen = strlen(buf);
109 if ((buflen + strlen(cgroup_path) - strlen(_root)) > (MAXPATHLEN-1)) {
110 return;
111 }
112 strncat(buf, cgroup_path + strlen(_root), MAXPATHLEN-buflen);
113 buf[MAXPATHLEN-1] = '\0';
114 _path = os::strdup(buf);
115 }
116 }
117 }
118 }
119 }
120 }
121
122 char *subsystem_path() { return _path; }
123 };
124
125 CgroupSubsystem* memory = NULL;
126 CgroupSubsystem* cpuset = NULL;
127 CgroupSubsystem* cpu = NULL;
128 CgroupSubsystem* cpuacct = NULL;
129
130 typedef char * cptr;
131
132 PRAGMA_DIAG_PUSH
133 PRAGMA_FORMAT_NONLITERAL_IGNORED
134 template <typename T> int subsystem_file_contents(CgroupSubsystem* c,
135 const char *filename,
136 const char *scan_fmt,
137 T returnval) {
138 FILE *fp = NULL;
139 char *p;
140 char file[MAXPATHLEN+1];
141 char buf[MAXPATHLEN+1];
142
143 if (c == NULL) {
144 log_debug(os, container)("subsystem_file_contents: CgroupSubsytem* is NULL");
145 return OSCONTAINER_ERROR;
164 if (p != NULL) {
165 int matched = sscanf(p, scan_fmt, returnval);
166 if (matched == 1) {
167 fclose(fp);
168 return 0;
169 } else {
170 log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
171 }
172 } else {
173 log_debug(os, container)("Empty file %s", file);
174 }
175 } else {
176 log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno));
177 }
178 if (fp != NULL)
179 fclose(fp);
180 return OSCONTAINER_ERROR;
181 }
182 PRAGMA_DIAG_POP
183
184 #define GET_CONTAINER_INFO(return_type, subsystem, filename, \
185 logstring, scan_fmt, variable) \
186 return_type variable; \
187 { \
188 int err; \
189 err = subsystem_file_contents(subsystem, \
190 filename, \
191 scan_fmt, \
192 &variable); \
193 if (err != 0) \
194 return (return_type) OSCONTAINER_ERROR; \
195 \
196 log_trace(os, container)(logstring, variable); \
197 }
198
199 #define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \
200 logstring, scan_fmt, variable, bufsize) \
201 char variable[bufsize]; \
202 { \
203 int err; \
204 err = subsystem_file_contents(subsystem, \
205 filename, \
206 scan_fmt, \
207 variable); \
208 if (err != 0) \
209 return (return_type) NULL; \
210 \
211 log_trace(os, container)(logstring, variable); \
212 }
213
214 /* init
215 *
216 * Initialize the container support and determine if
217 * we are running under cgroup control.
218 */
219 void OSContainer::init() {
220 FILE *mntinfo = NULL;
221 FILE *cgroup = NULL;
222 char buf[MAXPATHLEN+1];
223 char tmproot[MAXPATHLEN+1];
224 char tmpmount[MAXPATHLEN+1];
225 char *p;
226 jlong mem_limit;
227
228 assert(!_is_initialized, "Initializing OSContainer more than once");
229
230 _is_initialized = true;
231 _is_containerized = false;
232
233 _unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size();
249 * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory
250 */
251 mntinfo = fopen("/proc/self/mountinfo", "r");
252 if (mntinfo == NULL) {
253 log_debug(os, container)("Can't open /proc/self/mountinfo, %s",
254 os::strerror(errno));
255 return;
256 }
257
258 while ((p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) {
259 char tmpcgroups[MAXPATHLEN+1];
260 char *cptr = tmpcgroups;
261 char *token;
262
263 // mountinfo format is documented at https://www.kernel.org/doc/Documentation/filesystems/proc.txt
264 if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- cgroup %*s %s", tmproot, tmpmount, tmpcgroups) != 3) {
265 continue;
266 }
267 while ((token = strsep(&cptr, ",")) != NULL) {
268 if (strcmp(token, "memory") == 0) {
269 memory = new CgroupSubsystem(tmproot, tmpmount);
270 } else if (strcmp(token, "cpuset") == 0) {
271 cpuset = new CgroupSubsystem(tmproot, tmpmount);
272 } else if (strcmp(token, "cpu") == 0) {
273 cpu = new CgroupSubsystem(tmproot, tmpmount);
274 } else if (strcmp(token, "cpuacct") == 0) {
275 cpuacct= new CgroupSubsystem(tmproot, tmpmount);
276 }
277 }
278 }
279
280 fclose(mntinfo);
281
282 if (memory == NULL) {
283 log_debug(os, container)("Required cgroup memory subsystem not found");
284 return;
285 }
286 if (cpuset == NULL) {
287 log_debug(os, container)("Required cgroup cpuset subsystem not found");
288 return;
289 }
327 }
328
329 while ((p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) {
330 char *controllers;
331 char *token;
332 char *base;
333
334 /* Skip cgroup number */
335 strsep(&p, ":");
336 /* Get controllers and base */
337 controllers = strsep(&p, ":");
338 base = strsep(&p, "\n");
339
340 if (controllers == NULL) {
341 continue;
342 }
343
344 while ((token = strsep(&controllers, ",")) != NULL) {
345 if (strcmp(token, "memory") == 0) {
346 memory->set_subsystem_path(base);
347 } else if (strcmp(token, "cpuset") == 0) {
348 cpuset->set_subsystem_path(base);
349 } else if (strcmp(token, "cpu") == 0) {
350 cpu->set_subsystem_path(base);
351 } else if (strcmp(token, "cpuacct") == 0) {
352 cpuacct->set_subsystem_path(base);
353 }
354 }
355 }
356
357 fclose(cgroup);
358
359 // We need to update the amount of physical memory now that
360 // command line arguments have been processed.
361 if ((mem_limit = memory_limit_in_bytes()) > 0) {
362 os::Linux::set_physical_memory(mem_limit);
363 }
364
365 _is_containerized = true;
366
367 }
368
369 const char * OSContainer::container_type() {
370 if (is_containerized()) {
371 return "cgroupv1";
372 } else {
373 return NULL;
374 }
375 }
376
377
378 /* memory_limit_in_bytes
379 *
380 * Return the limit of available memory for this process.
381 *
382 * return:
383 * memory limit in bytes or
384 * -1 for unlimited
385 * OSCONTAINER_ERROR for not supported
386 */
387 jlong OSContainer::memory_limit_in_bytes() {
388 GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes",
389 "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit);
390
391 if (memlimit >= _unlimited_memory) {
392 log_trace(os, container)("Memory Limit is: Unlimited");
393 return (jlong)-1;
394 }
395 else {
396 return (jlong)memlimit;
397 }
398 }
399
400 jlong OSContainer::memory_and_swap_limit_in_bytes() {
401 GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes",
402 "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit);
403 if (memswlimit >= _unlimited_memory) {
404 log_trace(os, container)("Memory and Swap Limit is: Unlimited");
405 return (jlong)-1;
406 } else {
407 return (jlong)memswlimit;
408 }
409 }
410
411 jlong OSContainer::memory_soft_limit_in_bytes() {
412 GET_CONTAINER_INFO(julong, memory, "/memory.soft_limit_in_bytes",
413 "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit);
414 if (memsoftlimit >= _unlimited_memory) {
415 log_trace(os, container)("Memory Soft Limit is: Unlimited");
416 return (jlong)-1;
417 } else {
418 return (jlong)memsoftlimit;
419 }
420 }
421
422 /* memory_usage_in_bytes
423 *
424 * Return the amount of used memory for this process.
|
105 int buflen;
106 strncpy(buf, _mount_point, MAXPATHLEN);
107 buf[MAXPATHLEN-1] = '\0';
108 buflen = strlen(buf);
109 if ((buflen + strlen(cgroup_path) - strlen(_root)) > (MAXPATHLEN-1)) {
110 return;
111 }
112 strncat(buf, cgroup_path + strlen(_root), MAXPATHLEN-buflen);
113 buf[MAXPATHLEN-1] = '\0';
114 _path = os::strdup(buf);
115 }
116 }
117 }
118 }
119 }
120 }
121
122 char *subsystem_path() { return _path; }
123 };
124
125 class CgroupMemorySubsystem: CgroupSubsystem {
126 friend class OSContainer;
127
128 private:
129 /* Some container runtimes set limits via cgroup
130 * hierarchy. If set to true consider also memory.stat
131 * file if everything else seems unlimited */
132 bool _uses_mem_hierarchy;
133
134 public:
135 CgroupMemorySubsystem(char *root, char *mountpoint) : CgroupSubsystem::CgroupSubsystem(root, mountpoint) {
136 _uses_mem_hierarchy = false;
137 }
138
139 bool is_hierarchical() { return _uses_mem_hierarchy; }
140 void set_hierarchical(bool value) { _uses_mem_hierarchy = value; }
141 };
142
143 CgroupMemorySubsystem* memory = NULL;
144 CgroupSubsystem* cpuset = NULL;
145 CgroupSubsystem* cpu = NULL;
146 CgroupSubsystem* cpuacct = NULL;
147
148 typedef char * cptr;
149
150 PRAGMA_DIAG_PUSH
151 PRAGMA_FORMAT_NONLITERAL_IGNORED
152 template <typename T> int subsystem_file_contents(CgroupSubsystem* c,
153 const char *filename,
154 const char *scan_fmt,
155 T returnval) {
156 FILE *fp = NULL;
157 char *p;
158 char file[MAXPATHLEN+1];
159 char buf[MAXPATHLEN+1];
160
161 if (c == NULL) {
162 log_debug(os, container)("subsystem_file_contents: CgroupSubsytem* is NULL");
163 return OSCONTAINER_ERROR;
182 if (p != NULL) {
183 int matched = sscanf(p, scan_fmt, returnval);
184 if (matched == 1) {
185 fclose(fp);
186 return 0;
187 } else {
188 log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
189 }
190 } else {
191 log_debug(os, container)("Empty file %s", file);
192 }
193 } else {
194 log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno));
195 }
196 if (fp != NULL)
197 fclose(fp);
198 return OSCONTAINER_ERROR;
199 }
200 PRAGMA_DIAG_POP
201
202 PRAGMA_DIAG_PUSH
203 PRAGMA_FORMAT_NONLITERAL_IGNORED
204 template <typename T> int subsystem_file_line_contents(CgroupSubsystem* c,
205 const char *filename,
206 const char *matchline,
207 const char *scan_fmt,
208 T returnval) {
209 FILE *fp = NULL;
210 char *p;
211 char file[MAXPATHLEN+1];
212 char buf[MAXPATHLEN+1];
213 char discard[MAXPATHLEN+1];
214
215 if (c == NULL) {
216 log_debug(os, container)("subsystem_file_contents: CgroupSubsytem* is NULL");
217 return OSCONTAINER_ERROR;
218 }
219 if (c->subsystem_path() == NULL) {
220 log_debug(os, container)("subsystem_file_contents: subsystem path is NULL");
221 return OSCONTAINER_ERROR;
222 }
223
224 strncpy(file, c->subsystem_path(), MAXPATHLEN);
225 file[MAXPATHLEN-1] = '\0';
226 int filelen = strlen(file);
227 if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) {
228 log_debug(os, container)("File path too long %s, %s", file, filename);
229 return OSCONTAINER_ERROR;
230 }
231 strncat(file, filename, MAXPATHLEN-filelen);
232 log_trace(os, container)("Path to %s is %s", filename, file);
233 fp = fopen(file, "r");
234 if (fp != NULL) {
235 int err = 0;
236 while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) {
237 if (strstr(p, matchline) != NULL) {
238 // discard matchline string prefix
239 int matched = sscanf(p, scan_fmt, discard, returnval);
240 if (matched == 2) {
241 fclose(fp);
242 return 0;
243 } else {
244 err = 1;
245 log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
246 }
247 }
248 }
249 if (err == 0) {
250 log_debug(os, container)("Empty file %s, or no match found for %s", file, matchline);
251 }
252 } else {
253 log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno));
254 }
255 if (fp != NULL)
256 fclose(fp);
257 return OSCONTAINER_ERROR;
258 }
259 PRAGMA_DIAG_POP
260
261 #define GET_CONTAINER_INFO(return_type, subsystem, filename, \
262 logstring, scan_fmt, variable) \
263 return_type variable; \
264 { \
265 int err; \
266 err = subsystem_file_contents(subsystem, \
267 filename, \
268 scan_fmt, \
269 &variable); \
270 if (err != 0) \
271 return (return_type) OSCONTAINER_ERROR; \
272 \
273 log_trace(os, container)(logstring, variable); \
274 }
275
276 #define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \
277 logstring, scan_fmt, variable, bufsize) \
278 char variable[bufsize]; \
279 { \
280 int err; \
281 err = subsystem_file_contents(subsystem, \
282 filename, \
283 scan_fmt, \
284 variable); \
285 if (err != 0) \
286 return (return_type) NULL; \
287 \
288 log_trace(os, container)(logstring, variable); \
289 }
290
291 #define GET_CONTAINER_INFO_LINE(return_type, subsystem, filename, \
292 matchline, logstring, scan_fmt, variable) \
293 return_type variable; \
294 { \
295 int err; \
296 err = subsystem_file_line_contents(subsystem, \
297 filename, \
298 matchline, \
299 scan_fmt, \
300 &variable); \
301 if (err != 0) \
302 return (return_type) OSCONTAINER_ERROR; \
303 \
304 log_trace(os, container)(logstring, variable); \
305 }
306
307 /* init
308 *
309 * Initialize the container support and determine if
310 * we are running under cgroup control.
311 */
312 void OSContainer::init() {
313 FILE *mntinfo = NULL;
314 FILE *cgroup = NULL;
315 char buf[MAXPATHLEN+1];
316 char tmproot[MAXPATHLEN+1];
317 char tmpmount[MAXPATHLEN+1];
318 char *p;
319 jlong mem_limit;
320
321 assert(!_is_initialized, "Initializing OSContainer more than once");
322
323 _is_initialized = true;
324 _is_containerized = false;
325
326 _unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size();
342 * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory
343 */
344 mntinfo = fopen("/proc/self/mountinfo", "r");
345 if (mntinfo == NULL) {
346 log_debug(os, container)("Can't open /proc/self/mountinfo, %s",
347 os::strerror(errno));
348 return;
349 }
350
351 while ((p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) {
352 char tmpcgroups[MAXPATHLEN+1];
353 char *cptr = tmpcgroups;
354 char *token;
355
356 // mountinfo format is documented at https://www.kernel.org/doc/Documentation/filesystems/proc.txt
357 if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- cgroup %*s %s", tmproot, tmpmount, tmpcgroups) != 3) {
358 continue;
359 }
360 while ((token = strsep(&cptr, ",")) != NULL) {
361 if (strcmp(token, "memory") == 0) {
362 memory = new CgroupMemorySubsystem(tmproot, tmpmount);
363 } else if (strcmp(token, "cpuset") == 0) {
364 cpuset = new CgroupSubsystem(tmproot, tmpmount);
365 } else if (strcmp(token, "cpu") == 0) {
366 cpu = new CgroupSubsystem(tmproot, tmpmount);
367 } else if (strcmp(token, "cpuacct") == 0) {
368 cpuacct= new CgroupSubsystem(tmproot, tmpmount);
369 }
370 }
371 }
372
373 fclose(mntinfo);
374
375 if (memory == NULL) {
376 log_debug(os, container)("Required cgroup memory subsystem not found");
377 return;
378 }
379 if (cpuset == NULL) {
380 log_debug(os, container)("Required cgroup cpuset subsystem not found");
381 return;
382 }
420 }
421
422 while ((p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) {
423 char *controllers;
424 char *token;
425 char *base;
426
427 /* Skip cgroup number */
428 strsep(&p, ":");
429 /* Get controllers and base */
430 controllers = strsep(&p, ":");
431 base = strsep(&p, "\n");
432
433 if (controllers == NULL) {
434 continue;
435 }
436
437 while ((token = strsep(&controllers, ",")) != NULL) {
438 if (strcmp(token, "memory") == 0) {
439 memory->set_subsystem_path(base);
440 jlong hierarchy = uses_mem_hierarchy();
441 if (hierarchy > 0) {
442 memory->set_hierarchical(true);
443 }
444 } else if (strcmp(token, "cpuset") == 0) {
445 cpuset->set_subsystem_path(base);
446 } else if (strcmp(token, "cpu") == 0) {
447 cpu->set_subsystem_path(base);
448 } else if (strcmp(token, "cpuacct") == 0) {
449 cpuacct->set_subsystem_path(base);
450 }
451 }
452 }
453
454 fclose(cgroup);
455
456 // We need to update the amount of physical memory now that
457 // command line arguments have been processed.
458 if ((mem_limit = memory_limit_in_bytes()) > 0) {
459 os::Linux::set_physical_memory(mem_limit);
460 log_info(os, container)("Memory Limit is: " JLONG_FORMAT, mem_limit);
461 }
462
463 _is_containerized = true;
464
465 }
466
467 const char * OSContainer::container_type() {
468 if (is_containerized()) {
469 return "cgroupv1";
470 } else {
471 return NULL;
472 }
473 }
474
475 /* uses_mem_hierarchy
476 *
477 * Return whether or not hierarchical cgroup accounting is being
478 * done.
479 *
480 * return:
481 * A number > 0 if true, or
482 * OSCONTAINER_ERROR for not supported
483 */
484 jlong OSContainer::uses_mem_hierarchy() {
485 GET_CONTAINER_INFO(jlong, memory, "/memory.use_hierarchy",
486 "Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy);
487 return use_hierarchy;
488 }
489
490
491 /* memory_limit_in_bytes
492 *
493 * Return the limit of available memory for this process.
494 *
495 * return:
496 * memory limit in bytes or
497 * -1 for unlimited
498 * OSCONTAINER_ERROR for not supported
499 */
500 jlong OSContainer::memory_limit_in_bytes() {
501 GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes",
502 "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit);
503
504 if (memlimit >= _unlimited_memory) {
505 log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited");
506 if (memory->is_hierarchical()) {
507 const char* matchline = "hierarchical_memory_limit";
508 char* format = "%s " JULONG_FORMAT;
509 GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
510 "Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit)
511 if (hier_memlimit >= _unlimited_memory) {
512 log_trace(os, container)("Hierarchical Memory Limit is: Unlimited");
513 } else {
514 return (jlong)hier_memlimit;
515 }
516 }
517 return (jlong)-1;
518 }
519 else {
520 return (jlong)memlimit;
521 }
522 }
523
524 jlong OSContainer::memory_and_swap_limit_in_bytes() {
525 GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes",
526 "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit);
527 if (memswlimit >= _unlimited_memory) {
528 log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited");
529 if (memory->is_hierarchical()) {
530 const char* matchline = "hierarchical_memsw_limit";
531 char* format = "%s " JULONG_FORMAT;
532 GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
533 "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memlimit)
534 if (hier_memlimit >= _unlimited_memory) {
535 log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited");
536 } else {
537 return (jlong)hier_memlimit;
538 }
539 }
540 return (jlong)-1;
541 } else {
542 return (jlong)memswlimit;
543 }
544 }
545
546 jlong OSContainer::memory_soft_limit_in_bytes() {
547 GET_CONTAINER_INFO(julong, memory, "/memory.soft_limit_in_bytes",
548 "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit);
549 if (memsoftlimit >= _unlimited_memory) {
550 log_trace(os, container)("Memory Soft Limit is: Unlimited");
551 return (jlong)-1;
552 } else {
553 return (jlong)memsoftlimit;
554 }
555 }
556
557 /* memory_usage_in_bytes
558 *
559 * Return the amount of used memory for this process.
|