03222e
From fbdc87679cc4f3c9fc3653636e94be20f06d18e4 Mon Sep 17 00:00:00 2001
03222e
From: Anita Zhang <the.anitazha@gmail.com>
03222e
Date: Tue, 9 Nov 2021 15:26:28 -0800
03222e
Subject: [PATCH] core: replace slice dependencies as they get added
03222e
03222e
Defines a "UNIT_DEPENDENCY_SLICE_PROPERTY" UnitDependencyMask type that
03222e
is used when adding slices to the dependencies hashmap. This type is
03222e
used to remove slice dependencies when they get overridden by new ones.
03222e
03222e
Fixes #20182
03222e
---
03222e
 src/core/dbus-unit.c      |  2 +-
03222e
 src/core/load-fragment.c  |  2 +-
03222e
 src/core/unit-serialize.c |  1 +
03222e
 src/core/unit.c           | 10 +++++++---
03222e
 src/core/unit.h           |  7 +++++--
03222e
 src/test/test-engine.c    | 31 ++++++++++++++++++++++++++++++-
03222e
 6 files changed, 45 insertions(+), 8 deletions(-)
03222e
03222e
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
03222e
index fe320f1b05a8..d4ec789a7c11 100644
03222e
--- a/src/core/dbus-unit.c
03222e
+++ b/src/core/dbus-unit.c
03222e
@@ -2273,7 +2273,7 @@ static int bus_unit_set_transient_property(
03222e
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
03222e
 
03222e
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
03222e
-                        r = unit_set_slice(u, slice, UNIT_DEPENDENCY_FILE);
03222e
+                        r = unit_set_slice(u, slice);
03222e
                         if (r < 0)
03222e
                                 return r;
03222e
 
03222e
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
03222e
index 62cadaf2286f..830048ae1915 100644
03222e
--- a/src/core/load-fragment.c
03222e
+++ b/src/core/load-fragment.c
03222e
@@ -3792,7 +3792,7 @@ int config_parse_unit_slice(
03222e
                 return 0;
03222e
         }
03222e
 
03222e
-        r = unit_set_slice(u, slice, UNIT_DEPENDENCY_FILE);
03222e
+        r = unit_set_slice(u, slice);
03222e
         if (r < 0) {
03222e
                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to assign slice %s to unit %s, ignoring: %m", slice->id, u->id);
03222e
                 return 0;
03222e
diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c
03222e
index 3458d7017bd5..7d2e6bc130de 100644
03222e
--- a/src/core/unit-serialize.c
03222e
+++ b/src/core/unit-serialize.c
03222e
@@ -593,6 +593,7 @@ static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependency
03222e
                 { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
03222e
                 { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT,  "mountinfo-default"  },
03222e
                 { UNIT_DEPENDENCY_PROC_SWAP,          "proc-swap"          },
03222e
+                { UNIT_DEPENDENCY_SLICE_PROPERTY,     "slice-property"     },
03222e
         };
03222e
 
03222e
         assert(f);
03222e
diff --git a/src/core/unit.c b/src/core/unit.c
03222e
index 4c55827a6511..a3bca43566e0 100644
03222e
--- a/src/core/unit.c
03222e
+++ b/src/core/unit.c
03222e
@@ -3284,7 +3284,7 @@ int unit_set_invocation_id(Unit *u, sd_id128_t id) {
03222e
         return r;
03222e
 }
03222e
 
03222e
-int unit_set_slice(Unit *u, Unit *slice, UnitDependencyMask mask) {
03222e
+int unit_set_slice(Unit *u, Unit *slice) {
03222e
         int r;
03222e
 
03222e
         assert(u);
03222e
@@ -3317,7 +3317,11 @@ int unit_set_slice(Unit *u, Unit *slice, UnitDependencyMask mask) {
03222e
         if (UNIT_GET_SLICE(u) && u->cgroup_realized)
03222e
                 return -EBUSY;
03222e
 
03222e
-        r = unit_add_dependency(u, UNIT_IN_SLICE, slice, true, mask);
03222e
+        /* Remove any slices assigned prior; we should only have one UNIT_IN_SLICE dependency */
03222e
+        if (UNIT_GET_SLICE(u))
03222e
+                unit_remove_dependencies(u, UNIT_DEPENDENCY_SLICE_PROPERTY);
03222e
+
03222e
+        r = unit_add_dependency(u, UNIT_IN_SLICE, slice, true, UNIT_DEPENDENCY_SLICE_PROPERTY);
03222e
         if (r < 0)
03222e
                 return r;
03222e
 
03222e
@@ -3373,7 +3377,7 @@ int unit_set_default_slice(Unit *u) {
03222e
         if (r < 0)
03222e
                 return r;
03222e
 
03222e
-        return unit_set_slice(u, slice, UNIT_DEPENDENCY_FILE);
03222e
+        return unit_set_slice(u, slice);
03222e
 }
03222e
 
03222e
 const char *unit_slice_name(Unit *u) {
03222e
diff --git a/src/core/unit.h b/src/core/unit.h
03222e
index 0dd6a9591d96..ba12fe4ac1ef 100644
03222e
--- a/src/core/unit.h
03222e
+++ b/src/core/unit.h
03222e
@@ -89,7 +89,10 @@ typedef enum UnitDependencyMask {
03222e
         /* A dependency created because of data read from /proc/swaps and no other configuration source */
03222e
         UNIT_DEPENDENCY_PROC_SWAP          = 1 << 7,
03222e
 
03222e
-        _UNIT_DEPENDENCY_MASK_FULL         = (1 << 8) - 1,
03222e
+        /* A dependency for units in slices assigned by directly setting Slice= */
03222e
+        UNIT_DEPENDENCY_SLICE_PROPERTY     = 1 << 8,
03222e
+
03222e
+        _UNIT_DEPENDENCY_MASK_FULL         = (1 << 9) - 1,
03222e
 } UnitDependencyMask;
03222e
 
03222e
 /* The Unit's dependencies[] hashmaps use this structure as value. It has the same size as a void pointer, and thus can
03222e
@@ -782,7 +785,7 @@ Unit *unit_follow_merge(Unit *u) _pure_;
03222e
 int unit_load_fragment_and_dropin(Unit *u, bool fragment_required);
03222e
 int unit_load(Unit *unit);
03222e
 
03222e
-int unit_set_slice(Unit *u, Unit *slice, UnitDependencyMask mask);
03222e
+int unit_set_slice(Unit *u, Unit *slice);
03222e
 int unit_set_default_slice(Unit *u);
03222e
 
03222e
 const char *unit_description(Unit *u) _pure_;
03222e
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
03222e
index 880af36fb523..673c66561240 100644
03222e
--- a/src/test/test-engine.c
03222e
+++ b/src/test/test-engine.c
03222e
@@ -8,6 +8,7 @@
03222e
 #include "manager-dump.h"
03222e
 #include "rm-rf.h"
03222e
 #include "service.h"
03222e
+#include "slice.h"
03222e
 #include "special.h"
03222e
 #include "strv.h"
03222e
 #include "tests.h"
03222e
@@ -75,7 +76,8 @@ int main(int argc, char *argv[]) {
03222e
         _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
03222e
         _cleanup_(manager_freep) Manager *m = NULL;
03222e
         Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL,
03222e
-                *h = NULL, *i = NULL, *a_conj = NULL, *unit_with_multiple_dashes = NULL, *stub = NULL;
03222e
+                *h = NULL, *i = NULL, *a_conj = NULL, *unit_with_multiple_dashes = NULL, *stub = NULL,
03222e
+                *tomato = NULL, *sauce = NULL, *fruit = NULL, *zupa = NULL;
03222e
         Job *j;
03222e
         int r;
03222e
 
03222e
@@ -260,5 +262,32 @@ int main(int argc, char *argv[]) {
03222e
 
03222e
         verify_dependency_atoms();
03222e
 
03222e
+        /* Test adding multiple Slice= dependencies; only the last should remain */
03222e
+        assert_se(unit_new_for_name(m, sizeof(Service), "tomato.service", &tomato) >= 0);
03222e
+        assert_se(unit_new_for_name(m, sizeof(Slice), "sauce.slice", &sauce) >= 0);
03222e
+        assert_se(unit_new_for_name(m, sizeof(Slice), "fruit.slice", &fruit) >= 0);
03222e
+        assert_se(unit_new_for_name(m, sizeof(Slice), "zupa.slice", &zupa) >= 0);
03222e
+
03222e
+        unit_set_slice(tomato, sauce);
03222e
+        unit_set_slice(tomato, fruit);
03222e
+        unit_set_slice(tomato, zupa);
03222e
+
03222e
+        assert_se(UNIT_GET_SLICE(tomato) == zupa);
03222e
+        assert_se(!unit_has_dependency(tomato, UNIT_ATOM_IN_SLICE, sauce));
03222e
+        assert_se(!unit_has_dependency(tomato, UNIT_ATOM_IN_SLICE, fruit));
03222e
+        assert_se(unit_has_dependency(tomato, UNIT_ATOM_IN_SLICE, zupa));
03222e
+
03222e
+        assert_se(!unit_has_dependency(tomato, UNIT_ATOM_REFERENCES, sauce));
03222e
+        assert_se(!unit_has_dependency(tomato, UNIT_ATOM_REFERENCES, fruit));
03222e
+        assert_se(unit_has_dependency(tomato, UNIT_ATOM_REFERENCES, zupa));
03222e
+
03222e
+        assert_se(!unit_has_dependency(sauce, UNIT_ATOM_SLICE_OF, tomato));
03222e
+        assert_se(!unit_has_dependency(fruit, UNIT_ATOM_SLICE_OF, tomato));
03222e
+        assert_se(unit_has_dependency(zupa, UNIT_ATOM_SLICE_OF, tomato));
03222e
+
03222e
+        assert_se(!unit_has_dependency(sauce, UNIT_ATOM_REFERENCED_BY, tomato));
03222e
+        assert_se(!unit_has_dependency(fruit, UNIT_ATOM_REFERENCED_BY, tomato));
03222e
+        assert_se(unit_has_dependency(zupa, UNIT_ATOM_REFERENCED_BY, tomato));
03222e
+
03222e
         return 0;
03222e
 }