From cef2181cda87cbecd6e92f6d7a3bb8556067a88e Mon Sep 17 00:00:00 2001 From: Antonio Alvarez Feijoo Date: Mon, 10 Mar 2025 12:21:26 +0100 Subject: [PATCH] umount: do not move busy network mounts 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 | 14 +++++++++----- src/shutdown/umount.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c index a788f8cf838..6d7c78a97a6 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c @@ -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; diff --git a/src/shutdown/umount.h b/src/shutdown/umount.h index 22498e1e776..d18795c7278 100644 --- a/src/shutdown/umount.h +++ b/src/shutdown/umount.h @@ -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; -- 2.47.3