diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-12-12 20:12:35 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-12-12 20:12:35 +0100 |
commit | 7d54a03a877e9c3f3f3087401ac4ccc1e12c78ea (patch) | |
tree | 78a31d0d499781e6dd584677e3dbcd8c0398b787 /src | |
parent | b1acce80cd60fe95f16df2f1ad23ff2ad82d08e5 (diff) |
core: retry unmounting until we are done, in case of stacked mounts
Diffstat (limited to 'src')
-rw-r--r-- | src/core/mount.c | 46 | ||||
-rw-r--r-- | src/core/mount.h | 2 |
2 files changed, 41 insertions, 7 deletions
diff --git a/src/core/mount.c b/src/core/mount.c index e271d437cb..3029cfd4d8 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -45,6 +45,8 @@ #include "exit-status.h" #include "def.h" +#define RETRY_UMOUNT_MAX 32 + DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table); DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter); @@ -867,20 +869,28 @@ static void mount_enter_unmounting(Mount *m) { assert(m); + /* Start counting our attempts */ + if (!IN_SET(m->state, + MOUNT_UNMOUNTING, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL)) + m->n_retry_umount = 0; + m->control_command_id = MOUNT_EXEC_UNMOUNT; m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT; - if ((r = exec_command_set( - m->control_command, + r = exec_command_set(m->control_command, "/bin/umount", "-n", m->where, - NULL)) < 0) + NULL); + if (r < 0) goto fail; mount_unwatch_control_pid(m); - if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0) + r = mount_spawn(m, m->control_command, &m->control_pid); + if (r < 0) goto fail; mount_set_state(m, MOUNT_UNMOUNTING); @@ -1239,9 +1249,31 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { case MOUNT_UNMOUNTING_SIGKILL: case MOUNT_UNMOUNTING_SIGTERM: - if (f == MOUNT_SUCCESS) - mount_enter_dead(m, f); - else if (m->from_proc_self_mountinfo) + if (f == MOUNT_SUCCESS) { + + if (m->from_proc_self_mountinfo) { + + /* Still a mount point? If so, let's + * try again. Most likely there were + * multiple mount points stacked on + * top of each other. Note that due to + * the io event priority logic we can + * be sure the new mountinfo is loaded + * before we process the SIGCHLD for + * the mount command. */ + + if (m->n_retry_umount < RETRY_UMOUNT_MAX) { + log_unit_debug(u->id, "%s: mount still present, trying again.", u->id); + m->n_retry_umount++; + mount_enter_unmounting(m); + } else { + log_unit_debug(u->id, "%s: mount still present after %u attempts to unmount, giving up.", u->id, m->n_retry_umount); + mount_enter_mounted(m, f); + } + } else + mount_enter_dead(m, f); + + } else if (m->from_proc_self_mountinfo) mount_enter_mounted(m, f); else mount_enter_dead(m, f); diff --git a/src/core/mount.h b/src/core/mount.h index 2dcb663cb1..d6987e6fa1 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -112,6 +112,8 @@ struct Mount { pid_t control_pid; sd_event_source *timer_event_source; + + unsigned n_retry_umount; }; extern const UnitVTable mount_vtable; |