|
|
aed857 |
From 36226a9afe96bdffce9d0697be020f2ca9d7fe6f Mon Sep 17 00:00:00 2001
|
|
|
aed857 |
From: Michal Sekletar <msekletar@users.noreply.github.com>
|
|
|
aed857 |
Date: Fri, 23 Mar 2018 15:28:06 +0100
|
|
|
aed857 |
Subject: [PATCH] core: delay adding target dependencies until all units are
|
|
|
aed857 |
loaded and aliases resolved (#8381)
|
|
|
aed857 |
|
|
|
aed857 |
Currently we add target dependencies while we are loading units. This
|
|
|
aed857 |
can create ordering loops even if configuration doesn't contain any
|
|
|
aed857 |
loop. Take for example following configuration,
|
|
|
aed857 |
|
|
|
aed857 |
$ systemctl get-default
|
|
|
aed857 |
multi-user.target
|
|
|
aed857 |
|
|
|
aed857 |
$ cat /etc/systemd/system/test.service
|
|
|
aed857 |
[Unit]
|
|
|
aed857 |
After=default.target
|
|
|
aed857 |
|
|
|
aed857 |
[Service]
|
|
|
aed857 |
ExecStart=/bin/true
|
|
|
aed857 |
|
|
|
aed857 |
[Install]
|
|
|
aed857 |
WantedBy=multi-user.target
|
|
|
aed857 |
|
|
|
aed857 |
If we encounter such unit file early during manager start-up (e.g. load
|
|
|
aed857 |
queue is dispatched while enumerating devices due to SYSTEMD_WANTS in
|
|
|
aed857 |
udev rules) we would add stub unit default.target and we order it Before
|
|
|
aed857 |
test.service. At the same time we add implicit Before to
|
|
|
aed857 |
multi-user.target. Later we merge two units and we create ordering cycle
|
|
|
aed857 |
in the process.
|
|
|
aed857 |
|
|
|
aed857 |
To fix the issue we will now never add any target dependencies until we
|
|
|
aed857 |
loaded all the unit files and resolved all the aliases.
|
|
|
aed857 |
|
|
|
aed857 |
(cherry picked from commit 19496554e23ea4861ce780430052dcf86a2ffcba)
|
|
|
aed857 |
|
|
|
aed857 |
Resolves: #1368856
|
|
|
aed857 |
---
|
|
|
aed857 |
src/core/manager.c | 40 ++++++++++++++++++++++++++++++++++++++++
|
|
|
aed857 |
src/core/manager.h | 3 +++
|
|
|
aed857 |
src/core/unit.c | 46 ++++++++++++++++------------------------------
|
|
|
aed857 |
src/core/unit.h | 5 +++++
|
|
|
aed857 |
4 files changed, 64 insertions(+), 30 deletions(-)
|
|
|
aed857 |
|
|
|
aed857 |
diff --git a/src/core/manager.c b/src/core/manager.c
|
|
|
aed857 |
index 9c406bb5b..0466e4bb8 100644
|
|
|
aed857 |
--- a/src/core/manager.c
|
|
|
aed857 |
+++ b/src/core/manager.c
|
|
|
aed857 |
@@ -1373,6 +1373,41 @@ Unit *manager_get_unit(Manager *m, const char *name) {
|
|
|
aed857 |
return hashmap_get(m->units, name);
|
|
|
aed857 |
}
|
|
|
aed857 |
|
|
|
aed857 |
+static int manager_dispatch_target_deps_queue(Manager *m) {
|
|
|
aed857 |
+ Unit *u;
|
|
|
aed857 |
+ unsigned k;
|
|
|
aed857 |
+ int r = 0;
|
|
|
aed857 |
+
|
|
|
aed857 |
+ static const UnitDependency deps[] = {
|
|
|
aed857 |
+ UNIT_REQUIRED_BY,
|
|
|
aed857 |
+ UNIT_REQUIRED_BY_OVERRIDABLE,
|
|
|
aed857 |
+ UNIT_WANTED_BY,
|
|
|
aed857 |
+ UNIT_BOUND_BY
|
|
|
aed857 |
+ };
|
|
|
aed857 |
+
|
|
|
aed857 |
+ assert(m);
|
|
|
aed857 |
+
|
|
|
aed857 |
+ while ((u = m->target_deps_queue)) {
|
|
|
aed857 |
+ assert(u->in_target_deps_queue);
|
|
|
aed857 |
+
|
|
|
aed857 |
+ LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
|
|
|
aed857 |
+ u->in_target_deps_queue = false;
|
|
|
aed857 |
+
|
|
|
aed857 |
+ for (k = 0; k < ELEMENTSOF(deps); k++) {
|
|
|
aed857 |
+ Unit *target;
|
|
|
aed857 |
+ Iterator i;
|
|
|
aed857 |
+
|
|
|
aed857 |
+ SET_FOREACH(target, u->dependencies[deps[k]], i) {
|
|
|
aed857 |
+ r = unit_add_default_target_dependency(u, target);
|
|
|
aed857 |
+ if (r < 0)
|
|
|
aed857 |
+ return r;
|
|
|
aed857 |
+ }
|
|
|
aed857 |
+ }
|
|
|
aed857 |
+ }
|
|
|
aed857 |
+
|
|
|
aed857 |
+ return r;
|
|
|
aed857 |
+}
|
|
|
aed857 |
+
|
|
|
aed857 |
unsigned manager_dispatch_load_queue(Manager *m) {
|
|
|
aed857 |
Unit *u;
|
|
|
aed857 |
unsigned n = 0;
|
|
|
aed857 |
@@ -1396,6 +1431,11 @@ unsigned manager_dispatch_load_queue(Manager *m) {
|
|
|
aed857 |
}
|
|
|
aed857 |
|
|
|
aed857 |
m->dispatching_load_queue = false;
|
|
|
aed857 |
+
|
|
|
aed857 |
+ /* Dispatch the units waiting for their target dependencies to be added now, as all targets that we know about
|
|
|
aed857 |
+ * should be loaded and have aliases resolved */
|
|
|
aed857 |
+ (void) manager_dispatch_target_deps_queue(m);
|
|
|
aed857 |
+
|
|
|
aed857 |
return n;
|
|
|
aed857 |
}
|
|
|
aed857 |
|
|
|
aed857 |
diff --git a/src/core/manager.h b/src/core/manager.h
|
|
|
aed857 |
index 90d2d982e..b0e4cad1f 100644
|
|
|
aed857 |
--- a/src/core/manager.h
|
|
|
aed857 |
+++ b/src/core/manager.h
|
|
|
aed857 |
@@ -114,6 +114,9 @@ struct Manager {
|
|
|
aed857 |
/* Units that should be realized */
|
|
|
aed857 |
LIST_HEAD(Unit, cgroup_queue);
|
|
|
aed857 |
|
|
|
aed857 |
+ /* Target units whose default target dependencies haven't been set yet */
|
|
|
aed857 |
+ LIST_HEAD(Unit, target_deps_queue);
|
|
|
aed857 |
+
|
|
|
aed857 |
sd_event *event;
|
|
|
aed857 |
|
|
|
aed857 |
/* We use two hash tables here, since the same PID might be
|
|
|
aed857 |
diff --git a/src/core/unit.c b/src/core/unit.c
|
|
|
aed857 |
index 22d9beed7..cfddce34d 100644
|
|
|
aed857 |
--- a/src/core/unit.c
|
|
|
aed857 |
+++ b/src/core/unit.c
|
|
|
aed857 |
@@ -519,6 +519,9 @@ void unit_free(Unit *u) {
|
|
|
aed857 |
u->manager->n_in_gc_queue--;
|
|
|
aed857 |
}
|
|
|
aed857 |
|
|
|
aed857 |
+ if (u->in_target_deps_queue)
|
|
|
aed857 |
+ LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
|
|
|
aed857 |
+
|
|
|
aed857 |
if (u->in_cgroup_queue)
|
|
|
aed857 |
LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
|
|
|
aed857 |
|
|
|
aed857 |
@@ -1065,6 +1068,18 @@ int unit_load_fragment_and_dropin_optional(Unit *u) {
|
|
|
aed857 |
return 0;
|
|
|
aed857 |
}
|
|
|
aed857 |
|
|
|
aed857 |
+void unit_add_to_target_deps_queue(Unit *u) {
|
|
|
aed857 |
+ Manager *m = u->manager;
|
|
|
aed857 |
+
|
|
|
aed857 |
+ assert(u);
|
|
|
aed857 |
+
|
|
|
aed857 |
+ if (u->in_target_deps_queue)
|
|
|
aed857 |
+ return;
|
|
|
aed857 |
+
|
|
|
aed857 |
+ LIST_PREPEND(target_deps_queue, m->target_deps_queue, u);
|
|
|
aed857 |
+ u->in_target_deps_queue = true;
|
|
|
aed857 |
+}
|
|
|
aed857 |
+
|
|
|
aed857 |
int unit_add_default_target_dependency(Unit *u, Unit *target) {
|
|
|
aed857 |
assert(u);
|
|
|
aed857 |
assert(target);
|
|
|
aed857 |
@@ -1091,32 +1106,6 @@ int unit_add_default_target_dependency(Unit *u, Unit *target) {
|
|
|
aed857 |
return unit_add_dependency(target, UNIT_AFTER, u, true);
|
|
|
aed857 |
}
|
|
|
aed857 |
|
|
|
aed857 |
-static int unit_add_target_dependencies(Unit *u) {
|
|
|
aed857 |
-
|
|
|
aed857 |
- static const UnitDependency deps[] = {
|
|
|
aed857 |
- UNIT_REQUIRED_BY,
|
|
|
aed857 |
- UNIT_REQUIRED_BY_OVERRIDABLE,
|
|
|
aed857 |
- UNIT_WANTED_BY,
|
|
|
aed857 |
- UNIT_BOUND_BY
|
|
|
aed857 |
- };
|
|
|
aed857 |
-
|
|
|
aed857 |
- Unit *target;
|
|
|
aed857 |
- Iterator i;
|
|
|
aed857 |
- unsigned k;
|
|
|
aed857 |
- int r = 0;
|
|
|
aed857 |
-
|
|
|
aed857 |
- assert(u);
|
|
|
aed857 |
-
|
|
|
aed857 |
- for (k = 0; k < ELEMENTSOF(deps); k++)
|
|
|
aed857 |
- SET_FOREACH(target, u->dependencies[deps[k]], i) {
|
|
|
aed857 |
- r = unit_add_default_target_dependency(u, target);
|
|
|
aed857 |
- if (r < 0)
|
|
|
aed857 |
- return r;
|
|
|
aed857 |
- }
|
|
|
aed857 |
-
|
|
|
aed857 |
- return r;
|
|
|
aed857 |
-}
|
|
|
aed857 |
-
|
|
|
aed857 |
static int unit_add_slice_dependencies(Unit *u) {
|
|
|
aed857 |
assert(u);
|
|
|
aed857 |
|
|
|
aed857 |
@@ -1217,10 +1206,7 @@ int unit_load(Unit *u) {
|
|
|
aed857 |
}
|
|
|
aed857 |
|
|
|
aed857 |
if (u->load_state == UNIT_LOADED) {
|
|
|
aed857 |
-
|
|
|
aed857 |
- r = unit_add_target_dependencies(u);
|
|
|
aed857 |
- if (r < 0)
|
|
|
aed857 |
- goto fail;
|
|
|
aed857 |
+ unit_add_to_target_deps_queue(u);
|
|
|
aed857 |
|
|
|
aed857 |
r = unit_add_slice_dependencies(u);
|
|
|
aed857 |
if (r < 0)
|
|
|
aed857 |
diff --git a/src/core/unit.h b/src/core/unit.h
|
|
|
aed857 |
index 480e2e95f..dfec9cea0 100644
|
|
|
aed857 |
--- a/src/core/unit.h
|
|
|
aed857 |
+++ b/src/core/unit.h
|
|
|
aed857 |
@@ -162,6 +162,9 @@ struct Unit {
|
|
|
aed857 |
/* CGroup realize members queue */
|
|
|
aed857 |
LIST_FIELDS(Unit, cgroup_queue);
|
|
|
aed857 |
|
|
|
aed857 |
+ /* Target dependencies queue */
|
|
|
aed857 |
+ LIST_FIELDS(Unit, target_deps_queue);
|
|
|
aed857 |
+
|
|
|
aed857 |
/* PIDs we keep an eye on. Note that a unit might have many
|
|
|
aed857 |
* more, but these are the ones we care enough about to
|
|
|
aed857 |
* process SIGCHLD for */
|
|
|
aed857 |
@@ -228,6 +231,7 @@ struct Unit {
|
|
|
aed857 |
bool in_cleanup_queue:1;
|
|
|
aed857 |
bool in_gc_queue:1;
|
|
|
aed857 |
bool in_cgroup_queue:1;
|
|
|
aed857 |
+ bool in_target_deps_queue:1;
|
|
|
aed857 |
|
|
|
aed857 |
bool sent_dbus_new_signal:1;
|
|
|
aed857 |
|
|
|
aed857 |
@@ -498,6 +502,7 @@ void unit_add_to_load_queue(Unit *u);
|
|
|
aed857 |
void unit_add_to_dbus_queue(Unit *u);
|
|
|
aed857 |
void unit_add_to_cleanup_queue(Unit *u);
|
|
|
aed857 |
void unit_add_to_gc_queue(Unit *u);
|
|
|
aed857 |
+void unit_add_to_target_deps_queue(Unit *u);
|
|
|
aed857 |
|
|
|
aed857 |
int unit_merge(Unit *u, Unit *other);
|
|
|
aed857 |
int unit_merge_by_name(Unit *u, const char *other);
|