]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: remove JoinControllers= configuration setting
authorLennart Poettering <lennart@poettering.net>
Thu, 15 Nov 2018 20:07:43 +0000 (21:07 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 16 Nov 2018 13:54:13 +0000 (14:54 +0100)
This removes the ability to configure which cgroup controllers to mount
together. Instead, we'll now hardcode that "cpu" and "cpuacct" are
mounted together as well as "net_cls" and "net_prio".

The concept of mounting controllers together has no future as it does
not exist to cgroupsv2. Moreover, the current logic is systematically
broken, as revealed by the discussions in #10507. Also, we surveyed Red
Hat customers and couldn't find a single user of the concept (which
isn't particularly surprising, as it is broken...)

This reduced the (already way too complex) cgroup handling for us, since
we now know whenever we make a change to a cgroup for one controller to
which other controllers it applies.

man/systemd-system.conf.xml
src/core/main.c
src/core/mount-setup.c
src/core/mount-setup.h
src/core/system.conf.in
src/shared/conf-parser.c
src/shared/conf-parser.h
src/test/test-conf-parser.c
test/fuzz/fuzz-unit-file/directives.service

index 5ce2c6fb96c862fa76afa84f96ecb7a116e52e7d..ea17111bc59eba7b58c549f301f5b6bee4236b39 100644 (file)
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
       </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>
index 11537c81406560c3c9d5dcc1ee3dc3cb6df84f8a..cabcb9ec165cd51ee269e45ac0d5fa06646a1cd1 100644 (file)
@@ -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);
 }
index 16880e6157062f294547fdf25ae737caf8aeaa31..e15d94d98a2b226c977f8d270658bdd96efc77ad 100644 (file)
@@ -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;
index 43cd8908dee57572b97e53092b7d756de27fec00..b4ca2cf4b45bf28de8bd124d7746ac51e06c73f7 100644 (file)
@@ -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);
index ef1bbbd948f652c7f53d49c6e34a7f07daf00632..0a58737b8224f17ecf23c0bf3073f4ac5d83528e 100644 (file)
@@ -23,7 +23,6 @@
 #CrashReboot=no
 #CtrlAltDelBurstAction=reboot-force
 #CPUAffinity=1 2
-#JoinControllers=cpu,cpuacct net_cls,net_prio
 #RuntimeWatchdogSec=0
 #ShutdownWatchdogSec=10min
 #WatchdogDevice=
index 493ece9d09eff0118078db71f5c4c487a6b30050..b417ac2d6d8716debc4fd6c55d908c50da9fd0ac 100644 (file)
@@ -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,
index 16f042d8947613240d5abea2cd32e979ab5cef2f..865db4278b9faa46bd9aeeec883baed4efa0d5ef 100644 (file)
@@ -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);
 
index 368e02cb338a6a1277db64eb06df8b9c52a7ffb4..497becff731c62df97781fde9c1a3b5a1affdccb 100644 (file)
@@ -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]);
index fd830dde416ac79d50d2ab92aad1aac3c4d6e811..f454fd313ec63044a4ac823bc509f28a43817bc2 100644 (file)
@@ -690,7 +690,6 @@ HibernateMode=
 HibernateState=
 HybridSleepMode=
 HybridSleepState=
-JoinControllers=
 LogColor=
 LogLevel=
 LogLocation=