umount: do not move busy network mounts

If a network mount returns EBUSY on umount, the logic introduced in
6dc68a00cf 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 6dc68a00cf
This commit is contained in:
Antonio Alvarez Feijoo
2025-03-10 12:21:26 +01:00
committed by Yu Watanabe
parent 63b331517e
commit cef2181cda
2 changed files with 10 additions and 6 deletions

View 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;

View 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;