]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cgroup: update only siblings that got realized once
authorLennart Poettering <lennart@poettering.net>
Mon, 13 Jan 2020 19:06:39 +0000 (20:06 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 14 Jan 2020 09:44:19 +0000 (10:44 +0100)
Fixes: #14475
Replaces: #14554

src/core/cgroup.c

index 148ea1a8b19a86c74938d4197de22f8aba6bf73a..21a63a2d0d131d41181985b6ed0172951ba2964e 100644 (file)
@@ -2335,7 +2335,15 @@ static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
         Unit *slice;
 
         /* This adds the siblings of the specified unit and the siblings of all parent units to the cgroup
-         * queue. (But neither the specified unit itself nor the parents.) */
+         * queue. (But neither the specified unit itself nor the parents.)
+         *
+         * Propagation of realization "side-ways" (i.e. towards siblings) is in relevant on cgroup-v1 where
+         * scheduling become very weird if two units that own processes reside in the same slice, but one is
+         * realized in the "cpu" hierarchy and once is not (for example because one has CPUWeight= set and
+         * the other does not), because that means processes need to be scheduled against groups. Let's avoid
+         * this asymmetry by always ensuring that units below a slice that are realized at all are hence
+         * always realized in *all* their hierarchies, and it is sufficient for a unit's sibling to be
+         * realized for a unit to be realized too. */
 
         while ((slice = UNIT_DEREF(u->slice))) {
                 Iterator i;
@@ -2343,6 +2351,7 @@ static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
                 void *v;
 
                 HASHMAP_FOREACH_KEY(v, m, slice->dependencies[UNIT_BEFORE], i) {
+
                         /* Skip units that have a dependency on the slice but aren't actually in it. */
                         if (UNIT_DEREF(m->slice) != slice)
                                 continue;
@@ -2351,6 +2360,11 @@ static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
                         if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m)))
                                 continue;
 
+                        /* We only enqueue siblings if they were realized once at least, in the main
+                         * hierarchy. */
+                        if (!m->cgroup_realized)
+                                continue;
+
                         /* If the unit doesn't need any new controllers and has current ones realized, it
                          * doesn't need any changes. */
                         if (unit_has_mask_realized(m,
@@ -2648,6 +2662,7 @@ void unit_add_to_cgroup_empty_queue(Unit *u) {
         /* Let's verify that the cgroup is really empty */
         if (!u->cgroup_path)
                 return;
+
         r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
         if (r < 0) {
                 log_unit_debug_errno(u, r, "Failed to determine whether cgroup %s is empty: %m", u->cgroup_path);