From 04eb582acc203eab0bc5c2cc5e13986f16e09df0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 5 Jun 2018 18:26:45 +0200 Subject: [PATCH] core: enumerate perpetual units in a separate per-unit-type method Previously the enumerate() callback defined for each unit type would do two things: 1. It would create perpetual units (i.e. -.slice, system.slice, -.mount and init.scope) 2. It would enumerate units from /proc/self/mountinfo, /proc/swaps and the udev database With this change these two parts are split into two seperate methods: enumerate() now only does #2, while enumerate_perpetual() is responsible for #1. Why make this change? Well, perpetual units should have a slightly different effect that those found through enumeration: as perpetual units should be up unconditionally, perpetually and thus never change state, they should also not pull in deps by their state changing, not even when the state is first set to active. Thus, their state is generally initialized through the per-device coldplug() method in similar fashion to the deserialized state from a previous run would be put into place. OTOH units found through regular enumeration should result in state changes (and thus pull in deps due to state changes), hence their state should be put in effect in the catchup() method instead. Hence, given this difference, let's also separate the functions, so that the rule is: 1. What is created in enumerate_perpetual() should be started in coldplug() 2. What is created in enumerate() should be started in catchup(). --- src/core/manager.c | 22 ++++++++++++++++++++-- src/core/mount.c | 15 ++++++--------- src/core/scope.c | 4 ++-- src/core/slice.c | 4 ++-- src/core/unit.h | 8 +++++++- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index f90cc12910..04e0c6fe3b 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1322,13 +1322,30 @@ Manager* manager_free(Manager *m) { return mfree(m); } +static void manager_enumerate_perpetual(Manager *m) { + UnitType c; + + assert(m); + + /* Let's ask every type to load all units from disk/kernel that it might know */ + for (c = 0; c < _UNIT_TYPE_MAX; c++) { + if (!unit_type_supported(c)) { + log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c)); + continue; + } + + if (unit_vtable[c]->enumerate_perpetual) + unit_vtable[c]->enumerate_perpetual(m); + } +} + + static void manager_enumerate(Manager *m) { UnitType c; assert(m); - /* Let's ask every type to load all units from disk/kernel - * that it might know */ + /* Let's ask every type to load all units from disk/kernel that it might know */ for (c = 0; c < _UNIT_TYPE_MAX; c++) { if (!unit_type_supported(c)) { log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c)); @@ -1562,6 +1579,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { /* First, enumerate what we can from all config files */ dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_START); + manager_enumerate_perpetual(m); manager_enumerate(m); dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_FINISH); diff --git a/src/core/mount.c b/src/core/mount.c index 64115dc21b..dcc44657b2 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1671,7 +1671,7 @@ static int mount_get_timeout(Unit *u, usec_t *timeout) { return 1; } -static int synthesize_root_mount(Manager *m) { +static void mount_enumerate_perpetual(Manager *m) { Unit *u; int r; @@ -1683,8 +1683,10 @@ static int synthesize_root_mount(Manager *m) { u = manager_get_unit(m, SPECIAL_ROOT_MOUNT); if (!u) { r = unit_new_for_name(m, sizeof(Mount), SPECIAL_ROOT_MOUNT, &u); - if (r < 0) - return log_error_errno(r, "Failed to allocate the special " SPECIAL_ROOT_MOUNT " unit: %m"); + if (r < 0) { + log_error_errno(r, "Failed to allocate the special " SPECIAL_ROOT_MOUNT " unit: %m"); + return; + } } u->perpetual = true; @@ -1692,8 +1694,6 @@ static int synthesize_root_mount(Manager *m) { unit_add_to_load_queue(u); unit_add_to_dbus_queue(u); - - return 0; } static bool mount_is_mounted(Mount *m) { @@ -1707,10 +1707,6 @@ static void mount_enumerate(Manager *m) { assert(m); - r = synthesize_root_mount(m); - if (r < 0) - goto fail; - mnt_init_debug(0); if (!m->mount_monitor) { @@ -2001,6 +1997,7 @@ const UnitVTable mount_vtable = { .can_transient = true, + .enumerate_perpetual = mount_enumerate_perpetual, .enumerate = mount_enumerate, .shutdown = mount_shutdown, diff --git a/src/core/scope.c b/src/core/scope.c index 5db3296044..27ff545313 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -540,7 +540,7 @@ _pure_ static const char *scope_sub_state_to_string(Unit *u) { return scope_state_to_string(SCOPE(u)->state); } -static void scope_enumerate(Manager *m) { +static void scope_enumerate_perpetual(Manager *m) { Unit *u; int r; @@ -622,5 +622,5 @@ const UnitVTable scope_vtable = { .bus_set_property = bus_scope_set_property, .bus_commit_properties = bus_scope_commit_properties, - .enumerate = scope_enumerate, + .enumerate_perpetual = scope_enumerate_perpetual, }; diff --git a/src/core/slice.c b/src/core/slice.c index 71614e4b89..e8a7c9a585 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -326,7 +326,7 @@ static int slice_make_perpetual(Manager *m, const char *name, Unit **ret) { return 0; } -static void slice_enumerate(Manager *m) { +static void slice_enumerate_perpetual(Manager *m) { Unit *u; int r; @@ -383,7 +383,7 @@ const UnitVTable slice_vtable = { .bus_set_property = bus_slice_set_property, .bus_commit_properties = bus_slice_commit_properties, - .enumerate = slice_enumerate, + .enumerate_perpetual = slice_enumerate_perpetual, .status_message_formats = { .finished_start_job = { diff --git a/src/core/unit.h b/src/core/unit.h index 9d9d94dd4e..cff3825ddc 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -535,9 +535,15 @@ typedef struct UnitVTable { /* Returns true if the unit currently needs access to the console */ bool (*needs_console)(Unit *u); + /* Like the enumerate() callback further down, but only enumerates the perpetual units, i.e. all units that + * unconditionally exist and are always active. The main reason to keep both enumeration functions separate is + * philosophical: the state of perpetual units should be put in place by coldplug(), while the state of those + * discovered through regular enumeration should be put in place by catchup(), see below. */ + void (*enumerate_perpetual)(Manager *m); + /* This is called for each unit type and should be used to enumerate units already existing in the system * internally and load them. However, everything that is loaded here should still stay in inactive state. It is - * the job of the coldplug() call above to put the units into the initial state. */ + * the job of the catchup() call above to put the units into the discovered state. */ void (*enumerate)(Manager *m); /* Type specific cleanups. */