if (!cg_controller_is_valid(controller))
return -EINVAL;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (!cg_controller_is_valid(controller))
return -EINVAL;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0) {
if (r < 0)
return r;
- unified = cg_unified();
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
if (unified)
assert(path);
assert(pid >= 0);
- unified = cg_unified();
+ if (controller) {
+ if (!cg_controller_is_valid(controller))
+ return -EINVAL;
+ } else
+ controller = SYSTEMD_CGROUP_CONTROLLER;
+
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
- if (unified == 0) {
- if (controller) {
- if (!cg_controller_is_valid(controller))
- return -EINVAL;
- } else
- controller = SYSTEMD_CGROUP_CONTROLLER;
-
+ if (unified == 0)
cs = strlen(controller);
- }
fs = procfs_file_alloca(pid, "cgroup");
log_debug_elogind("Searching for PID %u in \"%s\" (controller \"%s\")",
assert(agent);
- unified = cg_unified();
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
if (unified) /* doesn't apply to unified hierarchy */
_cleanup_free_ char *fs = NULL;
int r, unified;
- unified = cg_unified();
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
if (unified) /* Doesn't apply to unified hierarchy */
if (controller && (isempty(path) || path_equal(path, "/")))
return false;
- unified = cg_unified();
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
return r;
/* If we are in the unified hierarchy, we are done now */
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0)
if (r < 0)
return r;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0)
return r;
}
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0)
if (r < 0)
return r;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0)
* includes controllers we can make sense of and that are
* actually accessible. */
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0) {
}
#endif // 0
-static thread_local int unified_cache = -1;
+static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN;
+
+static int cg_update_unified(void) {
-int cg_unified(void) {
struct statfs fs;
/* Checks if we support the unified hierarchy. Returns an
* have any other trouble determining if the unified hierarchy
* is supported. */
- if (unified_cache >= 0)
- return unified_cache;
+ if (unified_cache >= CGROUP_UNIFIED_NONE)
+ return 0;
if (statfs("/sys/fs/cgroup/", &fs) < 0)
return -errno;
#if 0 /// UNNEEDED by elogind
if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
- unified_cache = true;
- else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
+ unified_cache = CGROUP_UNIFIED_ALL;
+ else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
#else
/* elogind can not support the unified hierarchy as a controller,
* so always assume a classical hierarchy.
* If, and only *if*, someone really wants to substitute systemd-login
* in an environment managed by systemd with elogind, we might have to
* add such a support. */
- if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
+ if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
#endif // 0
- unified_cache = false;
- else
+ if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0)
+ return -errno;
+
+ unified_cache = F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC) ?
+ CGROUP_UNIFIED_SYSTEMD : CGROUP_UNIFIED_NONE;
+ } else
return -ENOMEDIUM;
- return unified_cache;
+ return 0;
+}
+
+int cg_unified(const char *controller) {
+
+ int r;
+
+ r = cg_update_unified();
+ if (r < 0)
+ return r;
+
+ if (streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER))
+ return unified_cache >= CGROUP_UNIFIED_SYSTEMD;
+ else
+ return unified_cache >= CGROUP_UNIFIED_ALL;
+}
+
+int cg_all_unified(void) {
+
+ return cg_unified(NULL);
}
#if 0 /// UNNEEDED by elogind
void cg_unified_flush(void) {
- unified_cache = -1;
+ unified_cache = CGROUP_UNIFIED_UNKNOWN;
}
int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
if (supported == 0)
return 0;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (!unified) /* on the legacy hiearchy there's no joining of controllers defined */
/* If the hierarchy is already mounted, then follow whatever
* was chosen for it. */
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified >= 0)
return unified;
#else
bool cg_is_legacy_wanted(void) {
return true;
+
+bool cg_is_unified_systemd_controller_wanted(void) {
+ static thread_local int wanted = -1;
+ int r, unified;
+
+ /* If the unified hierarchy is requested in full, no need to
+ * bother with this. */
+ if (cg_is_unified_wanted())
+ return 0;
+
+ /* If the hierarchy is already mounted, then follow whatever
+ * was chosen for it. */
+ unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
+ if (unified >= 0)
+ return unified;
+
+ /* Otherwise, let's see what the kernel command line has to
+ * say. Since checking that is expensive, let's cache the
+ * result. */
+ if (wanted >= 0)
+ return wanted;
+
+ r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller", NULL);
+ if (r > 0) {
+ wanted = false;
+ } else {
+ _cleanup_free_ char *value = NULL;
+
+ r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller=", &value);
+ if (r < 0)
+ return true;
+
+ if (r == 0)
+ wanted = true;
+ else
+ wanted = parse_boolean(value) <= 0;
+ }
+
+ return wanted;
+}
+
+bool cg_is_legacy_systemd_controller_wanted(void) {
+ return cg_is_legacy_wanted() && !cg_is_unified_systemd_controller_wanted();
}
#endif // 0
bool has_weight = cgroup_context_has_cpu_weight(c);
bool has_shares = cgroup_context_has_cpu_shares(c);
- if (cg_unified() > 0) {
+ if (cg_all_unified() > 0) {
uint64_t weight;
if (has_weight)
}
if ((mask & CGROUP_MASK_MEMORY) && !is_root) {
- if (cg_unified() > 0) {
+ if (cg_all_unified() > 0) {
uint64_t max = c->memory_max;
if (cgroup_context_has_unified_memory_config(c))
e = unit_get_exec_context(u);
if (!e ||
exec_context_maintains_privileges(e) ||
- cg_unified() > 0)
+ cg_all_unified() > 0)
return _CGROUP_MASK_ALL;
}
return 0;
/* Only applies to the unified hierarchy */
- r = cg_unified();
+ r = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
if (r < 0)
return log_unit_error_errno(u, r, "Failed detect whether the unified hierarchy is used: %m");
if (r == 0)
if (!u->cgroup_path)
return -ENOENT;
- if (cg_unified() > 0) /* On unified we can use proper notifications */
+ if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) > 0) /* On unified we can use proper notifications */
return 0;
return unit_watch_pids_in_path(u, u->cgroup_path);
int manager_setup_cgroup(Manager *m) {
_cleanup_free_ char *path = NULL;
CGroupController c;
- int r, unified;
+ int r, all_unified, systemd_unified;
char *e;
assert(m);
if (r < 0)
return log_error_errno(r, "Cannot find cgroup mount point: %m");
- unified = cg_unified();
- if (unified < 0)
- return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m");
- if (unified > 0)
+ all_unified = cg_all_unified();
+ systemd_unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
+
+ if (all_unified < 0 || systemd_unified < 0)
+ return log_error_errno(all_unified < 0 ? all_unified : systemd_unified,
+ "Couldn't determine if we are running in the unified hierarchy: %m");
+
+ if (all_unified > 0)
log_debug("Unified cgroup hierarchy is located at %s.", path);
+ else if (systemd_unified > 0)
+ log_debug("Unified cgroup hierarchy is located at %s. Controllers are on legacy hierarchies.", path);
else
log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
const char *scope_path;
/* 3. Install agent */
- if (unified) {
+ if (systemd_unified) {
/* In the unified hierarchy we can get
* cgroup empty notifications via inotify. */
return log_error_errno(errno, "Failed to open pin file: %m");
/* 6. Always enable hierarchical support if it exists... */
- if (!unified)
+ if (!all_unified)
(void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
}
if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0)
return -ENODATA;
- if (cg_unified() <= 0)
+ if (cg_all_unified() <= 0)
r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
else
r = cg_get_attribute("memory", u->cgroup_path, "memory.current", &v);
if (!u->cgroup_path)
return -ENODATA;
- if (cg_unified() > 0) {
+ if (cg_all_unified() > 0) {
const char *keys[] = { "usage_usec", NULL };
_cleanup_free_ char *val = NULL;
uint64_t us;
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
#if 0 /// UNNEEDED by elogind
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_unified_systemd_controller_wanted, MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_legacy_wanted, MNT_IN_CONTAINER },
+ cg_is_legacy_systemd_controller_wanted, MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
#else
{ "cgroup", "/sys/fs/cgroup/elogind", "cgroup", "none,name=elogind,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_legacy_wanted, MNT_IN_CONTAINER },