]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
umount: do not move busy network mounts
authorAntonio Alvarez Feijoo <antonio.feijoo@suse.com>
Mon, 10 Mar 2025 11:21:26 +0000 (12:21 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 10 Mar 2025 20:53:31 +0000 (05:53 +0900)
If a network mount returns EBUSY on umount, the logic introduced in
6dc68a00cfc816678fd713b12ae2a4cf2ae6da85 causes shutdown to hang indefinitely on
`fstatat()` (i.e., within `is_dir(m->path, true)`). Hence, skip this logic for
network mounts (following the same motivation we use to skip read-only mounts in
this kind of file systems).

Fixes 6dc68a00cfc816678fd713b12ae2a4cf2ae6da85

src/shutdown/umount.c
src/shutdown/umount.h

index a788f8cf8381f833c879b8f0f827d07dbed7984f..6d7c78a97a6688959fa119d1af8393c05dec7c94 100644 (file)
@@ -63,7 +63,7 @@ int mount_points_list_get(FILE *f, MountPoint **head) {
                 struct libmnt_fs *fs;
                 const char *path, *fstype;
                 unsigned long remount_flags = 0u;
-                bool try_remount_ro, is_api_vfs;
+                bool try_remount_ro, is_api_vfs, is_network;
                 _cleanup_free_ MountPoint *m = NULL;
 
                 r = mnt_table_next_fs(table, iter, &fs);
@@ -98,6 +98,7 @@ int mount_points_list_get(FILE *f, MountPoint **head) {
                     path_below_api_vfs(path))
                         continue;
 
+                is_network = fstype_is_network(fstype);
                 is_api_vfs = fstype_is_api_vfs(fstype);
 
                 /* If we are in a container, don't attempt to read-only mount anything as that brings no real
@@ -108,7 +109,7 @@ int mount_points_list_get(FILE *f, MountPoint **head) {
                  * leave a "dirty fs") and could hang if the network is down.  Note that umount2() is more
                  * careful and will not hang because of the network being down. */
                 try_remount_ro = detect_container() <= 0 &&
-                                 !fstype_is_network(fstype) &&
+                                 !is_network &&
                                  !is_api_vfs &&
                                  !fstype_is_ro(fstype) &&
                                  !fstab_test_yes_no_option(options, "ro\0rw\0");
@@ -152,7 +153,11 @@ int mount_points_list_get(FILE *f, MountPoint **head) {
                         /* Unmount sysfs/procfs/… lazily, since syncing doesn't matter there, and it's OK if
                          * something keeps an fd open to it. */
                         .umount_lazily = is_api_vfs,
-                        .leaf = leaf,
+
+                        /* If a mount point is not a leaf, moving it would invalidate our mount table.
+                         * If a mount point is on the network and the network is down, it can hang and block
+                         * the shutdown. */
+                        .umount_move_if_busy = leaf && !is_network,
                 };
 
                 m->path = strdup(path);
@@ -403,10 +408,9 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool last_
                         *changed = true;
 
                 /* If a mount is busy, we move it to not keep parent mount points busy.
-                 * If a mount point is not a leaf, moving it would invalidate our mount table.
                  * More moving will occur in next iteration with a fresh mount table.
                  */
-                if (r != -EBUSY || !m->leaf)
+                if (r != -EBUSY || !m->umount_move_if_busy)
                         continue;
 
                 _cleanup_free_ char *dirname = NULL;
index 22498e1e776df68de8c43b292093c8ee13b7af3c..d18795c727870d044bf72960bf1c01de9a72bfbf 100644 (file)
@@ -19,7 +19,7 @@ typedef struct MountPoint {
         unsigned long remount_flags;
         bool try_remount_ro;
         bool umount_lazily;
-        bool leaf;
+        bool umount_move_if_busy;
         LIST_FIELDS(struct MountPoint, mount_point);
 } MountPoint;