1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-19 14:04:03 +03:00

machined: rework state tracking logic for machines

This splits up the stopping logic for machines into two steps: first on
machine_stop() we begin with the shutdown of a machine by queuing the
stop method call for it. Then, in machine_finalize() we actually remove
the rest of its runtime context. This mimics closely how sessions are
handled in logind.

This also reworks the GC logic to strictly check the current state of
the machine unit, rather than shortcutting a few cases, like for example
assuming that UnitRemoved really means a machine is gone (which it isn't
since Reloading might trigger it, see #376).

Fixes #376.
This commit is contained in:
Lennart Poettering 2015-08-06 16:50:54 +03:00
parent e5a840c93a
commit 49f3fffd94
4 changed files with 36 additions and 47 deletions

View File

@ -419,7 +419,19 @@ static int machine_stop_scope(Machine *m) {
}
int machine_stop(Machine *m) {
int r = 0, k;
int r;
assert(m);
r = machine_stop_scope(m);
m->stopping = true;
machine_save(m);
return r;
}
int machine_finalize(Machine *m) {
assert(m);
if (m->started)
@ -430,20 +442,15 @@ int machine_stop(Machine *m) {
LOG_MESSAGE("Machine %s terminated.", m->name),
NULL);
/* Kill cgroup */
k = machine_stop_scope(m);
if (k < 0)
r = k;
machine_unlink(m);
machine_add_to_gc_queue(m);
if (m->started)
if (m->started) {
machine_send_signal(m, false);
m->started = false;
}
return r;
return 0;
}
bool machine_check_gc(Machine *m, bool drop_not_started) {
@ -474,8 +481,11 @@ void machine_add_to_gc_queue(Machine *m) {
MachineState machine_get_state(Machine *s) {
assert(s);
if (s->stopping)
return MACHINE_CLOSING;
if (s->scope_job)
return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
return MACHINE_OPENING;
return MACHINE_RUNNING;
}

View File

@ -82,6 +82,7 @@ struct Machine {
bool in_gc_queue:1;
bool started:1;
bool stopping:1;
sd_bus_message *create_message;
@ -100,6 +101,7 @@ bool machine_check_gc(Machine *m, bool drop_not_started);
void machine_add_to_gc_queue(Machine *m);
int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error);
int machine_stop(Machine *m);
int machine_finalize(Machine *m);
int machine_save(Machine *m);
int machine_load(Machine *m);
int machine_kill(Machine *m, KillWho who, int signo);

View File

@ -1136,7 +1136,8 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
machine_send_create_reply(machine, &e);
}
} else
}
machine_save(machine);
}
@ -1146,7 +1147,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *unit = NULL;
const char *path, *interface;
const char *path;
Manager *m = userdata;
Machine *machine;
int r;
@ -1170,36 +1171,6 @@ int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_err
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;
}
@ -1223,9 +1194,7 @@ int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *er
if (!machine)
return 0;
machine_release_unit(machine);
machine_add_to_gc_queue(machine);
return 0;
}

View File

@ -247,8 +247,16 @@ void manager_gc(Manager *m, bool drop_not_started) {
LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
machine->in_gc_queue = false;
if (!machine_check_gc(machine, drop_not_started)) {
/* First, if we are not closing yet, initiate stopping */
if (!machine_check_gc(machine, drop_not_started) &&
machine_get_state(machine) != MACHINE_CLOSING)
machine_stop(machine);
/* Now, the stop stop probably made this referenced
* again, but if it didn't, then it's time to let it
* go entirely. */
if (!machine_check_gc(machine, drop_not_started)) {
machine_finalize(machine);
machine_free(machine);
}
}