11/*
2- * Copyright (c) 2019, 2020 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2019, 2021 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
3434#include " runtime/os.hpp"
3535#include " utilities/globalDefinitions.hpp"
3636
37+ // controller names have to match the *_IDX indices
38+ static const char * cg_controller_name[] = { " cpu" , " cpuset" , " cpuacct" , " memory" , " pids" };
39+
3740CgroupSubsystem* CgroupSubsystemFactory::create () {
3841 CgroupV1MemoryController* memory = NULL ;
3942 CgroupV1Controller* cpuset = NULL ;
4043 CgroupV1Controller* cpu = NULL ;
4144 CgroupV1Controller* cpuacct = NULL ;
45+ CgroupV1Controller* pids = NULL ;
4246 CgroupInfo cg_infos[CG_INFO_LENGTH];
4347 u1 cg_type_flags = INVALID_CGROUPS_GENERIC;
4448 const char * proc_cgroups = " /proc/cgroups" ;
@@ -93,22 +97,29 @@ CgroupSubsystem* CgroupSubsystemFactory::create() {
9397 assert (is_cgroup_v1 (&cg_type_flags), " Cgroup v1 expected" );
9498 for (int i = 0 ; i < CG_INFO_LENGTH; i++) {
9599 CgroupInfo info = cg_infos[i];
96- if (strcmp (info._name , " memory" ) == 0 ) {
97- memory = new CgroupV1MemoryController (info._root_mount_path , info._mount_path );
98- memory->set_subsystem_path (info._cgroup_path );
99- } else if (strcmp (info._name , " cpuset" ) == 0 ) {
100- cpuset = new CgroupV1Controller (info._root_mount_path , info._mount_path );
101- cpuset->set_subsystem_path (info._cgroup_path );
102- } else if (strcmp (info._name , " cpu" ) == 0 ) {
103- cpu = new CgroupV1Controller (info._root_mount_path , info._mount_path );
104- cpu->set_subsystem_path (info._cgroup_path );
105- } else if (strcmp (info._name , " cpuacct" ) == 0 ) {
106- cpuacct = new CgroupV1Controller (info._root_mount_path , info._mount_path );
107- cpuacct->set_subsystem_path (info._cgroup_path );
100+ if (info._data_complete ) { // pids controller might have incomplete data
101+ if (strcmp (info._name , " memory" ) == 0 ) {
102+ memory = new CgroupV1MemoryController (info._root_mount_path , info._mount_path );
103+ memory->set_subsystem_path (info._cgroup_path );
104+ } else if (strcmp (info._name , " cpuset" ) == 0 ) {
105+ cpuset = new CgroupV1Controller (info._root_mount_path , info._mount_path );
106+ cpuset->set_subsystem_path (info._cgroup_path );
107+ } else if (strcmp (info._name , " cpu" ) == 0 ) {
108+ cpu = new CgroupV1Controller (info._root_mount_path , info._mount_path );
109+ cpu->set_subsystem_path (info._cgroup_path );
110+ } else if (strcmp (info._name , " cpuacct" ) == 0 ) {
111+ cpuacct = new CgroupV1Controller (info._root_mount_path , info._mount_path );
112+ cpuacct->set_subsystem_path (info._cgroup_path );
113+ } else if (strcmp (info._name , " pids" ) == 0 ) {
114+ pids = new CgroupV1Controller (info._root_mount_path , info._mount_path );
115+ pids->set_subsystem_path (info._cgroup_path );
116+ }
117+ } else {
118+ log_debug (os, container)(" CgroupInfo for %s not complete" , cg_controller_name[i]);
108119 }
109120 }
110121 cleanup (cg_infos);
111- return new CgroupV1Subsystem (cpuset, cpu, cpuacct, memory);
122+ return new CgroupV1Subsystem (cpuset, cpu, cpuacct, pids, memory);
112123}
113124
114125bool CgroupSubsystemFactory::determine_type (CgroupInfo* cg_infos,
@@ -122,9 +133,10 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
122133 char buf[MAXPATHLEN+1 ];
123134 char *p;
124135 bool is_cgroupsV2;
125- // true iff all controllers, memory, cpu, cpuset, cpuacct are enabled
136+ // true iff all required controllers, memory, cpu, cpuset, cpuacct are enabled
126137 // at the kernel level.
127- bool all_controllers_enabled;
138+ // pids might not be enabled on older Linux distros (SLES 12.1, RHEL 7.1)
139+ bool all_required_controllers_enabled;
128140
129141 /*
130142 * Read /proc/cgroups so as to be able to distinguish cgroups v2 vs cgroups v1.
@@ -136,10 +148,9 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
136148 */
137149 cgroups = fopen (proc_cgroups, " r" );
138150 if (cgroups == NULL ) {
139- log_debug (os, container)(" Can't open %s, %s" ,
140- proc_cgroups, os::strerror (errno));
141- *flags = INVALID_CGROUPS_GENERIC;
142- return false ;
151+ log_debug (os, container)(" Can't open %s, %s" , proc_cgroups, os::strerror (errno));
152+ *flags = INVALID_CGROUPS_GENERIC;
153+ return false ;
143154 }
144155
145156 while ((p = fgets (buf, MAXPATHLEN, cgroups)) != NULL ) {
@@ -167,19 +178,30 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
167178 cg_infos[CPUACCT_IDX]._name = os::strdup (name);
168179 cg_infos[CPUACCT_IDX]._hierarchy_id = hierarchy_id;
169180 cg_infos[CPUACCT_IDX]._enabled = (enabled == 1 );
181+ } else if (strcmp (name, " pids" ) == 0 ) {
182+ log_debug (os, container)(" Detected optional pids controller entry in %s" , proc_cgroups);
183+ cg_infos[PIDS_IDX]._name = os::strdup (name);
184+ cg_infos[PIDS_IDX]._hierarchy_id = hierarchy_id;
185+ cg_infos[PIDS_IDX]._enabled = (enabled == 1 );
170186 }
171187 }
172188 fclose (cgroups);
173189
174190 is_cgroupsV2 = true ;
175- all_controllers_enabled = true ;
191+ all_required_controllers_enabled = true ;
176192 for (int i = 0 ; i < CG_INFO_LENGTH; i++) {
177- is_cgroupsV2 = is_cgroupsV2 && cg_infos[i]._hierarchy_id == 0 ;
178- all_controllers_enabled = all_controllers_enabled && cg_infos[i]._enabled ;
193+ // pids controller is optional. All other controllers are required
194+ if (i != PIDS_IDX) {
195+ is_cgroupsV2 = is_cgroupsV2 && cg_infos[i]._hierarchy_id == 0 ;
196+ all_required_controllers_enabled = all_required_controllers_enabled && cg_infos[i]._enabled ;
197+ }
198+ if (log_is_enabled (Debug, os, container) && !cg_infos[i]._enabled ) {
199+ log_debug (os, container)(" controller %s is not enabled\n " , cg_controller_name[i]);
200+ }
179201 }
180202
181- if (!all_controllers_enabled ) {
182- // one or more controllers disabled, disable container support
203+ if (!all_required_controllers_enabled ) {
204+ // one or more required controllers disabled, disable container support
183205 log_debug (os, container)(" One or more required controllers disabled at kernel level." );
184206 cleanup (cg_infos);
185207 *flags = INVALID_CGROUPS_GENERIC;
@@ -220,17 +242,21 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
220242
221243 while (!is_cgroupsV2 && (token = strsep (&controllers, " ," )) != NULL ) {
222244 if (strcmp (token, " memory" ) == 0 ) {
223- assert (hierarchy_id == cg_infos[MEMORY_IDX]._hierarchy_id , " /proc/cgroups and /proc/self/cgroup hierarchy mismatch" );
245+ assert (hierarchy_id == cg_infos[MEMORY_IDX]._hierarchy_id , " /proc/cgroups and /proc/self/cgroup hierarchy mismatch for memory " );
224246 cg_infos[MEMORY_IDX]._cgroup_path = os::strdup (cgroup_path);
225247 } else if (strcmp (token, " cpuset" ) == 0 ) {
226- assert (hierarchy_id == cg_infos[CPUSET_IDX]._hierarchy_id , " /proc/cgroups and /proc/self/cgroup hierarchy mismatch" );
248+ assert (hierarchy_id == cg_infos[CPUSET_IDX]._hierarchy_id , " /proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpuset " );
227249 cg_infos[CPUSET_IDX]._cgroup_path = os::strdup (cgroup_path);
228250 } else if (strcmp (token, " cpu" ) == 0 ) {
229- assert (hierarchy_id == cg_infos[CPU_IDX]._hierarchy_id , " /proc/cgroups and /proc/self/cgroup hierarchy mismatch" );
251+ assert (hierarchy_id == cg_infos[CPU_IDX]._hierarchy_id , " /proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpu " );
230252 cg_infos[CPU_IDX]._cgroup_path = os::strdup (cgroup_path);
231253 } else if (strcmp (token, " cpuacct" ) == 0 ) {
232- assert (hierarchy_id == cg_infos[CPUACCT_IDX]._hierarchy_id , " /proc/cgroups and /proc/self/cgroup hierarchy mismatch" );
254+ assert (hierarchy_id == cg_infos[CPUACCT_IDX]._hierarchy_id , " /proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpuacc " );
233255 cg_infos[CPUACCT_IDX]._cgroup_path = os::strdup (cgroup_path);
256+ } else if (strcmp (token, " pids" ) == 0 ) {
257+ assert (hierarchy_id == cg_infos[PIDS_IDX]._hierarchy_id , " /proc/cgroups (%d) and /proc/self/cgroup (%d) hierarchy mismatch for pids" ,
258+ cg_infos[PIDS_IDX]._hierarchy_id , hierarchy_id);
259+ cg_infos[PIDS_IDX]._cgroup_path = os::strdup (cgroup_path);
234260 }
235261 }
236262 if (is_cgroupsV2) {
@@ -281,13 +307,15 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
281307
282308 /* Cgroup v1 relevant info
283309 *
284- * Find the cgroup mount point for memory, cpuset, cpu, cpuacct
310+ * Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids
285311 *
286312 * Example for docker:
287313 * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory
288314 *
289315 * Example for host:
290316 * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory
317+ *
318+ * 44 31 0:39 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,pids
291319 */
292320 if (sscanf (p, " %*d %*d %*d:%*d %s %s %*[^-]- %s %*s %s" , tmproot, tmpmount, tmp_fs_type, tmpcgroups) == 4 ) {
293321 if (strcmp (" cgroup" , tmp_fs_type) != 0 ) {
@@ -333,6 +361,12 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
333361 cg_infos[CPUACCT_IDX]._mount_path = os::strdup (tmpmount);
334362 cg_infos[CPUACCT_IDX]._root_mount_path = os::strdup (tmproot);
335363 cg_infos[CPUACCT_IDX]._data_complete = true ;
364+ } else if (strcmp (token, " pids" ) == 0 ) {
365+ any_cgroup_mounts_found = true ;
366+ assert (cg_infos[PIDS_IDX]._mount_path == NULL , " stomping of _mount_path" );
367+ cg_infos[PIDS_IDX]._mount_path = os::strdup (tmpmount);
368+ cg_infos[PIDS_IDX]._root_mount_path = os::strdup (tmproot);
369+ cg_infos[PIDS_IDX]._data_complete = true ;
336370 }
337371 }
338372 }
@@ -387,10 +421,13 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
387421 *flags = INVALID_CGROUPS_V1;
388422 return false ;
389423 }
424+ if (log_is_enabled (Debug, os, container) && !cg_infos[PIDS_IDX]._data_complete ) {
425+ log_debug (os, container)(" Optional cgroup v1 pids subsystem not found" );
426+ // keep the other controller info, pids is optional
427+ }
390428 // Cgroups v1 case, we have all the info we need.
391429 *flags = CGROUPS_V1;
392430 return true ;
393-
394431};
395432
396433void CgroupSubsystemFactory::cleanup (CgroupInfo* cg_infos) {
@@ -514,3 +551,22 @@ jlong CgroupSubsystem::memory_limit_in_bytes() {
514551 memory_limit->set_value (mem_limit, OSCONTAINER_CACHE_TIMEOUT);
515552 return mem_limit;
516553}
554+
555+ jlong CgroupSubsystem::limit_from_str (char * limit_str) {
556+ if (limit_str == NULL ) {
557+ return OSCONTAINER_ERROR;
558+ }
559+ // Unlimited memory in cgroups is the literal string 'max' for
560+ // some controllers, for example the pids controller.
561+ if (strcmp (" max" , limit_str) == 0 ) {
562+ os::free (limit_str);
563+ return (jlong)-1 ;
564+ }
565+ julong limit;
566+ if (sscanf (limit_str, JULONG_FORMAT, &limit) != 1 ) {
567+ os::free (limit_str);
568+ return OSCONTAINER_ERROR;
569+ }
570+ os::free (limit_str);
571+ return (jlong)limit;
572+ }
0 commit comments