]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/mount: if umount(8) fails but mount disappeared, assume success
authorMike Yuan <me@yhndnzj.com>
Fri, 16 Feb 2024 19:03:50 +0000 (03:03 +0800)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 20 Feb 2024 15:22:27 +0000 (16:22 +0100)
Fixes #31337

src/core/mount.c

index ecd8172fb457d9f67ef54d56f1cd381cec17872d..5090465f936f693b3a0974c8437cb0ca94ff04b4 100644 (file)
@@ -1583,7 +1583,8 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
         if (IN_SET(m->state, MOUNT_REMOUNTING, MOUNT_REMOUNTING_SIGKILL, MOUNT_REMOUNTING_SIGTERM))
                 mount_set_reload_result(m, f);
-        else if (m->result == MOUNT_SUCCESS)
+        else if (m->result == MOUNT_SUCCESS && !IN_SET(m->state, MOUNT_MOUNTING, MOUNT_UNMOUNTING))
+                /* MOUNT_MOUNTING and MOUNT_UNMOUNTING states need to be patched, see below. */
                 m->result = f;
 
         if (m->control_command) {
@@ -1606,11 +1607,11 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         switch (m->state) {
 
         case MOUNT_MOUNTING:
-                /* Our mount point has not appeared in mountinfo.  Something went wrong. */
+                /* Our mount point has not appeared in mountinfo. Something went wrong. */
 
                 if (f == MOUNT_SUCCESS) {
-                        /* Either /bin/mount has an unexpected definition of success,
-                         * or someone raced us and we lost. */
+                        /* Either /bin/mount has an unexpected definition of success, or someone raced us
+                         * and we lost. */
                         log_unit_warning(UNIT(m), "Mount process finished, but there is no mount.");
                         f = MOUNT_FAILURE_PROTOCOL;
                 }
@@ -1628,9 +1629,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                 break;
 
         case MOUNT_UNMOUNTING:
-
                 if (f == MOUNT_SUCCESS && 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. We might exceed the timeout specified by the user overall,
                          * but we will stop as soon as any one umount times out. */
@@ -1643,13 +1642,18 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                 log_unit_warning(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
                                 mount_enter_mounted(m, f);
                         }
+                } else if (f == MOUNT_FAILURE_EXIT_CODE && !m->from_proc_self_mountinfo) {
+                        /* Hmm, umount process spawned by us failed, but the mount disappeared anyway?
+                         * Maybe someone else is trying to unmount at the same time. */
+                        log_unit_notice(u, "Mount disappeared even though umount process failed, continuing.");
+                        mount_enter_dead(m, MOUNT_SUCCESS);
                 } else
                         mount_enter_dead_or_mounted(m, f);
 
                 break;
 
-        case MOUNT_UNMOUNTING_SIGKILL:
         case MOUNT_UNMOUNTING_SIGTERM:
+        case MOUNT_UNMOUNTING_SIGKILL:
                 mount_enter_dead_or_mounted(m, f);
                 break;
 
@@ -2194,7 +2198,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) {
                                  * then remove it because of an internal error. E.g., fuse.sshfs seems
                                  * to do that when the connection fails. See #17617. To handle such the
                                  * case, let's once set the state back to mounting. Then, the unit can
-                                 * correctly enter the failed state later in mount_sigchld(). */
+                                 * correctly enter the failed state later in mount_sigchld_event(). */
                                 mount_set_state(mount, MOUNT_MOUNTING);
                                 break;