summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-04-28 21:17:35 +0200
committerLennart Poettering <lennart@poettering.net>2015-04-28 21:34:23 +0200
commit9b420b3cfb8b93daf50e4cdbc92b05f2209ef893 (patch)
tree0077cd838eeb972c8c33071a85c17e49c02d2eb2
parentfe506d569d82467f31862c2ed82ef35f88854149 (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.c20
-rw-r--r--src/machine/machine.h2
-rw-r--r--src/machine/machined-dbus.c55
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) {