Skip to content

Commit ce07d89

Browse files
committed
mnt: Honor MNT_LOCKED when detaching mounts
Modify umount(MNT_DETACH) to keep mounts in the hash table that are locked to their parent mounts, when the parent is lazily unmounted. In mntput_no_expire detach the children from the hash table, depending on mnt_pin_kill in cleanup_mnt to decrement the mnt_count of the children. In __detach_mounts if there are any mounts that have been unmounted but still are on the list of mounts of a mountpoint, remove their children from the mount hash table and those children to the unmounted list so they won't linger potentially indefinitely waiting for their final mntput, now that the mounts serve no purpose. Cc: [email protected] Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 820f9f1 commit ce07d89

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

fs/namespace.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,13 @@ static void mntput_no_expire(struct mount *mnt)
10991099
rcu_read_unlock();
11001100

11011101
list_del(&mnt->mnt_instance);
1102+
1103+
if (unlikely(!list_empty(&mnt->mnt_mounts))) {
1104+
struct mount *p, *tmp;
1105+
list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) {
1106+
umount_mnt(p);
1107+
}
1108+
}
11021109
unlock_mount_hash();
11031110

11041111
if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) {
@@ -1370,6 +1377,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
13701377
propagate_umount(&tmp_list);
13711378

13721379
while (!list_empty(&tmp_list)) {
1380+
bool disconnect;
13731381
p = list_first_entry(&tmp_list, struct mount, mnt_list);
13741382
list_del_init(&p->mnt_expire);
13751383
list_del_init(&p->mnt_list);
@@ -1378,10 +1386,18 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
13781386
if (how & UMOUNT_SYNC)
13791387
p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
13801388

1381-
pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, &unmounted);
1389+
disconnect = !IS_MNT_LOCKED_AND_LAZY(p);
1390+
1391+
pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
1392+
disconnect ? &unmounted : NULL);
13821393
if (mnt_has_parent(p)) {
13831394
mnt_add_count(p->mnt_parent, -1);
1384-
umount_mnt(p);
1395+
if (!disconnect) {
1396+
/* Don't forget about p */
1397+
list_add_tail(&p->mnt_child, &p->mnt_parent->mnt_mounts);
1398+
} else {
1399+
umount_mnt(p);
1400+
}
13851401
}
13861402
change_mnt_propagation(p, MS_PRIVATE);
13871403
}
@@ -1506,7 +1522,14 @@ void __detach_mounts(struct dentry *dentry)
15061522
lock_mount_hash();
15071523
while (!hlist_empty(&mp->m_list)) {
15081524
mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
1509-
umount_tree(mnt, 0);
1525+
if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
1526+
struct mount *p, *tmp;
1527+
list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) {
1528+
hlist_add_head(&p->mnt_umount.s_list, &unmounted);
1529+
umount_mnt(p);
1530+
}
1531+
}
1532+
else umount_tree(mnt, 0);
15101533
}
15111534
unlock_mount_hash();
15121535
put_mountpoint(mp);

fs/pnode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
2121
#define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
2222
#define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED)
23+
#define IS_MNT_LOCKED_AND_LAZY(m) \
24+
(((m)->mnt.mnt_flags & (MNT_LOCKED|MNT_SYNC_UMOUNT)) == MNT_LOCKED)
2325

2426
#define CL_EXPIRE 0x01
2527
#define CL_SLAVE 0x02

0 commit comments

Comments
 (0)