Currently the hybrid mode mounts cgroup v2 on /sys/fs/cgroup instead of the v1
name=elogind hierarchy. While this works fine for elogind itself, it breaks
tools which expect cgroup v1 hierarchy on /sys/fs/cgroup/elogind.
This patch updates the hybrid mode so that it mounts v2 hierarchy on
/sys/fs/cgroup/unified and keeps v1 "name=elogind" hierarchy on
/sys/fs/cgroup/elogind for compatibility. elogind itself doesn't depend on the
"name=elogind" hierarchy at all. All operations take place on the v2 hierarchy
as before but the v1 hierarchy is kept in sync so that any tools which expect
it to be there can keep doing so. This allows elogind to take advantage of
cgroup v2 process management without requiring other tools to be aware of the
hybrid mode.
The hybrid mode is implemented by mapping the special elogind controller to
/sys/fs/cgroup/unified and making the basic cgroup utility operations -
cg_attach(), cg_create(), cg_rmdir() and cg_trim() - also operate on the
/sys/fs/cgroup/elogind hierarchy whenever the cgroup2 hierarchy is updated.
While a bit messy, this will allow dropping complications from using cgroup v1
for process management a lot sooner than otherwise possible which should make
it a net gain in terms of maintainability.
v2: Fixed !cgns breakage reported by @evverx and renamed the unified mount
point to /sys/fs/cgroup/unified as suggested by @brauner.
v3: chown the compat hierarchy too on delegation. Suggested by @evverx.
v4: [zj]
- drop the change to default, full "legacy" is still the default.
AM_CPPFLAGS = \
-include $(top_builddir)/config.h \
-DPKGSYSCONFDIR=\"$(pkgsysconfdir)\" \
AM_CPPFLAGS = \
-include $(top_builddir)/config.h \
-DPKGSYSCONFDIR=\"$(pkgsysconfdir)\" \
- -DSYSTEMD_CGROUP_CONTROLLER=\"$(CGROUP_CONTROLLER)\" \
+ -DSYSTEMD_CGROUP_CONTROLLER=\"_$(CGROUP_CONTROLLER)\" \
+ -DSYSTEMD_CGROUP_CONTROLLER_LEGACY=\"name=$(CGROUP_CONTROLLER)\" \
+ -DSYSTEMD_CGROUP_CONTROLLER_HYBRID=\"name=$(CGROUP_CONTROLLER)\" \
-DSYSTEMD_CGROUP_AGENT_PATH=\"$(rootlibexecdir)/elogind-cgroups-agent\" \
-DUDEVLIBEXECDIR=\"$(udevlibexecdir)\" \
-DPOLKIT_AGENT_BINARY_PATH=\"$(PKTTYAGENT)\" \
-DSYSTEMD_CGROUP_AGENT_PATH=\"$(rootlibexecdir)/elogind-cgroups-agent\" \
-DUDEVLIBEXECDIR=\"$(udevlibexecdir)\" \
-DPOLKIT_AGENT_BINARY_PATH=\"$(PKTTYAGENT)\" \
# If this was not possible, /proc/self/cgroup not mounted yet, and 'auto'
# chosen, error out.
AS_IF( [test -z "$with_cgroupctrl"],
# If this was not possible, /proc/self/cgroup not mounted yet, and 'auto'
# chosen, error out.
AS_IF( [test -z "$with_cgroupctrl"],
- AC_MSG_ERROR([No running cgroup controller found]), [
- # Otherwise add the 'name=' prefix
- with_cgroupctrl="name=$with_cgroupctrl"
-])
+ AC_MSG_ERROR([No running cgroup controller found]))
# ------------------------------------------------------------------------------
address_sanitizer_cflags=
# ------------------------------------------------------------------------------
address_sanitizer_cflags=
if (de->d_type != DT_DIR)
continue;
if (de->d_type != DT_DIR)
continue;
- if (streq(de->d_name, ".") ||
- streq(de->d_name, ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
b = strdup(de->d_name);
continue;
b = strdup(de->d_name);
if (r < 0 && errno != ENOENT)
return -errno;
if (r < 0 && errno != ENOENT)
return -errno;
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
+ r = cg_rmdir(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path);
+ if (r < 0)
+ log_warning_errno(r, "Failed to remove compat systemd cgroup %s: %m", path);
+ }
+
* just cuts off the name= prefixed used for named
* hierarchies, if it is specified. */
* just cuts off the name= prefixed used for named
* hierarchies, if it is specified. */
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+ if (cg_hybrid_unified())
+ controller = SYSTEMD_CGROUP_CONTROLLER_HYBRID;
+ else
+ controller = SYSTEMD_CGROUP_CONTROLLER_LEGACY;
+ }
+
e = startswith(controller, "name=");
if (e)
return e;
e = startswith(controller, "name=");
if (e)
return e;
}
int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
}
int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
if (!cg_controller_is_valid(controller))
return -EINVAL;
if (!cg_controller_is_valid(controller))
return -EINVAL;
- unified = cg_all_unified();
- if (unified < 0)
- return unified;
-
- if (unified > 0)
r = join_path_unified(path, suffix, fs);
else
r = join_path_legacy(controller, path, suffix, fs);
r = join_path_unified(path, suffix, fs);
else
r = join_path_legacy(controller, path, suffix, fs);
}
static int controller_is_accessible(const char *controller) {
}
static int controller_is_accessible(const char *controller) {
if (!cg_controller_is_valid(controller))
return -EINVAL;
if (!cg_controller_is_valid(controller))
return -EINVAL;
- unified = cg_all_unified();
- if (unified < 0)
- return unified;
- if (unified > 0) {
+ if (cg_all_unified()) {
/* We don't support named hierarchies if we are using
* the unified hierarchy. */
/* We don't support named hierarchies if we are using
* the unified hierarchy. */
int cg_trim(const char *controller, const char *path, bool delete_root) {
_cleanup_free_ char *fs = NULL;
int cg_trim(const char *controller, const char *path, bool delete_root) {
_cleanup_free_ char *fs = NULL;
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
+ q = cg_trim(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, delete_root);
+ if (q < 0)
+ log_warning_errno(q, "Failed to trim compat systemd cgroup %s: %m", path);
+ }
+
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
+ r = cg_create(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path);
+ if (r < 0)
+ log_warning_errno(r, "Failed to create compat systemd cgroup %s: %m", path);
+ }
+
xsprintf(c, PID_FMT "\n", pid);
xsprintf(c, PID_FMT "\n", pid);
- return write_string_file(fs, c, 0);
+ r = write_string_file(fs, c, 0);
+ if (r < 0)
+ return r;
+
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
+ r = cg_attach(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, pid);
+ if (r < 0)
+ log_warning_errno(r, "Failed to attach %d to compat systemd cgroup %s: %m", pid, path);
+ }
+
+ return 0;
}
int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
}
int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
- return chmod_and_chown(fs, mode, uid, gid);
+ r = chmod_and_chown(fs, mode, uid, gid);
+ if (r < 0)
+ return r;
+
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
+ r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set group access on compat systemd cgroup %s: %m", path);
+ }
+
+ return 0;
}
int cg_set_task_access(
}
int cg_set_task_access(
gid_t gid) {
_cleanup_free_ char *fs = NULL, *procs = NULL;
gid_t gid) {
_cleanup_free_ char *fs = NULL, *procs = NULL;
- unified = cg_unified(controller);
- if (unified < 0)
- return unified;
- if (unified)
- return 0;
+ if (!cg_unified(controller)) {
+ /* Compatibility, Always keep values for "tasks" in sync with
+ * "cgroup.procs" */
+ if (cg_get_path(controller, path, "tasks", &procs) >= 0)
+ (void) chmod_and_chown(procs, mode, uid, gid);
+ }
- /* Compatibility, Always keep values for "tasks" in sync with
- * "cgroup.procs" */
- if (cg_get_path(controller, path, "tasks", &procs) >= 0)
- (void) chmod_and_chown(procs, mode, uid, gid);
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
+ r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set task access on compat systemd cgroup %s: %m", path);
+ }
int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
+ const char *fs, *controller_str;
assert(path);
assert(pid >= 0);
assert(path);
assert(pid >= 0);
controller = SYSTEMD_CGROUP_CONTROLLER;
unified = cg_unified(controller);
controller = SYSTEMD_CGROUP_CONTROLLER;
unified = cg_unified(controller);
- if (unified < 0)
- return unified;
- if (unified == 0)
- cs = strlen(controller);
+ if (!unified) {
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
+ controller_str = SYSTEMD_CGROUP_CONTROLLER_LEGACY;
+ else
+ controller_str = controller;
+
+ cs = strlen(controller_str);
+ }
fs = procfs_file_alloca(pid, "cgroup");
log_debug_elogind("Searching for PID %u in \"%s\" (controller \"%s\")",
fs = procfs_file_alloca(pid, "cgroup");
log_debug_elogind("Searching for PID %u in \"%s\" (controller \"%s\")",
*e = 0;
FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
*e = 0;
FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
- if (k == cs && memcmp(word, controller, cs) == 0) {
+ if (k == cs && memcmp(word, controller_str, cs) == 0) {
int cg_install_release_agent(const char *controller, const char *agent) {
_cleanup_free_ char *fs = NULL, *contents = NULL;
const char *sc;
int cg_install_release_agent(const char *controller, const char *agent) {
_cleanup_free_ char *fs = NULL, *contents = NULL;
const char *sc;
- unified = cg_unified(controller);
- if (unified < 0)
- return unified;
- if (unified) /* doesn't apply to unified hierarchy */
+ if (cg_unified(controller)) /* doesn't apply to unified hierarchy */
return -EOPNOTSUPP;
r = cg_get_path(controller, NULL, "release_agent", &fs);
return -EOPNOTSUPP;
r = cg_get_path(controller, NULL, "release_agent", &fs);
int cg_uninstall_release_agent(const char *controller) {
_cleanup_free_ char *fs = NULL;
int cg_uninstall_release_agent(const char *controller) {
_cleanup_free_ char *fs = NULL;
- unified = cg_unified(controller);
- if (unified < 0)
- return unified;
- if (unified) /* Doesn't apply to unified hierarchy */
+ if (cg_unified(controller)) /* Doesn't apply to unified hierarchy */
return -EOPNOTSUPP;
r = cg_get_path(controller, NULL, "notify_on_release", &fs);
return -EOPNOTSUPP;
r = cg_get_path(controller, NULL, "notify_on_release", &fs);
}
int cg_is_empty_recursive(const char *controller, const char *path) {
}
int cg_is_empty_recursive(const char *controller, const char *path) {
if (controller && (isempty(path) || path_equal(path, "/")))
return false;
if (controller && (isempty(path) || path_equal(path, "/")))
return false;
- unified = cg_unified(controller);
- if (unified < 0)
- return unified;
-
- if (unified > 0) {
+ if (cg_unified(controller)) {
_cleanup_free_ char *t = NULL;
/* On the unified hierarchy we can check empty state
_cleanup_free_ char *t = NULL;
/* On the unified hierarchy we can check empty state
+ if (streq(p, SYSTEMD_CGROUP_CONTROLLER))
+ return true;
+
s = startswith(p, "name=");
if (s)
p = s;
s = startswith(p, "name=");
if (s)
p = s;
int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
CGroupController c;
int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
CGroupController c;
/* This one will create a cgroup in our private tree, but also
* duplicate it in the trees specified in mask, and remove it
/* This one will create a cgroup in our private tree, but also
* duplicate it in the trees specified in mask, and remove it
return r;
/* If we are in the unified hierarchy, we are done now */
return r;
/* If we are in the unified hierarchy, we are done now */
- unified = cg_all_unified();
- if (unified < 0)
- return unified;
- if (unified > 0)
return 0;
/* Otherwise, do the same in the other hierarchies */
return 0;
/* Otherwise, do the same in the other hierarchies */
int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
CGroupController c;
int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
CGroupController c;
r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
if (r < 0)
return r;
r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
if (r < 0)
return r;
- unified = cg_all_unified();
- if (unified < 0)
- return unified;
- if (unified > 0)
return 0;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
return 0;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
CGroupController c;
int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
CGroupController c;
if (!path_equal(from, to)) {
r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
if (!path_equal(from, to)) {
r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
- unified = cg_all_unified();
- if (unified < 0)
- return unified;
- if (unified > 0)
return r;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
return r;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
CGroupController c;
int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
CGroupController c;
r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
if (r < 0)
return r;
r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
if (r < 0)
return r;
- unified = cg_all_unified();
- if (unified < 0)
- return unified;
- if (unified > 0)
return r;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
return r;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
int cg_mask_supported(CGroupMask *ret) {
CGroupMask mask = 0;
int cg_mask_supported(CGroupMask *ret) {
CGroupMask mask = 0;
/* Determines the mask of supported cgroup controllers. Only
* includes controllers we can make sense of and that are
* actually accessible. */
/* Determines the mask of supported cgroup controllers. Only
* includes controllers we can make sense of and that are
* actually accessible. */
- unified = cg_all_unified();
- if (unified < 0)
- return unified;
- if (unified > 0) {
+ if (cg_all_unified()) {
_cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
const char *c;
_cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
const char *c;
if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
unified_cache = CGROUP_UNIFIED_ALL;
else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
unified_cache = CGROUP_UNIFIED_ALL;
else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
- 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;
+ if (statfs("/sys/fs/cgroup/unified/", &fs) == 0 &&
+ F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
+ unified_cache = CGROUP_UNIFIED_SYSTEMD;
+ else {
+ if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0)
+ return -errno;
+ if (!F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC))
+ return -ENOMEDIUM;
+ unified_cache = CGROUP_UNIFIED_NONE;
+ }
} else
return -ENOMEDIUM;
#else
} else
return -ENOMEDIUM;
#else
-int cg_unified(const char *controller) {
-
- int r;
+bool cg_unified(const char *controller) {
- r = cg_update_unified();
- if (r < 0)
- return r;
+ assert(cg_update_unified() >= 0);
if (streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER))
return unified_cache >= CGROUP_UNIFIED_SYSTEMD;
if (streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER))
return unified_cache >= CGROUP_UNIFIED_SYSTEMD;
return unified_cache >= CGROUP_UNIFIED_ALL;
}
return unified_cache >= CGROUP_UNIFIED_ALL;
}
-int cg_all_unified(void) {
+bool cg_all_unified(void) {
return cg_unified(NULL);
}
#if 0 /// UNNEEDED by elogind
return cg_unified(NULL);
}
#if 0 /// UNNEEDED by elogind
-void cg_unified_flush(void) {
+bool cg_hybrid_unified(void) {
+
+ assert(cg_update_unified() >= 0);
+
+ return unified_cache == CGROUP_UNIFIED_SYSTEMD;
+}
+
+int cg_unified_flush(void) {
unified_cache = CGROUP_UNIFIED_UNKNOWN;
unified_cache = CGROUP_UNIFIED_UNKNOWN;
+
+ return cg_update_unified();
}
int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
_cleanup_free_ char *fs = NULL;
CGroupController c;
}
int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
_cleanup_free_ char *fs = NULL;
CGroupController c;
assert(p);
if (supported == 0)
return 0;
assert(p);
if (supported == 0)
return 0;
- unified = cg_all_unified();
- if (unified < 0)
- return unified;
- if (!unified) /* on the legacy hiearchy there's no joining of controllers defined */
+ if (!cg_all_unified()) /* on the legacy hiearchy there's no joining of controllers defined */
return 0;
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
return 0;
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
bool cg_is_unified_wanted(void) {
static thread_local int wanted = -1;
bool cg_is_unified_wanted(void) {
static thread_local int wanted = -1;
/* If the hierarchy is already mounted, then follow whatever
* was chosen for it. */
/* If the hierarchy is already mounted, then follow whatever
* was chosen for it. */
- unified = cg_all_unified();
- if (unified >= 0)
- return unified;
+ if (cg_unified_flush() >= 0)
+ return cg_all_unified();
/* Otherwise, let's see what the kernel command line has to
* say. Since checking that is expensive, let's cache the
/* Otherwise, let's see what the kernel command line has to
* say. Since checking that is expensive, let's cache the
if (wanted >= 0)
return wanted;
if (wanted >= 0)
return wanted;
- r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy", NULL);
- if (r > 0)
- return (wanted = true);
- else {
- _cleanup_free_ char *value = NULL;
-
- r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy=", &value);
- if (r < 0)
- return false;
- if (r == 0)
- return (wanted = false);
+ r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", &b);
+ if (r < 0)
+ return false;
- return (wanted = parse_boolean(value) > 0);
- }
+ return (wanted = r > 0 ? b : false);
}
bool cg_is_legacy_wanted(void) {
}
bool cg_is_legacy_wanted(void) {
bool cg_is_unified_systemd_controller_wanted(void) {
static thread_local int wanted = -1;
bool cg_is_unified_systemd_controller_wanted(void) {
static thread_local int wanted = -1;
/* If the unified hierarchy is requested in full, no need to
* bother with this. */
/* If the unified hierarchy is requested in full, no need to
* bother with this. */
/* If the hierarchy is already mounted, then follow whatever
* was chosen for it. */
/* If the hierarchy is already mounted, then follow whatever
* was chosen for it. */
- unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
- if (unified >= 0)
- return unified;
+ if (cg_unified_flush() >= 0)
+ return cg_unified(SYSTEMD_CGROUP_CONTROLLER);
/* Otherwise, let's see what the kernel command line has to
* say. Since checking that is expensive, let's cache the
/* Otherwise, let's see what the kernel command line has to
* say. Since checking that is expensive, let's cache the
if (wanted >= 0)
return wanted;
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 false;
-
- if (r == 0)
- wanted = false;
- else
- wanted = parse_boolean(value) <= 0;
- }
-
- return wanted;
-}
+ r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", &b);
+ if (r < 0)
+ return false;
-bool cg_is_legacy_systemd_controller_wanted(void) {
- return cg_is_legacy_wanted() && !cg_is_unified_systemd_controller_wanted();
-}
#else
bool cg_is_legacy_wanted(void) {
return true;
#else
bool cg_is_legacy_wanted(void) {
return true;
+ /* The meaning of the kernel option is reversed wrt. to the return value
+ * of this function, hence the negation. */
+ return (wanted = r > 0 ? !b : false);
bool cg_ns_supported(void);
#endif // 0
bool cg_ns_supported(void);
#endif // 0
-int cg_all_unified(void);
-int cg_unified(const char *controller);
#if 0 /// UNNEEDED by elogind
#if 0 /// UNNEEDED by elogind
-void cg_unified_flush(void);
+bool cg_all_unified(void);
+bool cg_hybrid_unified(void);
+bool cg_unified(const char *controller);
+int cg_unified_flush(void);
bool cg_is_unified_wanted(void);
#endif // 0
bool cg_is_legacy_wanted(void);
#if 0 /// UNNEEDED by elogind
bool cg_is_unified_systemd_controller_wanted(void);
bool cg_is_unified_wanted(void);
#endif // 0
bool cg_is_legacy_wanted(void);
#if 0 /// UNNEEDED by elogind
bool cg_is_unified_systemd_controller_wanted(void);
-bool cg_is_legacy_systemd_controller_wanted(void);
#endif // 0
const char* cgroup_controller_to_string(CGroupController c) _const_;
#endif // 0
const char* cgroup_controller_to_string(CGroupController c) _const_;
* the watchdog pings will keep the loop busy. */
#define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
* the watchdog pings will keep the loop busy. */
#define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
+/* The default value for the net.unix.max_dgram_qlen sysctl */
+#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL
+
+#if 0 /// elogind allows foreign cgroup controllers. (Well, needs them, actually)
+#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd"
+#define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=unified"
+#define SYSTEMD_CGROUP_CONTROLLER "_systemd"
+#else
+#ifndef SYSTEMD_CGROUP_CONTROLLER_LEGACY
+# define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=elogind"
+#endif // SYSTEMD_CGROUP_CONTROLLER_LEGACY
+#ifndef SYSTEMD_CGROUP_CONTROLLER_HYBRID
+# define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=elogind"
+#endif // SYSTEMD_CGROUP_CONTROLLER_HYBRID
#ifndef SYSTEMD_CGROUP_CONTROLLER
#ifndef SYSTEMD_CGROUP_CONTROLLER
-# define SYSTEMD_CGROUP_CONTROLLER "name=elogind"
-#endif
+# define SYSTEMD_CGROUP_CONTROLLER "_elogind"
+#endif // SYSTEMD_CGROUP_CONTROLLER
+#endif // 0
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE
{ "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
{ "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,
+ { "cgroup", "/sys/fs/cgroup/unified", "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_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_systemd_controller_wanted, MNT_IN_CONTAINER },
+ cg_is_legacy_wanted, MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
#else
{ "cgroup", "/sys/fs/cgroup/elogind", "cgroup", "none,name=elogind,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
#else
{ "cgroup", "/sys/fs/cgroup/elogind", "cgroup", "none,name=elogind,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
int r = 0;
r = mount_points_setup(ELEMENTSOF(mount_table), loaded_policy);
int r = 0;
r = mount_points_setup(ELEMENTSOF(mount_table), loaded_policy);
* udevd. */
dev_setup(NULL, UID_INVALID, GID_INVALID);
* udevd. */
dev_setup(NULL, UID_INVALID, GID_INVALID);
- /* Mark the root directory as shared in regards to mount
- * propagation. The kernel defaults to "private", but we think
- * it makes more sense to have a default of "shared" so that
- * nspawn and the container tools work out of the box. If
- * specific setups need other settings they can reset the
- * propagation mode to private if needed. */
+ /* Mark the root directory as shared in regards to mount propagation. The kernel defaults to "private", but we
+ * think it makes more sense to have a default of "shared" so that nspawn and the container tools work out of
+ * the box. If specific setups need other settings they can reset the propagation mode to private if
+ * needed. Note that we set this only when we are invoked directly by the kernel. If we are invoked by a
+ * container manager we assume the container manager knows what it is doing (for example, because it set up
+ * some directories with different propagation modes). */
if (detect_container() <= 0)
if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
log_warning_errno(errno, "Failed to set up the root directory for shared mount propagation: %m");
if (detect_container() <= 0)
if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
log_warning_errno(errno, "Failed to set up the root directory for shared mount propagation: %m");
- /* Create a few directories we always want around, Note that
- * sd_booted() checks for /run/systemd/system, so this mkdir
- * really needs to stay for good, otherwise software that
- * copied sd-daemon.c into their sources will misdetect
- * systemd. */
+ /* Create a few directories we always want around, Note that sd_booted() checks for /run/systemd/system, so
+ * this mkdir really needs to stay for good, otherwise software that copied sd-daemon.c into their sources will
+ * misdetect systemd. */
(void) mkdir_label("/run/systemd", 0755);
(void) mkdir_label("/run/systemd/system", 0755);
(void) mkdir_label("/run/systemd", 0755);
(void) mkdir_label("/run/systemd/system", 0755);
- (void) mkdir_label("/run/systemd/inaccessible", 0000);
/* Set up inaccessible items */
/* Set up inaccessible items */
+ (void) mkdir_label("/run/systemd/inaccessible", 0000);
(void) mknod("/run/systemd/inaccessible/reg", S_IFREG | 0000, 0);
(void) mkdir_label("/run/systemd/inaccessible/dir", 0000);
(void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0));
(void) mknod("/run/systemd/inaccessible/reg", S_IFREG | 0000, 0);
(void) mkdir_label("/run/systemd/inaccessible/dir", 0000);
(void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0));