mirror of
https://github.com/systemd/systemd.git
synced 2024-11-06 08:26:52 +03:00
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
This commit is contained in:
parent
d14e3a0de9
commit
fae03ed32a
@ -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);
|
||||
|
||||
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));
|
||||
/* Filter out invocations with bogus state */
|
||||
if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT)
|
||||
return;
|
||||
|
||||
switch (state) {
|
||||
/* Don't propagate state changes from the mount if we are already down */
|
||||
if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
|
||||
return;
|
||||
|
||||
/* Propagate start limit hit state */
|
||||
if (other->start_limit_hit) {
|
||||
automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
(void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
automount_set_state(a, AUTOMOUNT_RUNNING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* 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)) {
|
||||
|
||||
(void) automount_send_ready(a, a->tokens, -ENODEV);
|
||||
|
||||
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,
|
||||
|
@ -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_;
|
||||
|
@ -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));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user