a4b143
From 9c9e7b8fffbb21009d39a90076542e553a5c2190 Mon Sep 17 00:00:00 2001
a4b143
From: Lennart Poettering <lennart@poettering.net>
a4b143
Date: Mon, 23 Sep 2013 21:56:05 -0500
a4b143
Subject: [PATCH] cgroup: if we do a cgroup operation then do something on all
a4b143
 supported controllers
a4b143
a4b143
Previously we did operations like attach, trim or migrate only on the
a4b143
controllers that were enabled for a specific unit. With this changes we
a4b143
will now do them for all supproted controllers, and fall back to all
a4b143
possible prefix paths if the specified paths do not exist.
a4b143
a4b143
This fixes issues if a controller is being disabled for a unit where it
a4b143
was previously enabled, and makes sure that all processes stay as "far
a4b143
down" the tree as groups exist.
a4b143
---
a4b143
 src/core/cgroup.c        |   8 +--
a4b143
 src/core/execute.c       |   4 +-
a4b143
 src/core/mount.c         |   2 +-
a4b143
 src/core/scope.c         |   2 +-
a4b143
 src/core/service.c       |   2 +-
a4b143
 src/core/socket.c        |   2 +-
a4b143
 src/core/swap.c          |   2 +-
a4b143
 src/shared/cgroup-util.c | 154 ++++++++++++++++++++++++++++++-----------------
a4b143
 src/shared/cgroup-util.h |  12 ++--
a4b143
 9 files changed, 118 insertions(+), 70 deletions(-)
a4b143
a4b143
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
a4b143
index 24a2306..2f1e4a3 100644
a4b143
--- a/src/core/cgroup.c
a4b143
+++ b/src/core/cgroup.c
a4b143
@@ -409,13 +409,13 @@ static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
a4b143
         }
a4b143
 
a4b143
         /* First, create our own group */
a4b143
-        r = cg_create_with_mask(mask, path);
a4b143
+        r = cg_create_everywhere(u->manager->cgroup_supported, mask, path);
a4b143
         if (r < 0)
a4b143
                 log_error("Failed to create cgroup %s: %s", path, strerror(-r));
a4b143
 
a4b143
         /* Then, possibly move things over */
a4b143
-        if (u->cgroup_path && !streq(path, u->cgroup_path)) {
a4b143
-                r = cg_migrate_with_mask(mask, u->cgroup_path, path);
a4b143
+        if (u->cgroup_path) {
a4b143
+                r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, path);
a4b143
                 if (r < 0)
a4b143
                         log_error("Failed to migrate cgroup %s: %s", path, strerror(-r));
a4b143
         }
a4b143
@@ -549,7 +549,7 @@ void unit_destroy_cgroup(Unit *u) {
a4b143
         if (!u->cgroup_path)
a4b143
                 return;
a4b143
 
a4b143
-        r = cg_trim_with_mask(u->cgroup_mask, u->cgroup_path, !unit_has_name(u, SPECIAL_ROOT_SLICE));
a4b143
+        r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !unit_has_name(u, SPECIAL_ROOT_SLICE));
a4b143
         if (r < 0)
a4b143
                 log_debug("Failed to destroy cgroup %s: %s", u->cgroup_path, strerror(-r));
a4b143
 
a4b143
diff --git a/src/core/execute.c b/src/core/execute.c
a4b143
index 43b571e..789122e 100644
a4b143
--- a/src/core/execute.c
a4b143
+++ b/src/core/execute.c
a4b143
@@ -1016,7 +1016,7 @@ int exec_spawn(ExecCommand *command,
a4b143
                bool apply_chroot,
a4b143
                bool apply_tty_stdin,
a4b143
                bool confirm_spawn,
a4b143
-               CGroupControllerMask cgroup_mask,
a4b143
+               CGroupControllerMask cgroup_supported,
a4b143
                const char *cgroup_path,
a4b143
                const char *unit_id,
a4b143
                int idle_pipe[4],
a4b143
@@ -1197,7 +1197,7 @@ int exec_spawn(ExecCommand *command,
a4b143
                 }
a4b143
 
a4b143
                 if (cgroup_path) {
a4b143
-                        err = cg_attach_with_mask(cgroup_mask, cgroup_path, 0);
a4b143
+                        err = cg_attach_everywhere(cgroup_supported, cgroup_path, 0);
a4b143
                         if (err < 0) {
a4b143
                                 r = EXIT_CGROUP;
a4b143
                                 goto fail_child;
a4b143
diff --git a/src/core/mount.c b/src/core/mount.c
a4b143
index 5c18d4e..78c5c1e 100644
a4b143
--- a/src/core/mount.c
a4b143
+++ b/src/core/mount.c
a4b143
@@ -888,7 +888,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
a4b143
                        true,
a4b143
                        true,
a4b143
                        UNIT(m)->manager->confirm_spawn,
a4b143
-                       UNIT(m)->cgroup_mask,
a4b143
+                       UNIT(m)->manager->cgroup_supported,
a4b143
                        UNIT(m)->cgroup_path,
a4b143
                        UNIT(m)->id,
a4b143
                        NULL,
a4b143
diff --git a/src/core/scope.c b/src/core/scope.c
a4b143
index b94f3ff..50e5dba 100644
a4b143
--- a/src/core/scope.c
a4b143
+++ b/src/core/scope.c
a4b143
@@ -257,7 +257,7 @@ static int scope_start(Unit *u) {
a4b143
                 return r;
a4b143
         }
a4b143
 
a4b143
-        r = cg_attach_many_with_mask(u->cgroup_mask, u->cgroup_path, s->pids);
a4b143
+        r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, s->pids);
a4b143
         if (r < 0)
a4b143
                 return r;
a4b143
 
a4b143
diff --git a/src/core/service.c b/src/core/service.c
a4b143
index 5953f45..fc04196 100644
a4b143
--- a/src/core/service.c
a4b143
+++ b/src/core/service.c
a4b143
@@ -1826,7 +1826,7 @@ static int service_spawn(
a4b143
                        apply_chroot,
a4b143
                        apply_tty_stdin,
a4b143
                        UNIT(s)->manager->confirm_spawn,
a4b143
-                       UNIT(s)->cgroup_mask,
a4b143
+                       UNIT(s)->manager->cgroup_supported,
a4b143
                        path,
a4b143
                        UNIT(s)->id,
a4b143
                        s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
a4b143
diff --git a/src/core/socket.c b/src/core/socket.c
a4b143
index 2130e48..25c2a51 100644
a4b143
--- a/src/core/socket.c
a4b143
+++ b/src/core/socket.c
a4b143
@@ -1241,7 +1241,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
a4b143
                        true,
a4b143
                        true,
a4b143
                        UNIT(s)->manager->confirm_spawn,
a4b143
-                       UNIT(s)->cgroup_mask,
a4b143
+                       UNIT(s)->manager->cgroup_supported,
a4b143
                        UNIT(s)->cgroup_path,
a4b143
                        UNIT(s)->id,
a4b143
                        NULL,
a4b143
diff --git a/src/core/swap.c b/src/core/swap.c
a4b143
index 76c7d45..d225485 100644
a4b143
--- a/src/core/swap.c
a4b143
+++ b/src/core/swap.c
a4b143
@@ -625,7 +625,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
a4b143
                        true,
a4b143
                        true,
a4b143
                        UNIT(s)->manager->confirm_spawn,
a4b143
-                       UNIT(s)->cgroup_mask,
a4b143
+                       UNIT(s)->manager->cgroup_supported,
a4b143
                        UNIT(s)->cgroup_path,
a4b143
                        UNIT(s)->id,
a4b143
                        NULL,
a4b143
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
a4b143
index 0bffebd..2e630d4 100644
a4b143
--- a/src/shared/cgroup-util.c
a4b143
+++ b/src/shared/cgroup-util.c
a4b143
@@ -435,6 +435,46 @@ int cg_migrate_recursive(
a4b143
         return ret;
a4b143
 }
a4b143
 
a4b143
+int cg_migrate_recursive_fallback(
a4b143
+                const char *cfrom,
a4b143
+                const char *pfrom,
a4b143
+                const char *cto,
a4b143
+                const char *pto,
a4b143
+                bool ignore_self,
a4b143
+                bool rem) {
a4b143
+
a4b143
+        int r;
a4b143
+
a4b143
+        assert(cfrom);
a4b143
+        assert(pfrom);
a4b143
+        assert(cto);
a4b143
+        assert(pto);
a4b143
+
a4b143
+        r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
a4b143
+        if (r < 0) {
a4b143
+                char prefix[strlen(pto) + 1];
a4b143
+
a4b143
+                /* This didn't work? Then let's try all prefixes of the destination */
a4b143
+
a4b143
+                strcpy(prefix, pto);
a4b143
+                for (;;) {
a4b143
+                        char *slash;
a4b143
+
a4b143
+                        slash = strrchr(prefix, '/');
a4b143
+                        if (!slash)
a4b143
+                                break;
a4b143
+
a4b143
+                        *slash = 0;
a4b143
+
a4b143
+                        r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
a4b143
+                        if (r >= 0)
a4b143
+                                break;
a4b143
+                }
a4b143
+        }
a4b143
+
a4b143
+        return r;
a4b143
+}
a4b143
+
a4b143
 static const char *normalize_controller(const char *controller) {
a4b143
 
a4b143
         assert(controller);
a4b143
@@ -607,6 +647,39 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
a4b143
         return write_string_file(fs, c);
a4b143
 }
a4b143
 
a4b143
+int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
a4b143
+        int r;
a4b143
+
a4b143
+        assert(controller);
a4b143
+        assert(path);
a4b143
+        assert(pid >= 0);
a4b143
+
a4b143
+        r = cg_attach(controller, path, pid);
a4b143
+        if (r < 0) {
a4b143
+                char prefix[strlen(path) + 1];
a4b143
+
a4b143
+                /* This didn't work? Then let's try all prefixes of
a4b143
+                 * the destination */
a4b143
+
a4b143
+                strcpy(prefix, path);
a4b143
+                for (;;) {
a4b143
+                        char *slash;
a4b143
+
a4b143
+                        slash = strrchr(prefix, '/');
a4b143
+                        if (!slash)
a4b143
+                                break;
a4b143
+
a4b143
+                        *slash = 0;
a4b143
+
a4b143
+                        r = cg_attach(controller, prefix, pid);
a4b143
+                        if (r >= 0)
a4b143
+                                break;
a4b143
+                }
a4b143
+        }
a4b143
+
a4b143
+        return r;
a4b143
+}
a4b143
+
a4b143
 int cg_set_group_access(
a4b143
                 const char *controller,
a4b143
                 const char *path,
a4b143
@@ -1607,7 +1680,7 @@ static const char mask_names[] =
a4b143
         "memory\0"
a4b143
         "devices\0";
a4b143
 
a4b143
-int cg_create_with_mask(CGroupControllerMask mask, const char *path) {
a4b143
+int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
a4b143
         CGroupControllerMask bit = 1;
a4b143
         const char *n;
a4b143
         int r;
a4b143
@@ -1623,102 +1696,75 @@ int cg_create_with_mask(CGroupControllerMask mask, const char *path) {
a4b143
 
a4b143
         /* Then, do the same in the other hierarchies */
a4b143
         NULSTR_FOREACH(n, mask_names) {
a4b143
-                if (bit & mask)
a4b143
+                if (mask & bit)
a4b143
                         cg_create(n, path);
a4b143
-                else
a4b143
+                else if (supported & bit)
a4b143
                         cg_trim(n, path, true);
a4b143
 
a4b143
                 bit <<= 1;
a4b143
         }
a4b143
 
a4b143
-        return r;
a4b143
+        return 0;
a4b143
 }
a4b143
 
a4b143
-int cg_attach_with_mask(CGroupControllerMask mask, const char *path, pid_t pid) {
a4b143
+int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid) {
a4b143
         CGroupControllerMask bit = 1;
a4b143
         const char *n;
a4b143
         int r;
a4b143
 
a4b143
         r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
a4b143
+        if (r < 0)
a4b143
+                return r;
a4b143
 
a4b143
         NULSTR_FOREACH(n, mask_names) {
a4b143
-                if (bit & mask)
a4b143
-                        cg_attach(n, path, pid);
a4b143
-                else {
a4b143
-                        char prefix[strlen(path) + 1], *slash;
a4b143
-
a4b143
-                        /* OK, this one is a bit harder... Now we need
a4b143
-                         * to add to the closest parent cgroup we
a4b143
-                         * can find */
a4b143
-                        strcpy(prefix, path);
a4b143
-                        while ((slash = strrchr(prefix, '/'))) {
a4b143
-                                int q;
a4b143
-                                *slash = 0;
a4b143
-
a4b143
-                                q = cg_attach(n, prefix, pid);
a4b143
-                                if (q >= 0)
a4b143
-                                        break;
a4b143
-                        }
a4b143
-                }
a4b143
+                if (supported & bit)
a4b143
+                        cg_attach_fallback(n, path, pid);
a4b143
 
a4b143
                 bit <<= 1;
a4b143
         }
a4b143
 
a4b143
-        return r;
a4b143
+        return 0;
a4b143
 }
a4b143
 
a4b143
-int cg_attach_many_with_mask(CGroupControllerMask mask, const char *path, Set* pids) {
a4b143
+int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids) {
a4b143
         Iterator i;
a4b143
         void *pidp;
a4b143
         int r = 0;
a4b143
 
a4b143
         SET_FOREACH(pidp, pids, i) {
a4b143
                 pid_t pid = PTR_TO_LONG(pidp);
a4b143
-                int k;
a4b143
+                int q;
a4b143
 
a4b143
-                k = cg_attach_with_mask(mask, path, pid);
a4b143
-                if (k < 0)
a4b143
-                        r = k;
a4b143
+                q = cg_attach_everywhere(supported, path, pid);
a4b143
+                if (q < 0)
a4b143
+                        r = q;
a4b143
         }
a4b143
 
a4b143
         return r;
a4b143
 }
a4b143
 
a4b143
-int cg_migrate_with_mask(CGroupControllerMask mask, const char *from, const char *to) {
a4b143
+int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to) {
a4b143
         CGroupControllerMask bit = 1;
a4b143
         const char *n;
a4b143
         int r;
a4b143
 
a4b143
-        if (path_equal(from, to))
a4b143
-                return 0;
a4b143
-
a4b143
-        r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
a4b143
+        if (!path_equal(from, to))  {
a4b143
+                r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
a4b143
+                if (r < 0)
a4b143
+                        return r;
a4b143
+        }
a4b143
 
a4b143
         NULSTR_FOREACH(n, mask_names) {
a4b143
-                if (bit & mask)
a4b143
-                        cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, to, n, to, false, false);
a4b143
-                else {
a4b143
-                        char prefix[strlen(to) + 1], *slash;
a4b143
-
a4b143
-                        strcpy(prefix, to);
a4b143
-                        while ((slash = strrchr(prefix, '/'))) {
a4b143
-                                int q;
a4b143
-
a4b143
-                                *slash = 0;
a4b143
-
a4b143
-                                q = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, to, n, prefix, false, false);
a4b143
-                                if (q >= 0)
a4b143
-                                        break;
a4b143
-                        }
a4b143
-                }
a4b143
+                if (supported & bit)
a4b143
+                        cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, to, false, false);
a4b143
 
a4b143
                 bit <<= 1;
a4b143
         }
a4b143
 
a4b143
-        return r;
a4b143
+        return 0;
a4b143
 }
a4b143
 
a4b143
-int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_root) {
a4b143
+int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
a4b143
         CGroupControllerMask bit = 1;
a4b143
         const char *n;
a4b143
         int r;
a4b143
@@ -1728,13 +1774,13 @@ int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_r
a4b143
                 return r;
a4b143
 
a4b143
         NULSTR_FOREACH(n, mask_names) {
a4b143
-                if (bit & mask)
a4b143
+                if (supported & bit)
a4b143
                         cg_trim(n, path, delete_root);
a4b143
 
a4b143
                 bit <<= 1;
a4b143
         }
a4b143
 
a4b143
-        return r;
a4b143
+        return 0;
a4b143
 }
a4b143
 
a4b143
 CGroupControllerMask cg_mask_supported(void) {
a4b143
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
a4b143
index 0fc93c1..0963450 100644
a4b143
--- a/src/shared/cgroup-util.h
a4b143
+++ b/src/shared/cgroup-util.h
a4b143
@@ -64,6 +64,7 @@ int cg_kill_recursive_and_wait(const char *controller, const char *path, bool re
a4b143
 
a4b143
 int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self);
a4b143
 int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool remove);
a4b143
+int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem);
a4b143
 
a4b143
 int cg_split_spec(const char *spec, char **controller, char **path);
a4b143
 int cg_join_spec(const char *controller, const char *path, char **spec);
a4b143
@@ -81,6 +82,7 @@ int cg_delete(const char *controller, const char *path);
a4b143
 
a4b143
 int cg_create(const char *controller, const char *path);
a4b143
 int cg_attach(const char *controller, const char *path, pid_t pid);
a4b143
+int cg_attach_fallback(const char *controller, const char *path, pid_t pid);
a4b143
 int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
a4b143
 
a4b143
 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
a4b143
@@ -126,10 +128,10 @@ bool cg_controller_is_valid(const char *p, bool allow_named);
a4b143
 
a4b143
 int cg_slice_to_path(const char *unit, char **ret);
a4b143
 
a4b143
-int cg_create_with_mask(CGroupControllerMask mask, const char *path);
a4b143
-int cg_attach_with_mask(CGroupControllerMask mask, const char *path, pid_t pid);
a4b143
-int cg_attach_many_with_mask(CGroupControllerMask mask, const char *path, Set* pids);
a4b143
-int cg_migrate_with_mask(CGroupControllerMask mask, const char *from, const char *to);
a4b143
-int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_root);
a4b143
+int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path);
a4b143
+int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid);
a4b143
+int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids);
a4b143
+int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to);
a4b143
+int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root);
a4b143
 
a4b143
 CGroupControllerMask cg_mask_supported(void);