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().
This commit is contained in:
Lennart Poettering 2018-06-05 18:26:45 +02:00
parent 244f805549
commit 04eb582acc
5 changed files with 37 additions and 16 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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,
};

View File

@ -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 = {

View File

@ -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. */