aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2014-12-22 20:12:07 -0500
committerEric W. Biederman <ebiederm@xmission.com>2015-04-02 21:34:19 -0400
commit411a938b5abc9cb126c41cccf5975ae464fe0f3e (patch)
tree730e8410fbeb2ec8190b9b2352abf80ffd56f0ce /fs
parent590ce4bcbfb4e0462a720a4ad901e84416080bba (diff)
mnt: Delay removal from the mount hash.
- Modify __lookup_mnt_hash_last to ignore mounts that have MNT_UMOUNTED set. - Don't remove mounts from the mount hash table in propogate_umount - Don't remove mounts from the mount hash table in umount_tree before the entire list of mounts to be umounted is selected. - Remove mounts from the mount hash table as the last thing that happens in the case where a mount has a parent in umount_tree. Mounts without parents are not hashed (by definition). This paves the way for delaying removal from the mount hash table even farther and fixing the MNT_LOCKED vs MNT_DETACH issue. Cc: stable@vger.kernel.org Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/namespace.c13
-rw-r--r--fs/pnode.c1
2 files changed, 8 insertions, 6 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index d1708147eb45..083e3401a808 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -632,14 +632,17 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
632 */ 632 */
633struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) 633struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry)
634{ 634{
635 struct mount *p, *res; 635 struct mount *p, *res = NULL;
636 res = p = __lookup_mnt(mnt, dentry); 636 p = __lookup_mnt(mnt, dentry);
637 if (!p) 637 if (!p)
638 goto out; 638 goto out;
639 if (!(p->mnt.mnt_flags & MNT_UMOUNT))
640 res = p;
639 hlist_for_each_entry_continue(p, mnt_hash) { 641 hlist_for_each_entry_continue(p, mnt_hash) {
640 if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) 642 if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry)
641 break; 643 break;
642 res = p; 644 if (!(p->mnt.mnt_flags & MNT_UMOUNT))
645 res = p;
643 } 646 }
644out: 647out:
645 return res; 648 return res;
@@ -1336,9 +1339,8 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
1336 list_move(&p->mnt_list, &tmp_list); 1339 list_move(&p->mnt_list, &tmp_list);
1337 } 1340 }
1338 1341
1339 /* Hide the mounts from lookup_mnt and mnt_mounts */ 1342 /* Hide the mounts from mnt_mounts */
1340 list_for_each_entry(p, &tmp_list, mnt_list) { 1343 list_for_each_entry(p, &tmp_list, mnt_list) {
1341 hlist_del_init_rcu(&p->mnt_hash);
1342 list_del_init(&p->mnt_child); 1344 list_del_init(&p->mnt_child);
1343 } 1345 }
1344 1346
@@ -1365,6 +1367,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
1365 p->mnt_mountpoint = p->mnt.mnt_root; 1367 p->mnt_mountpoint = p->mnt.mnt_root;
1366 p->mnt_parent = p; 1368 p->mnt_parent = p;
1367 p->mnt_mp = NULL; 1369 p->mnt_mp = NULL;
1370 hlist_del_init_rcu(&p->mnt_hash);
1368 } 1371 }
1369 change_mnt_propagation(p, MS_PRIVATE); 1372 change_mnt_propagation(p, MS_PRIVATE);
1370 } 1373 }
diff --git a/fs/pnode.c b/fs/pnode.c
index ac3aa0d43b90..c27ae38ee250 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -383,7 +383,6 @@ static void __propagate_umount(struct mount *mnt)
383 */ 383 */
384 if (child && list_empty(&child->mnt_mounts)) { 384 if (child && list_empty(&child->mnt_mounts)) {
385 list_del_init(&child->mnt_child); 385 list_del_init(&child->mnt_child);
386 hlist_del_init_rcu(&child->mnt_hash);
387 child->mnt.mnt_flags |= MNT_UMOUNT; 386 child->mnt.mnt_flags |= MNT_UMOUNT;
388 list_move_tail(&child->mnt_list, &mnt->mnt_list); 387 list_move_tail(&child->mnt_list, &mnt->mnt_list);
389 } 388 }