| From 411a938b5abc9cb126c41cccf5975ae464fe0f3e Mon Sep 17 00:00:00 2001 |
| From: "Eric W. Biederman" <ebiederm@xmission.com> |
| Date: Mon, 22 Dec 2014 19:12:07 -0600 |
| Subject: mnt: Delay removal from the mount hash. |
| |
| From: "Eric W. Biederman" <ebiederm@xmission.com> |
| |
| commit 411a938b5abc9cb126c41cccf5975ae464fe0f3e upstream. |
| |
| - 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. |
| |
| Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/namespace.c | 13 ++++++++----- |
| fs/pnode.c | 1 - |
| 2 files changed, 8 insertions(+), 6 deletions(-) |
| |
| --- a/fs/namespace.c |
| +++ b/fs/namespace.c |
| @@ -632,14 +632,17 @@ struct mount *__lookup_mnt(struct vfsmou |
| */ |
| struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) |
| { |
| - struct mount *p, *res; |
| - res = p = __lookup_mnt(mnt, dentry); |
| + struct mount *p, *res = NULL; |
| + p = __lookup_mnt(mnt, dentry); |
| if (!p) |
| goto out; |
| + if (!(p->mnt.mnt_flags & MNT_UMOUNT)) |
| + res = p; |
| hlist_for_each_entry_continue(p, mnt_hash) { |
| if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) |
| break; |
| - res = p; |
| + if (!(p->mnt.mnt_flags & MNT_UMOUNT)) |
| + res = p; |
| } |
| out: |
| return res; |
| @@ -1338,9 +1341,8 @@ static void umount_tree(struct mount *mn |
| list_move(&p->mnt_list, &tmp_list); |
| } |
| |
| - /* Hide the mounts from lookup_mnt and mnt_mounts */ |
| + /* Hide the mounts from mnt_mounts */ |
| list_for_each_entry(p, &tmp_list, mnt_list) { |
| - hlist_del_init_rcu(&p->mnt_hash); |
| list_del_init(&p->mnt_child); |
| } |
| |
| @@ -1367,6 +1369,7 @@ static void umount_tree(struct mount *mn |
| p->mnt_mountpoint = p->mnt.mnt_root; |
| p->mnt_parent = p; |
| p->mnt_mp = NULL; |
| + hlist_del_init_rcu(&p->mnt_hash); |
| } |
| change_mnt_propagation(p, MS_PRIVATE); |
| } |
| --- a/fs/pnode.c |
| +++ b/fs/pnode.c |
| @@ -383,7 +383,6 @@ static void __propagate_umount(struct mo |
| */ |
| if (child && list_empty(&child->mnt_mounts)) { |
| list_del_init(&child->mnt_child); |
| - hlist_del_init_rcu(&child->mnt_hash); |
| child->mnt.mnt_flags |= MNT_UMOUNT; |
| list_move_tail(&child->mnt_list, &mnt->mnt_list); |
| } |