mnt: On an unmount propagate clearing of MNT_LOCKED
authorEric W. Biederman <ebiederm@xmission.com>
Sat, 3 Jan 2015 11:39:35 +0000 (05:39 -0600)
committerEric W. Biederman <ebiederm@xmission.com>
Fri, 3 Apr 2015 01:34:19 +0000 (20:34 -0500)
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.

Cc: stable@vger.kernel.org
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
fs/namespace.c
fs/pnode.c
fs/pnode.h

index 083e340..2b12b7a 100644 (file)
@@ -1333,6 +1333,9 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
        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;
index c27ae38..8989029 100644 (file)
@@ -362,6 +362,26 @@ int propagate_mount_busy(struct mount *mnt, int refcnt)
 }
 
 /*
+ * 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.
  */
index aa6d65d..af47d4b 100644 (file)
@@ -42,6 +42,7 @@ int propagate_mnt(struct mount *, struct mountpoint *, struct mount *,
                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);