]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 2 May 2015 15:56:13 +0000 (17:56 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 2 May 2015 15:56:13 +0000 (17:56 +0200)
added patches:
mnt-add-mnt_umount-flag.patch
mnt-delay-removal-from-the-mount-hash.patch
mnt-don-t-propagate-umounts-in-__detach_mounts.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-fix-the-error-check-in-__detach_mounts.patch
mnt-honor-mnt_locked-when-detaching-mounts.patch
mnt-improve-the-umount_tree-flags.patch
mnt-in-umount_tree-reuse-mnt_list-instead-of-mnt_hash.patch
mnt-on-an-unmount-propagate-clearing-of-mnt_locked.patch
mnt-update-detach_mounts-to-leave-mounts-connected.patch

13 files changed:
queue-4.0/mnt-add-mnt_umount-flag.patch [new file with mode: 0644]
queue-4.0/mnt-delay-removal-from-the-mount-hash.patch [new file with mode: 0644]
queue-4.0/mnt-don-t-propagate-umounts-in-__detach_mounts.patch [new file with mode: 0644]
queue-4.0/mnt-don-t-propagate-unmounts-to-locked-mounts.patch [new file with mode: 0644]
queue-4.0/mnt-factor-out-unhash_mnt-from-detach_mnt-and-umount_tree.patch [new file with mode: 0644]
queue-4.0/mnt-factor-umount_mnt-from-umount_tree.patch [new file with mode: 0644]
queue-4.0/mnt-fix-the-error-check-in-__detach_mounts.patch [new file with mode: 0644]
queue-4.0/mnt-honor-mnt_locked-when-detaching-mounts.patch [new file with mode: 0644]
queue-4.0/mnt-improve-the-umount_tree-flags.patch [new file with mode: 0644]
queue-4.0/mnt-in-umount_tree-reuse-mnt_list-instead-of-mnt_hash.patch [new file with mode: 0644]
queue-4.0/mnt-on-an-unmount-propagate-clearing-of-mnt_locked.patch [new file with mode: 0644]
queue-4.0/mnt-update-detach_mounts-to-leave-mounts-connected.patch [new file with mode: 0644]
queue-4.0/series

diff --git a/queue-4.0/mnt-add-mnt_umount-flag.patch b/queue-4.0/mnt-add-mnt_umount-flag.patch
new file mode 100644 (file)
index 0000000..e766650
--- /dev/null
@@ -0,0 +1,58 @@
+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 */
diff --git a/queue-4.0/mnt-delay-removal-from-the-mount-hash.patch b/queue-4.0/mnt-delay-removal-from-the-mount-hash.patch
new file mode 100644 (file)
index 0000000..8bb5edd
--- /dev/null
@@ -0,0 +1,80 @@
+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);
+               }
diff --git a/queue-4.0/mnt-don-t-propagate-umounts-in-__detach_mounts.patch b/queue-4.0/mnt-don-t-propagate-umounts-in-__detach_mounts.patch
new file mode 100644 (file)
index 0000000..6738ae9
--- /dev/null
@@ -0,0 +1,44 @@
+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);
diff --git a/queue-4.0/mnt-don-t-propagate-unmounts-to-locked-mounts.patch b/queue-4.0/mnt-don-t-propagate-unmounts-to-locked-mounts.patch
new file mode 100644 (file)
index 0000000..dcce186
--- /dev/null
@@ -0,0 +1,94 @@
+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
diff --git a/queue-4.0/mnt-factor-out-unhash_mnt-from-detach_mnt-and-umount_tree.patch b/queue-4.0/mnt-factor-out-unhash_mnt-from-detach_mnt-and-umount_tree.patch
new file mode 100644 (file)
index 0000000..324f834
--- /dev/null
@@ -0,0 +1,70 @@
+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);
+       }
diff --git a/queue-4.0/mnt-factor-umount_mnt-from-umount_tree.patch b/queue-4.0/mnt-factor-umount_mnt-from-umount_tree.patch
new file mode 100644 (file)
index 0000000..5164c13
--- /dev/null
@@ -0,0 +1,51 @@
+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);
+       }
diff --git a/queue-4.0/mnt-fix-the-error-check-in-__detach_mounts.patch b/queue-4.0/mnt-fix-the-error-check-in-__detach_mounts.patch
new file mode 100644 (file)
index 0000000..7bbadcd
--- /dev/null
@@ -0,0 +1,34 @@
+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();
diff --git a/queue-4.0/mnt-honor-mnt_locked-when-detaching-mounts.patch b/queue-4.0/mnt-honor-mnt_locked-when-detaching-mounts.patch
new file mode 100644 (file)
index 0000000..8e6e4ef
--- /dev/null
@@ -0,0 +1,101 @@
+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
diff --git a/queue-4.0/mnt-improve-the-umount_tree-flags.patch b/queue-4.0/mnt-improve-the-umount_tree-flags.patch
new file mode 100644 (file)
index 0000000..595228e
--- /dev/null
@@ -0,0 +1,156 @@
+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);
diff --git a/queue-4.0/mnt-in-umount_tree-reuse-mnt_list-instead-of-mnt_hash.patch b/queue-4.0/mnt-in-umount_tree-reuse-mnt_list-instead-of-mnt_hash.patch
new file mode 100644 (file)
index 0000000..76cb484
--- /dev/null
@@ -0,0 +1,99 @@
+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);
diff --git a/queue-4.0/mnt-on-an-unmount-propagate-clearing-of-mnt_locked.patch b/queue-4.0/mnt-on-an-unmount-propagate-clearing-of-mnt_locked.patch
new file mode 100644 (file)
index 0000000..4591b3f
--- /dev/null
@@ -0,0 +1,78 @@
+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);
diff --git a/queue-4.0/mnt-update-detach_mounts-to-leave-mounts-connected.patch b/queue-4.0/mnt-update-detach_mounts-to-leave-mounts-connected.patch
new file mode 100644 (file)
index 0000000..9ed9e95
--- /dev/null
@@ -0,0 +1,55 @@
+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);
index d3ecae7a2f6d6454703aa511eaeaa053d4276ec0..6aa2c32a5022e0df0bcbaf4f31ecfc44e7da8182 100644 (file)
@@ -104,3 +104,15 @@ nfc-st21nfcb-retry-i2c_master_send-if-it-returns-a-negative-value.patch
 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