105 int buflen;
106 strncpy(buf, _mount_point, MAXPATHLEN);
107 buf[MAXPATHLEN-1] = '\0';
108 buflen = strlen(buf);
109 if ((buflen + strlen(cgroup_path)) > (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 int mountid;
221 int parentid;
222 int major;
223 int minor;
224 FILE *mntinfo = NULL;
225 FILE *cgroup = NULL;
226 char buf[MAXPATHLEN+1];
227 char tmproot[MAXPATHLEN+1];
228 char tmpmount[MAXPATHLEN+1];
229 char tmpbase[MAXPATHLEN+1];
230 char *p;
231 jlong mem_limit;
232
233 assert(!_is_initialized, "Initializing OSContainer more than once");
261 }
262
263 while ( (p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) {
264 // Look for the filesystem type and see if it's cgroup
265 char fstype[MAXPATHLEN+1];
266 fstype[0] = '\0';
267 char *s = strstr(p, " - ");
268 if (s != NULL &&
269 sscanf(s, " - %s", fstype) == 1 &&
270 strcmp(fstype, "cgroup") == 0) {
271
272 if (strstr(p, "memory") != NULL) {
273 int matched = sscanf(p, "%d %d %d:%d %s %s",
274 &mountid,
275 &parentid,
276 &major,
277 &minor,
278 tmproot,
279 tmpmount);
280 if (matched == 6) {
281 memory = new CgroupSubsystem(tmproot, tmpmount);
282 }
283 else
284 log_debug(os, container)("Incompatible str containing cgroup and memory: %s", p);
285 } else if (strstr(p, "cpuset") != NULL) {
286 int matched = sscanf(p, "%d %d %d:%d %s %s",
287 &mountid,
288 &parentid,
289 &major,
290 &minor,
291 tmproot,
292 tmpmount);
293 if (matched == 6) {
294 cpuset = new CgroupSubsystem(tmproot, tmpmount);
295 }
296 else {
297 log_debug(os, container)("Incompatible str containing cgroup and cpuset: %s", p);
298 }
299 } else if (strstr(p, "cpu,cpuacct") != NULL || strstr(p, "cpuacct,cpu") != NULL) {
300 int matched = sscanf(p, "%d %d %d:%d %s %s",
301 &mountid,
390 log_debug(os, container)("Can't open /proc/self/cgroup, %s",
391 os::strerror(errno));
392 return;
393 }
394
395 while ( (p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) {
396 int cgno;
397 int matched;
398 char *controller;
399 char *base;
400
401 /* Skip cgroup number */
402 strsep(&p, ":");
403 /* Get controller and base */
404 controller = strsep(&p, ":");
405 base = strsep(&p, "\n");
406
407 if (controller != NULL) {
408 if (strstr(controller, "memory") != NULL) {
409 memory->set_subsystem_path(base);
410 } else if (strstr(controller, "cpuset") != NULL) {
411 cpuset->set_subsystem_path(base);
412 } else if (strstr(controller, "cpu,cpuacct") != NULL || strstr(controller, "cpuacct,cpu") != NULL) {
413 cpu->set_subsystem_path(base);
414 cpuacct->set_subsystem_path(base);
415 } else if (strstr(controller, "cpuacct") != NULL) {
416 cpuacct->set_subsystem_path(base);
417 } else if (strstr(controller, "cpu") != NULL) {
418 cpu->set_subsystem_path(base);
419 }
420 }
421 }
422
423 fclose(cgroup);
424
425 // We need to update the amount of physical memory now that
426 // command line arguments have been processed.
427 if ((mem_limit = memory_limit_in_bytes()) > 0) {
428 os::Linux::set_physical_memory(mem_limit);
429 }
430
431 _is_containerized = true;
432
433 }
434
435 const char * OSContainer::container_type() {
436 if (is_containerized()) {
437 return "cgroupv1";
438 } else {
439 return NULL;
440 }
441 }
442
443
444 /* memory_limit_in_bytes
445 *
446 * Return the limit of available memory for this process.
447 *
448 * return:
449 * memory limit in bytes or
450 * -1 for unlimited
451 * OSCONTAINER_ERROR for not supported
452 */
453 jlong OSContainer::memory_limit_in_bytes() {
454 GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes",
455 "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit);
456
457 if (memlimit >= _unlimited_memory) {
458 log_trace(os, container)("Memory Limit is: Unlimited");
459 return (jlong)-1;
460 }
461 else {
462 return (jlong)memlimit;
463 }
464 }
465
466 jlong OSContainer::memory_and_swap_limit_in_bytes() {
467 GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes",
468 "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit);
469 if (memswlimit >= _unlimited_memory) {
470 log_trace(os, container)("Memory and Swap Limit is: Unlimited");
471 return (jlong)-1;
472 } else {
473 return (jlong)memswlimit;
474 }
475 }
476
477 jlong OSContainer::memory_soft_limit_in_bytes() {
478 GET_CONTAINER_INFO(julong, memory, "/memory.soft_limit_in_bytes",
479 "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit);
480 if (memsoftlimit >= _unlimited_memory) {
481 log_trace(os, container)("Memory Soft Limit is: Unlimited");
482 return (jlong)-1;
483 } else {
484 return (jlong)memsoftlimit;
485 }
486 }
487
488 /* memory_usage_in_bytes
489 *
490 * 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)) > (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 int mountid;
314 int parentid;
315 int major;
316 int minor;
317 FILE *mntinfo = NULL;
318 FILE *cgroup = NULL;
319 char buf[MAXPATHLEN+1];
320 char tmproot[MAXPATHLEN+1];
321 char tmpmount[MAXPATHLEN+1];
322 char tmpbase[MAXPATHLEN+1];
323 char *p;
324 jlong mem_limit;
325
326 assert(!_is_initialized, "Initializing OSContainer more than once");
354 }
355
356 while ( (p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) {
357 // Look for the filesystem type and see if it's cgroup
358 char fstype[MAXPATHLEN+1];
359 fstype[0] = '\0';
360 char *s = strstr(p, " - ");
361 if (s != NULL &&
362 sscanf(s, " - %s", fstype) == 1 &&
363 strcmp(fstype, "cgroup") == 0) {
364
365 if (strstr(p, "memory") != NULL) {
366 int matched = sscanf(p, "%d %d %d:%d %s %s",
367 &mountid,
368 &parentid,
369 &major,
370 &minor,
371 tmproot,
372 tmpmount);
373 if (matched == 6) {
374 memory = new CgroupMemorySubsystem(tmproot, tmpmount);
375 }
376 else
377 log_debug(os, container)("Incompatible str containing cgroup and memory: %s", p);
378 } else if (strstr(p, "cpuset") != NULL) {
379 int matched = sscanf(p, "%d %d %d:%d %s %s",
380 &mountid,
381 &parentid,
382 &major,
383 &minor,
384 tmproot,
385 tmpmount);
386 if (matched == 6) {
387 cpuset = new CgroupSubsystem(tmproot, tmpmount);
388 }
389 else {
390 log_debug(os, container)("Incompatible str containing cgroup and cpuset: %s", p);
391 }
392 } else if (strstr(p, "cpu,cpuacct") != NULL || strstr(p, "cpuacct,cpu") != NULL) {
393 int matched = sscanf(p, "%d %d %d:%d %s %s",
394 &mountid,
483 log_debug(os, container)("Can't open /proc/self/cgroup, %s",
484 os::strerror(errno));
485 return;
486 }
487
488 while ( (p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) {
489 int cgno;
490 int matched;
491 char *controller;
492 char *base;
493
494 /* Skip cgroup number */
495 strsep(&p, ":");
496 /* Get controller and base */
497 controller = strsep(&p, ":");
498 base = strsep(&p, "\n");
499
500 if (controller != NULL) {
501 if (strstr(controller, "memory") != NULL) {
502 memory->set_subsystem_path(base);
503 jlong hierarchy = uses_mem_hierarchy();
504 if (hierarchy > 0) {
505 memory->set_hierarchical(true);
506 }
507 } else if (strstr(controller, "cpuset") != NULL) {
508 cpuset->set_subsystem_path(base);
509 } else if (strstr(controller, "cpu,cpuacct") != NULL || strstr(controller, "cpuacct,cpu") != NULL) {
510 cpu->set_subsystem_path(base);
511 cpuacct->set_subsystem_path(base);
512 } else if (strstr(controller, "cpuacct") != NULL) {
513 cpuacct->set_subsystem_path(base);
514 } else if (strstr(controller, "cpu") != NULL) {
515 cpu->set_subsystem_path(base);
516 }
517 }
518 }
519
520 fclose(cgroup);
521
522 // We need to update the amount of physical memory now that
523 // command line arguments have been processed.
524 if ((mem_limit = memory_limit_in_bytes()) > 0) {
525 os::Linux::set_physical_memory(mem_limit);
526 log_info(os, container)("Memory Limit is: " JLONG_FORMAT, mem_limit);
527 }
528
529 _is_containerized = true;
530
531 }
532
533 const char * OSContainer::container_type() {
534 if (is_containerized()) {
535 return "cgroupv1";
536 } else {
537 return NULL;
538 }
539 }
540
541 /* uses_mem_hierarchy
542 *
543 * Return whether or not hierarchical cgroup accounting is being
544 * done.
545 *
546 * return:
547 * A number > 0 if true, or
548 * OSCONTAINER_ERROR for not supported
549 */
550 jlong OSContainer::uses_mem_hierarchy() {
551 GET_CONTAINER_INFO(jlong, memory, "/memory.use_hierarchy",
552 "Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy);
553 return use_hierarchy;
554 }
555
556
557 /* memory_limit_in_bytes
558 *
559 * Return the limit of available memory for this process.
560 *
561 * return:
562 * memory limit in bytes or
563 * -1 for unlimited
564 * OSCONTAINER_ERROR for not supported
565 */
566 jlong OSContainer::memory_limit_in_bytes() {
567 GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes",
568 "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit);
569
570 if (memlimit >= _unlimited_memory) {
571 log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited");
572 if (memory->is_hierarchical()) {
573 const char* matchline = "hierarchical_memory_limit";
574 char* format = "%s " JULONG_FORMAT;
575 GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
576 "Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit)
577 if (hier_memlimit >= _unlimited_memory) {
578 log_trace(os, container)("Hierarchical Memory Limit is: Unlimited");
579 } else {
580 return (jlong)hier_memlimit;
581 }
582 }
583 return (jlong)-1;
584 }
585 else {
586 return (jlong)memlimit;
587 }
588 }
589
590 jlong OSContainer::memory_and_swap_limit_in_bytes() {
591 GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes",
592 "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit);
593 if (memswlimit >= _unlimited_memory) {
594 log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited");
595 if (memory->is_hierarchical()) {
596 const char* matchline = "hierarchical_memsw_limit";
597 char* format = "%s " JULONG_FORMAT;
598 GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
599 "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memlimit)
600 if (hier_memlimit >= _unlimited_memory) {
601 log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited");
602 } else {
603 return (jlong)hier_memlimit;
604 }
605 }
606 return (jlong)-1;
607 } else {
608 return (jlong)memswlimit;
609 }
610 }
611
612 jlong OSContainer::memory_soft_limit_in_bytes() {
613 GET_CONTAINER_INFO(julong, memory, "/memory.soft_limit_in_bytes",
614 "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit);
615 if (memsoftlimit >= _unlimited_memory) {
616 log_trace(os, container)("Memory Soft Limit is: Unlimited");
617 return (jlong)-1;
618 } else {
619 return (jlong)memsoftlimit;
620 }
621 }
622
623 /* memory_usage_in_bytes
624 *
625 * Return the amount of used memory for this process.
|