diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-04-28 21:17:35 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-04-28 21:34:23 +0200 |
commit | 9b420b3cfb8b93daf50e4cdbc92b05f2209ef893 (patch) | |
tree | 0077cd838eeb972c8c33071a85c17e49c02d2eb2 | |
parent | fe506d569d82467f31862c2ed82ef35f88854149 (diff) |
machined: make sure to track machine unit states properly
If a unit is stopped for a moment, we need to invalidate our knowledge
of it, otherwise we might be confused by automatic restarts
This makes reboots for nspawn containers run as service work correctly.
https://bugs.freedesktop.org/show_bug.cgi?id=87428
-rw-r--r-- | src/machine/machine.c | 20 | ||||
-rw-r--r-- | src/machine/machine.h | 2 | ||||
-rw-r--r-- | src/machine/machined-dbus.c | 55 |
3 files changed, 62 insertions, 15 deletions
diff --git a/src/machine/machine.c b/src/machine/machine.c index dd073addec..05fc4f849f 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -80,17 +80,14 @@ void machine_free(Machine *m) { if (m->in_gc_queue) LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m); - if (m->unit) { - hashmap_remove(m->manager->machine_units, m->unit); - free(m->unit); - } + machine_release_unit(m); free(m->scope_job); - hashmap_remove(m->manager->machines, m->name); + (void) hashmap_remove(m->manager->machines, m->name); if (m->leader > 0) - hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m); + (void) hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m); sd_bus_message_unref(m->create_message); @@ -526,6 +523,17 @@ MachineOperation *machine_operation_unref(MachineOperation *o) { return NULL; } +void machine_release_unit(Machine *m) { + assert(m); + + if (!m->unit) + return; + + (void) hashmap_remove(m->manager->machine_units, m->unit); + free(m->unit); + m->unit = NULL; +} + static const char* const machine_class_table[_MACHINE_CLASS_MAX] = { [MACHINE_CONTAINER] = "container", [MACHINE_VM] = "vm" diff --git a/src/machine/machine.h b/src/machine/machine.h index 7b27aa27e0..bbe5217f65 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -105,6 +105,8 @@ int machine_save(Machine *m); int machine_load(Machine *m); int machine_kill(Machine *m, KillWho who, int signo); +void machine_release_unit(Machine *m); + MachineState machine_get_state(Machine *u); MachineOperation *machine_operation_unref(MachineOperation *o); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 066a8da918..76109700a3 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -24,6 +24,7 @@ #include <unistd.h> #include "sd-id128.h" +#include "strv.h" #include "path-util.h" #include "unit-name.h" #include "bus-util.h" @@ -923,9 +924,9 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ char *unit = NULL; + const char *path, *interface; Manager *m = userdata; Machine *machine; - const char *path; int r; assert(bus); @@ -939,13 +940,46 @@ int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdat r = unit_name_from_dbus_path(path, &unit); if (r == -EINVAL) /* not for a unit */ return 0; - if (r < 0) - return r; + if (r < 0){ + log_oom(); + return 0; + } machine = hashmap_get(m->machine_units, unit); - if (machine) - machine_add_to_gc_queue(machine); + if (!machine) + return 0; + + r = sd_bus_message_read(message, "s", &interface); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } + + if (streq(interface, "org.freedesktop.systemd1.Unit")) { + struct properties { + char *active_state; + char *sub_state; + } properties = {}; + const struct bus_properties_map map[] = { + { "ActiveState", "s", NULL, offsetof(struct properties, active_state) }, + { "SubState", "s", NULL, offsetof(struct properties, sub_state) }, + {} + }; + + r = bus_message_map_properties_changed(message, map, &properties); + if (r < 0) + bus_log_parse_error(r); + else if (streq_ptr(properties.active_state, "inactive") || + streq_ptr(properties.active_state, "failed") || + streq_ptr(properties.sub_state, "auto-restart")) + machine_release_unit(machine); + + free(properties.active_state); + free(properties.sub_state); + } + + machine_add_to_gc_queue(machine); return 0; } @@ -962,12 +996,15 @@ int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_ r = sd_bus_message_read(message, "so", &unit, &path); if (r < 0) { bus_log_parse_error(r); - return r; + return 0; } machine = hashmap_get(m->machine_units, unit); - if (machine) - machine_add_to_gc_queue(machine); + if (!machine) + return 0; + + machine_release_unit(machine); + machine_add_to_gc_queue(machine); return 0; } @@ -1190,7 +1227,7 @@ int manager_unit_is_active(Manager *manager, const char *unit) { if (r < 0) return -EINVAL; - return !streq(state, "inactive") && !streq(state, "failed"); + return !STR_IN_SET(state, "inactive", "failed"); } int manager_job_is_active(Manager *manager, const char *path) { |