diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-05-02 16:51:45 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-05-02 16:51:45 +0200 |
commit | fae03ed32a77934a5c39ed8e338ec6c7a75857a0 (patch) | |
tree | 3b243e1410f2a08fd746f0c952d755af0a2a42a1 /src/core | |
parent | d14e3a0de913cd5ef52693a9466129820322cff3 (diff) |
automount: rework propagation between automount and mount units
Port the progagation logic to the generic Unit->trigger_notify() callback logic
in the unit vtable, that is called for a unit not only when the triggered unit
of it changes state but also when a job for that unit finishes. This, firstly
allows us to make the code a bit cleaner and more generic, but more
importantly, allows us to notice correctly when a mount job fails, and
propagate that back to autofs client processes.
Fixes: #2181
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/automount.c | 65 | ||||
-rw-r--r-- | src/core/automount.h | 3 | ||||
-rw-r--r-- | src/core/mount.c | 19 |
3 files changed, 42 insertions, 45 deletions
diff --git a/src/core/automount.c b/src/core/automount.c index d2386d04f7..5577c64255 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -464,43 +464,57 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) { static int automount_start_expire(Automount *a); -int automount_update_mount(Automount *a, MountState old_state, MountState state) { +static void automount_trigger_notify(Unit *u, Unit *other) { + Automount *a = AUTOMOUNT(u); int r; assert(a); + assert(other); + + /* Filter out invocations with bogus state */ + if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT) + return; + + /* Don't propagate state changes from the mount if we are already down */ + if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING)) + return; - log_unit_debug(UNIT(a), "Got notified about mount unit state change %s → %s", mount_state_to_string(old_state), mount_state_to_string(state)); + /* Propagate start limit hit state */ + if (other->start_limit_hit) { + automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT); + return; + } - switch (state) { + /* Don't propagate anything if there's still a job queued */ + if (other->job) + return; + + /* The mount is successfully established */ + if (IN_SET(MOUNT(other)->state, MOUNT_MOUNTED, MOUNT_REMOUNTING)) { + (void) automount_send_ready(a, a->tokens, 0); - case MOUNT_MOUNTED: - case MOUNT_REMOUNTING: - automount_send_ready(a, a->tokens, 0); r = automount_start_expire(a); if (r < 0) log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m"); - break; - case MOUNT_DEAD: - case MOUNT_UNMOUNTING: - case MOUNT_MOUNTING_SIGTERM: - case MOUNT_MOUNTING_SIGKILL: - case MOUNT_REMOUNTING_SIGTERM: - case MOUNT_REMOUNTING_SIGKILL: - case MOUNT_UNMOUNTING_SIGTERM: - case MOUNT_UNMOUNTING_SIGKILL: - case MOUNT_FAILED: - if (old_state != state) - automount_send_ready(a, a->tokens, -ENODEV); + automount_set_state(a, AUTOMOUNT_RUNNING); + } - (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); - break; + /* The mount is in some unhappy state now, let's unfreeze any waiting clients */ + if (IN_SET(MOUNT(other)->state, + MOUNT_DEAD, MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL, + MOUNT_FAILED)) { - default: - break; - } + (void) automount_send_ready(a, a->tokens, -ENODEV); - return 0; + if (a->expire_event_source) + (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); + + automount_set_state(a, AUTOMOUNT_WAITING); + } } static void automount_enter_waiting(Automount *a) { @@ -1032,6 +1046,7 @@ static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { [AUTOMOUNT_SUCCESS] = "success", [AUTOMOUNT_FAILURE_RESOURCES] = "resources", [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); @@ -1066,6 +1081,8 @@ const UnitVTable automount_vtable = { .check_gc = automount_check_gc, + .trigger_notify = automount_trigger_notify, + .reset_failed = automount_reset_failed, .bus_vtable = bus_automount_vtable, diff --git a/src/core/automount.h b/src/core/automount.h index 414717e5b8..76a201178e 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -27,6 +27,7 @@ typedef enum AutomountResult { AUTOMOUNT_SUCCESS, AUTOMOUNT_FAILURE_RESOURCES, AUTOMOUNT_FAILURE_START_LIMIT_HIT, + AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT, _AUTOMOUNT_RESULT_MAX, _AUTOMOUNT_RESULT_INVALID = -1 } AutomountResult; @@ -54,7 +55,5 @@ struct Automount { extern const UnitVTable automount_vtable; -int automount_update_mount(Automount *a, MountState old_state, MountState state); - const char* automount_result_to_string(AutomountResult i) _const_; AutomountResult automount_result_from_string(const char *s) _pure_; diff --git a/src/core/mount.c b/src/core/mount.c index aa48941f0d..037f3684c7 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -584,23 +584,6 @@ static int mount_load(Unit *u) { return mount_verify(m); } -static int mount_notify_automount(Mount *m, MountState old_state, MountState state) { - Unit *p; - int r; - Iterator i; - - assert(m); - - SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i) - if (p->type == UNIT_AUTOMOUNT) { - r = automount_update_mount(AUTOMOUNT(p), old_state, state); - if (r < 0) - return r; - } - - return 0; -} - static void mount_set_state(Mount *m, MountState state) { MountState old_state; assert(m); @@ -624,8 +607,6 @@ static void mount_set_state(Mount *m, MountState state) { m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; } - mount_notify_automount(m, old_state, state); - if (state != old_state) log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state)); |