aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c29
-rw-r--r--fs/pnode.h2
2 files changed, 28 insertions, 3 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 010d5bebcb7e..1894d1878dbc 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1099,6 +1099,13 @@ static void mntput_no_expire(struct mount *mnt)
1099 rcu_read_unlock(); 1099 rcu_read_unlock();
1100 1100
1101 list_del(&mnt->mnt_instance); 1101 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 }
1102 unlock_mount_hash(); 1109 unlock_mount_hash();
1103 1110
1104 if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) { 1111 if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) {
@@ -1370,6 +1377,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
1370 propagate_umount(&tmp_list); 1377 propagate_umount(&tmp_list);
1371 1378
1372 while (!list_empty(&tmp_list)) { 1379 while (!list_empty(&tmp_list)) {
1380 bool disconnect;
1373 p = list_first_entry(&tmp_list, struct mount, mnt_list); 1381 p = list_first_entry(&tmp_list, struct mount, mnt_list);
1374 list_del_init(&p->mnt_expire); 1382 list_del_init(&p->mnt_expire);
1375 list_del_init(&p->mnt_list); 1383 list_del_init(&p->mnt_list);
@@ -1378,10 +1386,18 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
1378 if (how & UMOUNT_SYNC) 1386 if (how & UMOUNT_SYNC)
1379 p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; 1387 p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
1380 1388
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);
1382 if (mnt_has_parent(p)) { 1393 if (mnt_has_parent(p)) {
1383 mnt_add_count(p->mnt_parent, -1); 1394 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 }
1385 } 1401 }
1386 change_mnt_propagation(p, MS_PRIVATE); 1402 change_mnt_propagation(p, MS_PRIVATE);
1387 } 1403 }
@@ -1506,7 +1522,14 @@ void __detach_mounts(struct dentry *dentry)
1506 lock_mount_hash(); 1522 lock_mount_hash();
1507 while (!hlist_empty(&mp->m_list)) { 1523 while (!hlist_empty(&mp->m_list)) {
1508 mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list); 1524 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);
1510 } 1533 }
1511 unlock_mount_hash(); 1534 unlock_mount_hash();
1512 put_mountpoint(mp); 1535 put_mountpoint(mp);
diff --git a/fs/pnode.h b/fs/pnode.h
index 0fcdbe7ca648..7114ce6e6b9e 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -20,6 +20,8 @@
20#define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED) 20#define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
21#define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED) 21#define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
22#define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED) 22#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)
23 25
24#define CL_EXPIRE 0x01 26#define CL_EXPIRE 0x01
25#define CL_SLAVE 0x02 27#define CL_SLAVE 0x02