summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--man/systemd-system.conf.xml23
-rw-r--r--src/core/main.c6
-rw-r--r--src/core/mount-setup.c150
-rw-r--r--src/core/mount-setup.h2
-rw-r--r--src/core/system.conf.in1
-rw-r--r--src/shared/conf-parser.c115
-rw-r--r--src/shared/conf-parser.h1
-rw-r--r--src/test/test-conf-parser.c40
-rw-r--r--test/fuzz/fuzz-unit-file/directives.service1
9 files changed, 82 insertions, 257 deletions
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 5ce2c6fb96..ea17111bc5 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -107,29 +107,6 @@
</varlistentry>
<varlistentry>
- <term><varname>JoinControllers=cpu,cpuacct net_cls,netprio</varname></term>
-
- <listitem><para>Configures controllers that shall be mounted
- in a single hierarchy. By default, systemd will mount all
- controllers which are enabled in the kernel in individual
- hierarchies, with the exception of those listed in this
- setting. Takes a space-separated list of comma-separated
- controller names, in order to allow multiple joined
- hierarchies. Defaults to 'cpu,cpuacct'. Pass an empty string
- to ensure that systemd mounts all controllers in separate
- hierarchies.</para>
-
- <para>Note that this option is only applied once, at very
- early boot. If you use an initial RAM disk (initrd) that uses
- systemd, it might hence be necessary to rebuild the initrd if
- this option is changed, and make sure the new configuration
- file is included in it. Otherwise, the initrd might mount the
- controller hierarchies in a different configuration than
- intended, and the main system cannot remount them
- anymore.</para></listitem>
- </varlistentry>
-
- <varlistentry>
<term><varname>RuntimeWatchdogSec=</varname></term>
<term><varname>ShutdownWatchdogSec=</varname></term>
diff --git a/src/core/main.c b/src/core/main.c
index 11537c8140..cabcb9ec16 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -100,7 +100,6 @@ static ShowStatus arg_show_status = _SHOW_STATUS_INVALID;
static bool arg_switched_root = false;
static PagerFlags arg_pager_flags = 0;
static bool arg_service_watchdogs = true;
-static char ***arg_join_controllers = NULL;
static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
static usec_t arg_default_restart_usec = DEFAULT_RESTART_USEC;
@@ -667,7 +666,7 @@ static int parse_config_file(void) {
{ "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot },
{ "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL },
- { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
+ { "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_CONFIGURATION, NULL },
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
{ "Manager", "WatchdogDevice", config_parse_path, 0, &arg_watchdog_device },
@@ -1956,7 +1955,7 @@ static int initialize_runtime(
install_crash_handler();
if (!skip_setup) {
- r = mount_cgroup_controllers(arg_join_controllers);
+ r = mount_cgroup_controllers();
if (r < 0) {
*ret_error_message = "Failed to mount cgroup hierarchies";
return r;
@@ -2081,7 +2080,6 @@ static void free_arguments(void) {
arg_default_unit = mfree(arg_default_unit);
arg_confirm_spawn = mfree(arg_confirm_spawn);
- arg_join_controllers = strv_free_free(arg_join_controllers);
arg_default_environment = strv_free(arg_default_environment);
arg_syscall_archs = set_free(arg_syscall_archs);
}
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 16880e6157..e15d94d98a 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -229,76 +229,105 @@ int mount_setup_early(void) {
return mount_points_setup(N_EARLY_MOUNT, false);
}
-int mount_cgroup_controllers(char ***join_controllers) {
+static const char *join_with(const char *controller) {
+
+ static const char* const pairs[] = {
+ "cpu", "cpuacct",
+ "net_cls", "net_prio",
+ NULL
+ };
+
+ const char *const *x, *const *y;
+
+ assert(controller);
+
+ /* This will lookup which controller to mount another controller with. Input is a controller name, and output
+ * is the other controller name. The function works both ways: you can input one and get the other, and input
+ * the other to get the one. */
+
+ STRV_FOREACH_PAIR(x, y, pairs) {
+ if (streq(controller, *x))
+ return *y;
+ if (streq(controller, *y))
+ return *x;
+ }
+
+ return NULL;
+}
+
+static int symlink_controller(const char *target, const char *alias) {
+ const char *a;
+ int r;
+
+ assert(target);
+ assert(alias);
+
+ a = strjoina("/sys/fs/cgroup/", alias);
+
+ r = symlink_idempotent(target, a, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create symlink %s: %m", a);
+
+#ifdef SMACK_RUN_LABEL
+ const char *p;
+
+ p = strjoina("/sys/fs/cgroup/", target);
+
+ r = mac_smack_copy(a, p);
+ if (r < 0 && r != -EOPNOTSUPP)
+ return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", p, a);
+#endif
+
+ return 0;
+}
+
+int mount_cgroup_controllers(void) {
_cleanup_set_free_free_ Set *controllers = NULL;
- bool has_argument = !!join_controllers;
int r;
if (!cg_is_legacy_wanted())
return 0;
/* Mount all available cgroup controllers that are built into the kernel. */
-
- if (!has_argument)
- /* The defaults:
- * mount "cpu" + "cpuacct" together, and "net_cls" + "net_prio".
- *
- * We'd like to add "cpuset" to the mix, but "cpuset" doesn't really
- * work for groups with no initialized attributes.
- */
- join_controllers = (char**[]) {
- STRV_MAKE("cpu", "cpuacct"),
- STRV_MAKE("net_cls", "net_prio"),
- NULL,
- };
-
r = cg_kernel_controllers(&controllers);
if (r < 0)
return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");
for (;;) {
_cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
+ const char *other_controller;
MountPoint p = {
.what = "cgroup",
.type = "cgroup",
.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
.mode = MNT_IN_CONTAINER,
};
- char ***k = NULL;
controller = set_steal_first(controllers);
if (!controller)
break;
- for (k = join_controllers; *k; k++)
- if (strv_find(*k, controller))
- break;
-
- if (*k) {
- char **i, **j;
-
- for (i = *k, j = *k; *i; i++) {
-
- if (!streq(*i, controller)) {
- _cleanup_free_ char *t;
-
- t = set_remove(controllers, *i);
- if (!t) {
- if (has_argument)
- free(*i);
- continue;
- }
- }
-
- *(j++) = *i;
+ /* Check if we shall mount this together with another controller */
+ other_controller = join_with(controller);
+ if (other_controller) {
+ _cleanup_free_ char *c = NULL;
+
+ /* Check if the other controller is actually available in the kernel too */
+ c = set_remove(controllers, other_controller);
+ if (c) {
+
+ /* Join the two controllers into one string, and maintain a stable ordering */
+ if (strcmp(controller, other_controller) < 0)
+ options = strjoin(controller, ",", other_controller);
+ else
+ options = strjoin(other_controller, ",", controller);
+ if (!options)
+ return log_oom();
}
+ }
- *j = NULL;
-
- options = strv_join(*k, ",");
- if (!options)
- return log_oom();
- } else
+ /* The simple case, where there's only one controller to mount together */
+ if (!options)
options = TAKE_PTR(controller);
where = strappend("/sys/fs/cgroup/", options);
@@ -312,35 +341,14 @@ int mount_cgroup_controllers(char ***join_controllers) {
if (r < 0)
return r;
- if (r > 0 && *k) {
- char **i;
-
- for (i = *k; *i; i++) {
- _cleanup_free_ char *t = NULL;
-
- t = strappend("/sys/fs/cgroup/", *i);
- if (!t)
- return log_oom();
-
- r = symlink(options, t);
- if (r >= 0) {
-#ifdef SMACK_RUN_LABEL
- _cleanup_free_ char *src;
- src = strappend("/sys/fs/cgroup/", options);
- if (!src)
- return log_oom();
- r = mac_smack_copy(t, src);
- if (r < 0 && r != -EOPNOTSUPP)
- return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", src, t);
-#endif
- } else if (errno != EEXIST)
- return log_error_errno(errno, "Failed to create symlink %s: %m", t);
- }
- }
+ /* Create symlinks from the individual controller names, in case we have a joined mount */
+ if (controller)
+ (void) symlink_controller(options, controller);
+ if (other_controller)
+ (void) symlink_controller(options, other_controller);
}
- /* Now that we mounted everything, let's make the tmpfs the
- * cgroup file systems are mounted into read-only. */
+ /* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
(void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
return 0;
diff --git a/src/core/mount-setup.h b/src/core/mount-setup.h
index 43cd8908de..b4ca2cf4b4 100644
--- a/src/core/mount-setup.h
+++ b/src/core/mount-setup.h
@@ -6,7 +6,7 @@
int mount_setup_early(void);
int mount_setup(bool loaded_policy);
-int mount_cgroup_controllers(char ***join_controllers);
+int mount_cgroup_controllers(void);
bool mount_point_is_api(const char *path);
bool mount_point_ignore(const char *path);
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index ef1bbbd948..0a58737b82 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -23,7 +23,6 @@
#CrashReboot=no
#CtrlAltDelBurstAction=reboot-force
#CPUAffinity=1 2
-#JoinControllers=cpu,cpuacct net_cls,net_prio
#RuntimeWatchdogSec=0
#ShutdownWatchdogSec=10min
#WatchdogDevice=
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 493ece9d09..b417ac2d6d 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -1013,121 +1013,6 @@ int config_parse_ip_port(
return 0;
}
-int config_parse_join_controllers(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- char ****ret = data;
- const char *whole_rvalue = rvalue;
- unsigned n = 0;
- _cleanup_(strv_free_freep) char ***controllers = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(ret);
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- char **l;
- int r;
-
- r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
- return r;
- }
- if (r == 0)
- break;
-
- l = strv_split(word, ",");
- if (!l)
- return log_oom();
- strv_uniq(l);
-
- if (strv_length(l) <= 1) {
- strv_free(l);
- continue;
- }
-
- if (!controllers) {
- controllers = new(char**, 2);
- if (!controllers) {
- strv_free(l);
- return log_oom();
- }
-
- controllers[0] = l;
- controllers[1] = NULL;
-
- n = 1;
- } else {
- char ***a;
- char ***t;
-
- t = new0(char**, n+2);
- if (!t) {
- strv_free(l);
- return log_oom();
- }
-
- n = 0;
-
- for (a = controllers; *a; a++)
- if (strv_overlap(*a, l)) {
- if (strv_extend_strv(&l, *a, false) < 0) {
- strv_free(l);
- strv_free_free(t);
- return log_oom();
- }
-
- } else {
- char **c;
-
- c = strv_copy(*a);
- if (!c) {
- strv_free(l);
- strv_free_free(t);
- return log_oom();
- }
-
- t[n++] = c;
- }
-
- t[n++] = strv_uniq(l);
-
- strv_free_free(controllers);
- controllers = t;
- }
- }
- if (!isempty(rvalue))
- log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
-
- /* As a special case, return a single empty strv, to override the default */
- if (!controllers) {
- controllers = new(char**, 2);
- if (!controllers)
- return log_oom();
- controllers[0] = strv_new(NULL);
- if (!controllers[0])
- return log_oom();
- controllers[1] = NULL;
- }
-
- strv_free_free(*ret);
- *ret = TAKE_PTR(controllers);
-
- return 0;
-}
-
int config_parse_mtu(
const char *unit,
const char *filename,
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 16f042d894..865db4278b 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -137,7 +137,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_personality);
CONFIG_PARSER_PROTOTYPE(config_parse_permille);
CONFIG_PARSER_PROTOTYPE(config_parse_ifname);
CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
-CONFIG_PARSER_PROTOTYPE(config_parse_join_controllers);
CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index 368e02cb33..497becff73 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -210,45 +210,6 @@ static void test_config_parse_iec_uint64(void) {
assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0);
}
-static void test_config_parse_join_controllers(void) {
- int r;
- _cleanup_(strv_free_freep) char ***c = NULL;
- char ***c2;
-
- /* Test normal operation */
- r = config_parse_join_controllers(NULL, "example.conf", 11, "Section", 10, "JoinControllers", 0, "cpu,cpuacct net_cls,netprio", &c, NULL);
- assert_se(r == 0);
- assert_se(c);
- assert_se(strv_length(c[0]) == 2);
- assert_se(strv_equal(c[0], STRV_MAKE("cpu", "cpuacct")));
- assert_se(strv_length(c[1]) == 2);
- assert_se(strv_equal(c[1], STRV_MAKE("net_cls", "netprio")));
- assert_se(c[2] == NULL);
-
- /* Test special case of no mounted controllers */
- r = config_parse_join_controllers(NULL, "example.conf", 12, "Section", 10, "JoinControllers", 0, "", &c, NULL);
- assert_se(r == 0);
- assert_se(c);
- assert_se(strv_equal(c[0], STRV_MAKE_EMPTY));
- assert_se(c[1] == NULL);
-
- /* Test merging of overlapping lists */
- r = config_parse_join_controllers(NULL, "example.conf", 13, "Section", 10, "JoinControllers", 0, "a,b b,c", &c, NULL);
- assert_se(r == 0);
- assert_se(c);
- assert_se(strv_length(c[0]) == 3);
- assert_se(strv_contains(c[0], "a"));
- assert_se(strv_contains(c[0], "b"));
- assert_se(strv_contains(c[0], "c"));
- assert_se(c[1] == NULL);
-
- /* Test ignoring of bad lines */
- c2 = c;
- r = config_parse_join_controllers(NULL, "example.conf", 14, "Section", 10, "JoinControllers", 0, "a,\"b ", &c, NULL);
- assert_se(r < 0);
- assert_se(c == c2);
-}
-
#define x10(x) x x x x x x x x x x
#define x100(x) x10(x10(x))
#define x1000(x) x10(x100(x))
@@ -407,7 +368,6 @@ int main(int argc, char **argv) {
test_config_parse_sec();
test_config_parse_nsec();
test_config_parse_iec_uint64();
- test_config_parse_join_controllers();
for (i = 0; i < ELEMENTSOF(config_file); i++)
test_config_parse(i, config_file[i]);
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index fd830dde41..f454fd313e 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -690,7 +690,6 @@ HibernateMode=
HibernateState=
HybridSleepMode=
HybridSleepState=
-JoinControllers=
LogColor=
LogLevel=
LogLocation=