--- /dev/null
+From 590ce4bcbfb4e0462a720a4ad901e84416080bba Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Mon, 22 Dec 2014 18:30:08 -0600
+Subject: mnt: Add MNT_UMOUNT flag
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit 590ce4bcbfb4e0462a720a4ad901e84416080bba upstream.
+
+In some instances it is necessary to know if the the unmounting
+process has begun on a mount. Add MNT_UMOUNT to make that reliably
+testable.
+
+This fix gets used in fixing locked mounts in MNT_DETACH
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 4 +++-
+ fs/pnode.c | 1 +
+ include/linux/mount.h | 1 +
+ 3 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1333,8 +1333,10 @@ static void umount_tree(struct mount *mn
+ struct mount *p;
+
+ /* Gather the mounts to umount */
+- for (p = mnt; p; p = next_mnt(p, mnt))
++ for (p = mnt; p; p = next_mnt(p, mnt)) {
++ p->mnt.mnt_flags |= MNT_UMOUNT;
+ list_move(&p->mnt_list, &tmp_list);
++ }
+
+ /* Hide the mounts from lookup_mnt and mnt_mounts */
+ list_for_each_entry(p, &tmp_list, mnt_list) {
+--- a/fs/pnode.c
++++ b/fs/pnode.c
+@@ -384,6 +384,7 @@ 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);
+ }
+ }
+--- a/include/linux/mount.h
++++ b/include/linux/mount.h
+@@ -61,6 +61,7 @@ struct mnt_namespace;
+ #define MNT_DOOMED 0x1000000
+ #define MNT_SYNC_UMOUNT 0x2000000
+ #define MNT_MARKED 0x4000000
++#define MNT_UMOUNT 0x8000000
+
+ struct vfsmount {
+ struct dentry *mnt_root; /* root of the mounted tree */
--- /dev/null
+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);
+ }
--- /dev/null
+From 8318e667f176f7ea34451a1a530634e293f216ac Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 24 Dec 2014 07:35:10 -0600
+Subject: mnt: Don't propagate umounts in __detach_mounts
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit 8318e667f176f7ea34451a1a530634e293f216ac upstream.
+
+Invoking mount propagation from __detach_mounts is inefficient and
+wrong.
+
+It is inefficient because __detach_mounts already walks the list of
+mounts that where something needs to be done, and mount propagation
+walks some subset of those mounts again.
+
+It is actively wrong because if the dentry that is passed to
+__detach_mounts is not part of the path to a mount that mount should
+not be affected.
+
+change_mnt_propagation(p,MS_PRIVATE) modifies the mount propagation
+tree of a master mount so it's slaves are connected to another master
+if possible. Which means even removing a mount from the middle of a
+mount tree with __detach_mounts will not deprive any mount propagated
+mount events.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1487,7 +1487,7 @@ void __detach_mounts(struct dentry *dent
+ lock_mount_hash();
+ while (!hlist_empty(&mp->m_list)) {
+ mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
+- umount_tree(mnt, UMOUNT_PROPAGATE);
++ umount_tree(mnt, 0);
+ }
+ unlock_mount_hash();
+ put_mountpoint(mp);
--- /dev/null
+From 0c56fe31420ca599c90240315f7959bf1b4eb6ce Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Mon, 5 Jan 2015 13:38:04 -0600
+Subject: mnt: Don't propagate unmounts to locked mounts
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit 0c56fe31420ca599c90240315f7959bf1b4eb6ce upstream.
+
+If the first mount in shared subtree is locked don't unmount the
+shared subtree.
+
+This is ensured by walking through the mounts parents before children
+and marking a mount as unmountable if it is not locked or it is locked
+but it's parent is marked.
+
+This allows recursive mount detach to propagate through a set of
+mounts when unmounting them would not reveal what is under any locked
+mount.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/pnode.c | 32 +++++++++++++++++++++++++++++---
+ fs/pnode.h | 1 +
+ 2 files changed, 30 insertions(+), 3 deletions(-)
+
+--- a/fs/pnode.c
++++ b/fs/pnode.c
+@@ -382,6 +382,26 @@ void propagate_mount_unlock(struct mount
+ }
+
+ /*
++ * Mark all mounts that the MNT_LOCKED logic will allow to be unmounted.
++ */
++static void mark_umount_candidates(struct mount *mnt)
++{
++ struct mount *parent = mnt->mnt_parent;
++ struct mount *m;
++
++ BUG_ON(parent == mnt);
++
++ for (m = propagation_next(parent, parent); m;
++ m = propagation_next(m, parent)) {
++ struct mount *child = __lookup_mnt_last(&m->mnt,
++ mnt->mnt_mountpoint);
++ if (child && (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m))) {
++ SET_MNT_MARK(child);
++ }
++ }
++}
++
++/*
+ * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
+ * parent propagates to.
+ */
+@@ -398,10 +418,13 @@ static void __propagate_umount(struct mo
+ struct mount *child = __lookup_mnt_last(&m->mnt,
+ mnt->mnt_mountpoint);
+ /*
+- * umount the child only if the child has no
+- * other children
++ * umount the child only if the child has no children
++ * and the child is marked safe to unmount.
+ */
+- if (child && list_empty(&child->mnt_mounts)) {
++ if (!child || !IS_MNT_MARKED(child))
++ continue;
++ CLEAR_MNT_MARK(child);
++ if (list_empty(&child->mnt_mounts)) {
+ list_del_init(&child->mnt_child);
+ child->mnt.mnt_flags |= MNT_UMOUNT;
+ list_move_tail(&child->mnt_list, &mnt->mnt_list);
+@@ -420,6 +443,9 @@ int propagate_umount(struct list_head *l
+ {
+ struct mount *mnt;
+
++ list_for_each_entry_reverse(mnt, list, mnt_list)
++ mark_umount_candidates(mnt);
++
+ list_for_each_entry(mnt, list, mnt_list)
+ __propagate_umount(mnt);
+ return 0;
+--- a/fs/pnode.h
++++ b/fs/pnode.h
+@@ -19,6 +19,7 @@
+ #define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED)
+ #define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
+ #define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
++#define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED)
+
+ #define CL_EXPIRE 0x01
+ #define CL_SLAVE 0x02
--- /dev/null
+From 7bdb11de8ee4f4ae195e2fa19efd304e0b36c63b Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Mon, 29 Dec 2014 13:03:41 -0600
+Subject: mnt: Factor out unhash_mnt from detach_mnt and umount_tree
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit 7bdb11de8ee4f4ae195e2fa19efd304e0b36c63b upstream.
+
+Create a function unhash_mnt that contains the common code between
+detach_mnt and umount_tree, and use unhash_mnt in place of the common
+code. This add a unncessary list_del_init(mnt->mnt_child) into
+umount_tree but given that mnt_child is already empty this extra
+line is a noop.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -798,10 +798,8 @@ static void __touch_mnt_namespace(struct
+ /*
+ * vfsmount lock must be held for write
+ */
+-static void detach_mnt(struct mount *mnt, struct path *old_path)
++static void unhash_mnt(struct mount *mnt)
+ {
+- old_path->dentry = mnt->mnt_mountpoint;
+- old_path->mnt = &mnt->mnt_parent->mnt;
+ mnt->mnt_parent = mnt;
+ mnt->mnt_mountpoint = mnt->mnt.mnt_root;
+ list_del_init(&mnt->mnt_child);
+@@ -814,6 +812,16 @@ static void detach_mnt(struct mount *mnt
+ /*
+ * vfsmount lock must be held for write
+ */
++static void detach_mnt(struct mount *mnt, struct path *old_path)
++{
++ old_path->dentry = mnt->mnt_mountpoint;
++ old_path->mnt = &mnt->mnt_parent->mnt;
++ unhash_mnt(mnt);
++}
++
++/*
++ * vfsmount lock must be held for write
++ */
+ void mnt_set_mountpoint(struct mount *mnt,
+ struct mountpoint *mp,
+ struct mount *child_mnt)
+@@ -1364,15 +1372,10 @@ static void umount_tree(struct mount *mn
+
+ pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, &unmounted);
+ if (mnt_has_parent(p)) {
+- hlist_del_init(&p->mnt_mp_list);
+- put_mountpoint(p->mnt_mp);
+ mnt_add_count(p->mnt_parent, -1);
+ /* old mountpoint will be dropped when we can do that */
+ p->mnt_ex_mountpoint = p->mnt_mountpoint;
+- p->mnt_mountpoint = p->mnt.mnt_root;
+- p->mnt_parent = p;
+- p->mnt_mp = NULL;
+- hlist_del_init_rcu(&p->mnt_hash);
++ unhash_mnt(p);
+ }
+ change_mnt_propagation(p, MS_PRIVATE);
+ }
--- /dev/null
+From 6a46c5735c29175da55b2fa9d53775182422cdd7 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Thu, 15 Jan 2015 22:58:33 -0600
+Subject: mnt: Factor umount_mnt from umount_tree
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit 6a46c5735c29175da55b2fa9d53775182422cdd7 upstream.
+
+For future use factor out a function umount_mnt from umount_tree.
+This function unhashes a mount and remembers where the mount
+was mounted so that eventually when the code makes it to a
+sleeping context the mountpoint can be dput.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -822,6 +822,16 @@ static void detach_mnt(struct mount *mnt
+ /*
+ * vfsmount lock must be held for write
+ */
++static void umount_mnt(struct mount *mnt)
++{
++ /* old mountpoint will be dropped when we can do that */
++ mnt->mnt_ex_mountpoint = mnt->mnt_mountpoint;
++ unhash_mnt(mnt);
++}
++
++/*
++ * vfsmount lock must be held for write
++ */
+ void mnt_set_mountpoint(struct mount *mnt,
+ struct mountpoint *mp,
+ struct mount *child_mnt)
+@@ -1373,9 +1383,7 @@ static void umount_tree(struct mount *mn
+ pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, &unmounted);
+ if (mnt_has_parent(p)) {
+ mnt_add_count(p->mnt_parent, -1);
+- /* old mountpoint will be dropped when we can do that */
+- p->mnt_ex_mountpoint = p->mnt_mountpoint;
+- unhash_mnt(p);
++ umount_mnt(p);
+ }
+ change_mnt_propagation(p, MS_PRIVATE);
+ }
--- /dev/null
+From f53e57975151f54ad8caa1b0ac8a78091cd5700a Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Mon, 19 Jan 2015 11:48:45 -0600
+Subject: mnt: Fix the error check in __detach_mounts
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit f53e57975151f54ad8caa1b0ac8a78091cd5700a upstream.
+
+lookup_mountpoint can return either NULL or an error value.
+Update the test in __detach_mounts to test for an error value
+to avoid pathological cases causing a NULL pointer dereferences.
+
+The callers of __detach_mounts should prevent it from ever being
+called on an unlinked dentry but don't take any chances.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1518,7 +1518,7 @@ void __detach_mounts(struct dentry *dent
+
+ namespace_lock();
+ mp = lookup_mountpoint(dentry);
+- if (!mp)
++ if (IS_ERR_OR_NULL(mp))
+ goto out_unlock;
+
+ lock_mount_hash();
--- /dev/null
+From ce07d891a0891d3c0d0c2d73d577490486b809e1 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Tue, 23 Dec 2014 21:37:03 -0600
+Subject: mnt: Honor MNT_LOCKED when detaching mounts
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit ce07d891a0891d3c0d0c2d73d577490486b809e1 upstream.
+
+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.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 29 ++++++++++++++++++++++++++---
+ fs/pnode.h | 2 ++
+ 2 files changed, 28 insertions(+), 3 deletions(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1099,6 +1099,13 @@ static void mntput_no_expire(struct moun
+ rcu_read_unlock();
+
+ list_del(&mnt->mnt_instance);
++
++ if (unlikely(!list_empty(&mnt->mnt_mounts))) {
++ struct mount *p, *tmp;
++ list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) {
++ umount_mnt(p);
++ }
++ }
+ unlock_mount_hash();
+
+ if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) {
+@@ -1372,6 +1379,7 @@ static void umount_tree(struct mount *mn
+ propagate_umount(&tmp_list);
+
+ while (!list_empty(&tmp_list)) {
++ bool disconnect;
+ p = list_first_entry(&tmp_list, struct mount, mnt_list);
+ list_del_init(&p->mnt_expire);
+ list_del_init(&p->mnt_list);
+@@ -1380,10 +1388,18 @@ static void umount_tree(struct mount *mn
+ if (how & UMOUNT_SYNC)
+ p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
+
+- pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, &unmounted);
++ disconnect = !IS_MNT_LOCKED_AND_LAZY(p);
++
++ pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
++ disconnect ? &unmounted : NULL);
+ if (mnt_has_parent(p)) {
+ mnt_add_count(p->mnt_parent, -1);
+- umount_mnt(p);
++ if (!disconnect) {
++ /* Don't forget about p */
++ list_add_tail(&p->mnt_child, &p->mnt_parent->mnt_mounts);
++ } else {
++ umount_mnt(p);
++ }
+ }
+ change_mnt_propagation(p, MS_PRIVATE);
+ }
+@@ -1508,7 +1524,14 @@ void __detach_mounts(struct dentry *dent
+ lock_mount_hash();
+ while (!hlist_empty(&mp->m_list)) {
+ mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
+- umount_tree(mnt, 0);
++ if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
++ struct mount *p, *tmp;
++ list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) {
++ hlist_add_head(&p->mnt_umount.s_list, &unmounted);
++ umount_mnt(p);
++ }
++ }
++ else umount_tree(mnt, 0);
+ }
+ unlock_mount_hash();
+ put_mountpoint(mp);
+--- a/fs/pnode.h
++++ b/fs/pnode.h
+@@ -20,6 +20,8 @@
+ #define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
+ #define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
+ #define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED)
++#define IS_MNT_LOCKED_AND_LAZY(m) \
++ (((m)->mnt.mnt_flags & (MNT_LOCKED|MNT_SYNC_UMOUNT)) == MNT_LOCKED)
+
+ #define CL_EXPIRE 0x01
+ #define CL_SLAVE 0x02
--- /dev/null
+From e819f152104c9f7c9fe50e1aecce6f5d4bf06d65 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 24 Dec 2014 07:20:01 -0600
+Subject: mnt: Improve the umount_tree flags
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit e819f152104c9f7c9fe50e1aecce6f5d4bf06d65 upstream.
+
+- Remove the unneeded declaration from pnode.h
+- Mark umount_tree static as it has no callers outside of namespace.c
+- Define an enumeration of umount_tree's flags.
+- Pass umount_tree's flags in by name
+
+This removes the magic numbers 0, 1 and 2 making the code a little
+clearer and makes it possible for there to be lazy unmounts that don't
+propagate. Which is what __detach_mounts actually wants for example.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 31 ++++++++++++++++---------------
+ fs/pnode.h | 1 -
+ 2 files changed, 16 insertions(+), 16 deletions(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1319,14 +1319,15 @@ static inline void namespace_lock(void)
+ down_write(&namespace_sem);
+ }
+
++enum umount_tree_flags {
++ UMOUNT_SYNC = 1,
++ UMOUNT_PROPAGATE = 2,
++};
+ /*
+ * mount_lock must be held
+ * namespace_sem must be held for write
+- * how = 0 => just this tree, don't propagate
+- * how = 1 => propagate; we know that nobody else has reference to any victims
+- * how = 2 => lazy umount
+ */
+-void umount_tree(struct mount *mnt, int how)
++static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
+ {
+ HLIST_HEAD(tmp_list);
+ struct mount *p;
+@@ -1339,7 +1340,7 @@ void umount_tree(struct mount *mnt, int
+ hlist_for_each_entry(p, &tmp_list, mnt_hash)
+ list_del_init(&p->mnt_child);
+
+- if (how)
++ if (how & UMOUNT_PROPAGATE)
+ propagate_umount(&tmp_list);
+
+ while (!hlist_empty(&tmp_list)) {
+@@ -1349,7 +1350,7 @@ void umount_tree(struct mount *mnt, int
+ list_del_init(&p->mnt_list);
+ __touch_mnt_namespace(p->mnt_ns);
+ p->mnt_ns = NULL;
+- if (how < 2)
++ if (how & UMOUNT_SYNC)
+ p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
+
+ pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, &unmounted);
+@@ -1447,14 +1448,14 @@ static int do_umount(struct mount *mnt,
+
+ if (flags & MNT_DETACH) {
+ if (!list_empty(&mnt->mnt_list))
+- umount_tree(mnt, 2);
++ umount_tree(mnt, UMOUNT_PROPAGATE);
+ retval = 0;
+ } else {
+ shrink_submounts(mnt);
+ retval = -EBUSY;
+ if (!propagate_mount_busy(mnt, 2)) {
+ if (!list_empty(&mnt->mnt_list))
+- umount_tree(mnt, 1);
++ umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC);
+ retval = 0;
+ }
+ }
+@@ -1486,7 +1487,7 @@ void __detach_mounts(struct dentry *dent
+ lock_mount_hash();
+ while (!hlist_empty(&mp->m_list)) {
+ mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
+- umount_tree(mnt, 2);
++ umount_tree(mnt, UMOUNT_PROPAGATE);
+ }
+ unlock_mount_hash();
+ put_mountpoint(mp);
+@@ -1648,7 +1649,7 @@ struct mount *copy_tree(struct mount *mn
+ out:
+ if (res) {
+ lock_mount_hash();
+- umount_tree(res, 0);
++ umount_tree(res, UMOUNT_SYNC);
+ unlock_mount_hash();
+ }
+ return q;
+@@ -1672,7 +1673,7 @@ void drop_collected_mounts(struct vfsmou
+ {
+ namespace_lock();
+ lock_mount_hash();
+- umount_tree(real_mount(mnt), 0);
++ umount_tree(real_mount(mnt), UMOUNT_SYNC);
+ unlock_mount_hash();
+ namespace_unlock();
+ }
+@@ -1855,7 +1856,7 @@ static int attach_recursive_mnt(struct m
+ out_cleanup_ids:
+ while (!hlist_empty(&tree_list)) {
+ child = hlist_entry(tree_list.first, struct mount, mnt_hash);
+- umount_tree(child, 0);
++ umount_tree(child, UMOUNT_SYNC);
+ }
+ unlock_mount_hash();
+ cleanup_group_ids(source_mnt, NULL);
+@@ -2035,7 +2036,7 @@ static int do_loopback(struct path *path
+ err = graft_tree(mnt, parent, mp);
+ if (err) {
+ lock_mount_hash();
+- umount_tree(mnt, 0);
++ umount_tree(mnt, UMOUNT_SYNC);
+ unlock_mount_hash();
+ }
+ out2:
+@@ -2406,7 +2407,7 @@ void mark_mounts_for_expiry(struct list_
+ while (!list_empty(&graveyard)) {
+ mnt = list_first_entry(&graveyard, struct mount, mnt_expire);
+ touch_mnt_namespace(mnt->mnt_ns);
+- umount_tree(mnt, 1);
++ umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC);
+ }
+ unlock_mount_hash();
+ namespace_unlock();
+@@ -2477,7 +2478,7 @@ static void shrink_submounts(struct moun
+ m = list_first_entry(&graveyard, struct mount,
+ mnt_expire);
+ touch_mnt_namespace(m->mnt_ns);
+- umount_tree(m, 1);
++ umount_tree(m, UMOUNT_PROPAGATE|UMOUNT_SYNC);
+ }
+ }
+ }
+--- a/fs/pnode.h
++++ b/fs/pnode.h
+@@ -47,7 +47,6 @@ int get_dominating_id(struct mount *mnt,
+ unsigned int mnt_get_count(struct mount *mnt);
+ void mnt_set_mountpoint(struct mount *, struct mountpoint *,
+ struct mount *);
+-void umount_tree(struct mount *, int);
+ struct mount *copy_tree(struct mount *, struct dentry *, int);
+ bool is_path_reachable(struct mount *, struct dentry *,
+ const struct path *root);
--- /dev/null
+From c003b26ff98ca04a180ff34c38c007a3998d62f9 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Thu, 18 Dec 2014 13:10:48 -0600
+Subject: mnt: In umount_tree reuse mnt_list instead of mnt_hash
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit c003b26ff98ca04a180ff34c38c007a3998d62f9 upstream.
+
+umount_tree builds a list of mounts that need to be unmounted.
+Utilize mnt_list for this purpose instead of mnt_hash. This begins to
+allow keeping a mount on the mnt_hash after it is unmounted, which is
+necessary for a properly functioning MNT_LOCKED implementation.
+
+The fact that mnt_list is an ordinary list makding available list_move
+is nice bonus.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 20 +++++++++++---------
+ fs/pnode.c | 6 +++---
+ fs/pnode.h | 2 +-
+ 3 files changed, 15 insertions(+), 13 deletions(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1329,23 +1329,25 @@ enum umount_tree_flags {
+ */
+ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
+ {
+- HLIST_HEAD(tmp_list);
++ LIST_HEAD(tmp_list);
+ struct mount *p;
+
+- for (p = mnt; p; p = next_mnt(p, mnt)) {
+- hlist_del_init_rcu(&p->mnt_hash);
+- hlist_add_head(&p->mnt_hash, &tmp_list);
+- }
++ /* Gather the mounts to umount */
++ for (p = mnt; p; p = next_mnt(p, mnt))
++ list_move(&p->mnt_list, &tmp_list);
+
+- hlist_for_each_entry(p, &tmp_list, mnt_hash)
++ /* Hide the mounts from lookup_mnt and mnt_mounts */
++ list_for_each_entry(p, &tmp_list, mnt_list) {
++ hlist_del_init_rcu(&p->mnt_hash);
+ list_del_init(&p->mnt_child);
++ }
+
++ /* Add propogated mounts to the tmp_list */
+ if (how & UMOUNT_PROPAGATE)
+ propagate_umount(&tmp_list);
+
+- while (!hlist_empty(&tmp_list)) {
+- p = hlist_entry(tmp_list.first, struct mount, mnt_hash);
+- hlist_del_init_rcu(&p->mnt_hash);
++ while (!list_empty(&tmp_list)) {
++ p = list_first_entry(&tmp_list, struct mount, mnt_list);
+ list_del_init(&p->mnt_expire);
+ list_del_init(&p->mnt_list);
+ __touch_mnt_namespace(p->mnt_ns);
+--- a/fs/pnode.c
++++ b/fs/pnode.c
+@@ -384,7 +384,7 @@ 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);
+- hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash);
++ list_move_tail(&child->mnt_list, &mnt->mnt_list);
+ }
+ }
+ }
+@@ -396,11 +396,11 @@ static void __propagate_umount(struct mo
+ *
+ * vfsmount lock must be held for write
+ */
+-int propagate_umount(struct hlist_head *list)
++int propagate_umount(struct list_head *list)
+ {
+ struct mount *mnt;
+
+- hlist_for_each_entry(mnt, list, mnt_hash)
++ list_for_each_entry(mnt, list, mnt_list)
+ __propagate_umount(mnt);
+ return 0;
+ }
+--- a/fs/pnode.h
++++ b/fs/pnode.h
+@@ -40,7 +40,7 @@ static inline void set_mnt_shared(struct
+ void change_mnt_propagation(struct mount *, int);
+ int propagate_mnt(struct mount *, struct mountpoint *, struct mount *,
+ struct hlist_head *);
+-int propagate_umount(struct hlist_head *);
++int propagate_umount(struct list_head *);
+ int propagate_mount_busy(struct mount *, int);
+ void mnt_release_group_id(struct mount *);
+ int get_dominating_id(struct mount *mnt, const struct path *root);
--- /dev/null
+From 5d88457eb5b86b475422dc882f089203faaeedb5 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Sat, 3 Jan 2015 05:39:35 -0600
+Subject: mnt: On an unmount propagate clearing of MNT_LOCKED
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit 5d88457eb5b86b475422dc882f089203faaeedb5 upstream.
+
+A prerequisite of calling umount_tree is that the point where the tree
+is mounted at is valid to unmount.
+
+If we are propagating the effect of the unmount clear MNT_LOCKED in
+every instance where the same filesystem is mounted on the same
+mountpoint in the mount tree, as we know (by virtue of the fact
+that umount_tree was called) that it is safe to reveal what
+is at that mountpoint.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 3 +++
+ fs/pnode.c | 20 ++++++++++++++++++++
+ fs/pnode.h | 1 +
+ 3 files changed, 24 insertions(+)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1335,6 +1335,9 @@ static void umount_tree(struct mount *mn
+ LIST_HEAD(tmp_list);
+ struct mount *p;
+
++ if (how & UMOUNT_PROPAGATE)
++ propagate_mount_unlock(mnt);
++
+ /* Gather the mounts to umount */
+ for (p = mnt; p; p = next_mnt(p, mnt)) {
+ p->mnt.mnt_flags |= MNT_UMOUNT;
+--- a/fs/pnode.c
++++ b/fs/pnode.c
+@@ -362,6 +362,26 @@ int propagate_mount_busy(struct mount *m
+ }
+
+ /*
++ * Clear MNT_LOCKED when it can be shown to be safe.
++ *
++ * mount_lock lock must be held for write
++ */
++void propagate_mount_unlock(struct mount *mnt)
++{
++ struct mount *parent = mnt->mnt_parent;
++ struct mount *m, *child;
++
++ BUG_ON(parent == mnt);
++
++ for (m = propagation_next(parent, parent); m;
++ m = propagation_next(m, parent)) {
++ child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
++ if (child)
++ child->mnt.mnt_flags &= ~MNT_LOCKED;
++ }
++}
++
++/*
+ * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
+ * parent propagates to.
+ */
+--- a/fs/pnode.h
++++ b/fs/pnode.h
+@@ -42,6 +42,7 @@ int propagate_mnt(struct mount *, struct
+ struct hlist_head *);
+ int propagate_umount(struct list_head *);
+ int propagate_mount_busy(struct mount *, int);
++void propagate_mount_unlock(struct mount *);
+ void mnt_release_group_id(struct mount *);
+ int get_dominating_id(struct mount *mnt, const struct path *root);
+ unsigned int mnt_get_count(struct mount *mnt);
--- /dev/null
+From e0c9c0afd2fc958ffa34b697972721d81df8a56f Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 1 Apr 2015 18:30:06 -0500
+Subject: mnt: Update detach_mounts to leave mounts connected
+
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+
+commit e0c9c0afd2fc958ffa34b697972721d81df8a56f upstream.
+
+Now that it is possible to lazily unmount an entire mount tree and
+leave the individual mounts connected to each other add a new flag
+UMOUNT_CONNECTED to umount_tree to force this behavior and use
+this flag in detach_mounts.
+
+This closes a bug where the deletion of a file or directory could
+trigger an unmount and reveal data under a mount point.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/namespace.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1350,6 +1350,7 @@ static inline void namespace_lock(void)
+ enum umount_tree_flags {
+ UMOUNT_SYNC = 1,
+ UMOUNT_PROPAGATE = 2,
++ UMOUNT_CONNECTED = 4,
+ };
+ /*
+ * mount_lock must be held
+@@ -1388,7 +1389,10 @@ static void umount_tree(struct mount *mn
+ if (how & UMOUNT_SYNC)
+ p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
+
+- disconnect = !IS_MNT_LOCKED_AND_LAZY(p);
++ disconnect = !(((how & UMOUNT_CONNECTED) &&
++ mnt_has_parent(p) &&
++ (p->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) ||
++ IS_MNT_LOCKED_AND_LAZY(p));
+
+ pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
+ disconnect ? &unmounted : NULL);
+@@ -1531,7 +1535,7 @@ void __detach_mounts(struct dentry *dent
+ umount_mnt(p);
+ }
+ }
+- else umount_tree(mnt, 0);
++ else umount_tree(mnt, UMOUNT_CONNECTED);
+ }
+ unlock_mount_hash();
+ put_mountpoint(mp);
rtlwifi-rtl8192cu-add-new-usb-id.patch
rtlwifi-rtl8192cu-add-new-device-id.patch
ext4-make-fsync-to-sync-parent-dir-in-no-journal-for-real-this-time.patch
+mnt-improve-the-umount_tree-flags.patch
+mnt-don-t-propagate-umounts-in-__detach_mounts.patch
+mnt-in-umount_tree-reuse-mnt_list-instead-of-mnt_hash.patch
+mnt-add-mnt_umount-flag.patch
+mnt-delay-removal-from-the-mount-hash.patch
+mnt-on-an-unmount-propagate-clearing-of-mnt_locked.patch
+mnt-don-t-propagate-unmounts-to-locked-mounts.patch
+mnt-factor-out-unhash_mnt-from-detach_mnt-and-umount_tree.patch
+mnt-factor-umount_mnt-from-umount_tree.patch
+mnt-honor-mnt_locked-when-detaching-mounts.patch
+mnt-fix-the-error-check-in-__detach_mounts.patch
+mnt-update-detach_mounts-to-leave-mounts-connected.patch