chiark / gitweb /
systemd: fix memory leak in cgroup code
[elogind.git] / src / core / cgroup.c
index 8bf4d896deaf843603c2415d22a789ae5986f02f..1a8fd3728f06acf9179a2170d175507b77e8a91e 100644 (file)
@@ -41,7 +41,7 @@ void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
         assert(c);
         assert(a);
 
-        LIST_REMOVE(CGroupDeviceAllow, device_allow, c->device_allow, a);
+        LIST_REMOVE(device_allow, c->device_allow, a);
         free(a->path);
         free(a);
 }
@@ -50,7 +50,7 @@ void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODe
         assert(c);
         assert(w);
 
-        LIST_REMOVE(CGroupBlockIODeviceWeight, device_weights, c->blockio_device_weights, w);
+        LIST_REMOVE(device_weights, c->blockio_device_weights, w);
         free(w->path);
         free(w);
 }
@@ -59,7 +59,7 @@ void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockI
         assert(c);
         assert(b);
 
-        LIST_REMOVE(CGroupBlockIODeviceBandwidth, device_bandwidths, c->blockio_device_bandwidths, b);
+        LIST_REMOVE(device_bandwidths, c->blockio_device_bandwidths, b);
         free(b->path);
         free(b);
 }
@@ -376,23 +376,23 @@ static CGroupControllerMask unit_get_siblings_mask(Unit *u) {
 }
 
 static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
-        char *path = NULL;
+        _cleanup_free_ char *path;
         int r;
-        bool is_in_hash = false;
+        bool was_in_hash = false;
 
         assert(u);
 
         path = unit_default_cgroup_path(u);
         if (!path)
-                return -ENOMEM;
+                return log_oom();
 
         r = hashmap_put(u->manager->cgroup_unit, path, u);
         if (r == 0)
-                is_in_hash = true;
-
-        if (r < 0) {
-                log_error("cgroup %s exists already: %s", path, strerror(-r));
-                free(path);
+                was_in_hash = true;
+        else if (r < 0) {
+                log_error(r == -EEXIST ?
+                          "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s",
+                          path, strerror(-r));
                 return r;
         }
 
@@ -405,13 +405,15 @@ static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
         if (u->cgroup_path) {
                 r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, path);
                 if (r < 0)
-                        log_error("Failed to migrate cgroup %s: %s", path, strerror(-r));
+                        log_error("Failed to migrate cgroup from %s to %s: %s",
+                                  u->cgroup_path, path, strerror(-r));
         }
 
-        if (!is_in_hash) {
-                /* And remember the new data */
+        if (!was_in_hash) {
+                /* Remember the new data */
                 free(u->cgroup_path);
                 u->cgroup_path = path;
+                path = NULL;
         }
 
         u->cgroup_realized = true;
@@ -426,7 +428,7 @@ static int unit_realize_cgroup_now(Unit *u) {
         assert(u);
 
         if (u->in_cgroup_queue) {
-                LIST_REMOVE(Unit, cgroup_queue, u->manager->cgroup_queue, u);
+                LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
                 u->in_cgroup_queue = false;
         }
 
@@ -450,7 +452,7 @@ static void unit_add_to_cgroup_queue(Unit *u) {
         if (u->in_cgroup_queue)
                 return;
 
-        LIST_PREPEND(Unit, cgroup_queue, u->manager->cgroup_queue, u);
+        LIST_PREPEND(cgroup_queue, u->manager->cgroup_queue, u);
         u->in_cgroup_queue = true;
 }
 
@@ -509,7 +511,7 @@ int unit_realize_cgroup(Unit *u) {
          * unit, we need to first create all parents, but there's more
          * actually: for the weight-based controllers we also need to
          * make sure that all our siblings (i.e. units that are in the
-         * same slice as we are) have cgroup too. Otherwise things
+         * same slice as we are) have cgroups, too. Otherwise things
          * would become very uneven as each of their processes would
          * get as much resources as all our group together. This call
          * will synchronously create the parent cgroups, but will
@@ -589,8 +591,8 @@ pid_t unit_search_main_pid(Unit *u) {
 
 int manager_setup_cgroup(Manager *m) {
         _cleanup_free_ char *path = NULL;
+        char *e;
         int r;
-        char *e, *a;
 
         assert(m);
 
@@ -610,9 +612,13 @@ int manager_setup_cgroup(Manager *m) {
                 return r;
         }
 
-        /* Already in /system.slice? If so, let's cut this off again */
+        /* LEGACY: Already in /system.slice? If so, let's cut this
+         * off. This is to support live upgrades from older systemd
+         * versions where PID 1 was moved there. */
         if (m->running_as == SYSTEMD_SYSTEM) {
                 e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
+                if (!e)
+                        e = endswith(m->cgroup_root, "/system");
                 if (e)
                         *e = 0;
         }
@@ -643,12 +649,8 @@ int manager_setup_cgroup(Manager *m) {
                         log_debug("Release agent already installed.");
         }
 
-        /* 4. Realize the system slice and put us in there */
-        if (m->running_as == SYSTEMD_SYSTEM) {
-                a = strappenda(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
-                r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, a, 0);
-        } else
-                r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, 0);
+        /* 4. Make sure we are in the root cgroup */
+        r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, 0);
         if (r < 0) {
                 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
                 return r;