core: add a new unit method "catchup()"

This is very similar to the existing unit method coldplug() but is
called a bit later. The idea is that that coldplug() restores the unit
state from before any prior reload/restart, i.e. puts the deserialized
state in effect. The catchup() call is then called a bit later, to
catch up with the system state for which we missed notifications while
we were reloading. This is only really useful for mount, swap and device
mount points were we should be careful to generate all missing unit
state change events (i.e. call unit_notify() appropriately) for
everything that happened while we were reloading.
This commit is contained in:
Lennart Poettering 2018-06-05 16:53:22 +02:00
parent 62b0cbb358
commit f0831ed2a0
3 changed files with 47 additions and 11 deletions

View File

@ -1350,7 +1350,9 @@ static void manager_coldplug(Manager *m) {
assert(m);
/* Then, let's set up their initial state. */
log_debug("Invoking unit coldplug() handlers…");
/* Let's place the units back into their deserialized state */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
/* ignore aliases */
@ -1363,6 +1365,26 @@ static void manager_coldplug(Manager *m) {
}
}
static void manager_catchup(Manager *m) {
Iterator i;
Unit *u;
char *k;
assert(m);
log_debug("Invoking unit catchup() handlers…");
/* Let's catch up on any state changes that happened while we were reloading/reexecing */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
/* ignore aliases */
if (u->id != k)
continue;
unit_catchup(u);
}
}
static void manager_build_unit_path_cache(Manager *m) {
char **i;
int r;
@ -1602,6 +1624,9 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->send_reloading_done = true;
}
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);
return 0;
}
@ -3414,6 +3439,9 @@ int manager_reload(Manager *m) {
manager_recheck_journal(m);
manager_recheck_dbus(m);
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);
/* Sync current state of bus names with our set of listening units */
q = manager_enqueue_sync_bus_names(m);
if (q < 0 && r >= 0)

View File

@ -2298,7 +2298,6 @@ static void unit_update_on_console(Unit *u) {
manager_ref_console(u->manager);
else
manager_unref_console(u->manager);
}
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags) {
@ -3730,8 +3729,7 @@ int unit_coldplug(Unit *u) {
assert(u);
/* Make sure we don't enter a loop, when coldplugging
* recursively. */
/* Make sure we don't enter a loop, when coldplugging recursively. */
if (u->coldplugged)
return 0;
@ -3759,6 +3757,13 @@ int unit_coldplug(Unit *u) {
return r;
}
void unit_catchup(Unit *u) {
assert(u);
if (UNIT_VTABLE(u)->catchup)
UNIT_VTABLE(u)->catchup(u);
}
static bool fragment_mtime_newer(const char *path, usec_t mtime, bool path_masked) {
struct stat st;

View File

@ -437,10 +437,14 @@ typedef struct UnitVTable {
* UNIT_STUB if no configuration could be found. */
int (*load)(Unit *u);
/* If a lot of units got created via enumerate(), this is
* where to actually set the state and call unit_notify(). */
/* During deserialization we only record the intended state to return to. With coldplug() we actually put the
* deserialized state in effect. This is where unit_notify() should be called to start things up. */
int (*coldplug)(Unit *u);
/* This is called shortly after all units' coldplug() call was invoked. It's supposed to catch up state changes
* we missed so far (for example because they took place while we were reloading/reexecing) */
void (*catchup)(Unit *u);
void (*dump)(Unit *u, FILE *f, const char *prefix);
int (*start)(Unit *u);
@ -531,11 +535,9 @@ typedef struct UnitVTable {
/* Returns true if the unit currently needs access to the console */
bool (*needs_console)(Unit *u);
/* This is called for each unit type and should be used to
* enumerate existing devices 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. */
/* 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. */
void (*enumerate)(Manager *m);
/* Type specific cleanups. */
@ -687,6 +689,7 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *v
int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency d, UnitDependencyMask mask);
int unit_coldplug(Unit *u);
void unit_catchup(Unit *u);
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t);