aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-08-30 18:32:05 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-08-30 18:32:05 -0400
commit81b6b06197606b4bef4e427a197aeb808e8d89e1 (patch)
tree81d548e2161c8b9ccae34497df40251268bf3050 /fs/namespace.c
parent88b368f27a094277143d8ecd5a056116f6a41520 (diff)
fix EBUSY on umount() from MNT_SHRINKABLE
We need the parents of victims alive until namespace_unlock() gets to dput() of the (ex-)mountpoints. However, that screws up the "is it busy" checks in case when we have shrinkable mounts that need to be killed. Solution: go ahead and decrement refcounts of parents right in umount_tree(), increment them again just before dropping rwsem in namespace_unlock() (and let the loop in the end of namespace_unlock() finally drop those references for good, as we do now). Parents can't get freed until we drop rwsem - at least one reference is kept until then, both in case when parent is among the victims and when it is not. So they'll still be around when we get to namespace_unlock(). Cc: stable@vger.kernel.org # 3.12+ Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 3273177873f0..ef42d9bee212 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1217,6 +1217,11 @@ static void namespace_unlock(void)
1217 head.first->pprev = &head.first; 1217 head.first->pprev = &head.first;
1218 INIT_HLIST_HEAD(&unmounted); 1218 INIT_HLIST_HEAD(&unmounted);
1219 1219
1220 /* undo decrements we'd done in umount_tree() */
1221 hlist_for_each_entry(mnt, &head, mnt_hash)
1222 if (mnt->mnt_ex_mountpoint.mnt)
1223 mntget(mnt->mnt_ex_mountpoint.mnt);
1224
1220 up_write(&namespace_sem); 1225 up_write(&namespace_sem);
1221 1226
1222 synchronize_rcu(); 1227 synchronize_rcu();
@@ -1268,6 +1273,7 @@ void umount_tree(struct mount *mnt, int how)
1268 p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; 1273 p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
1269 if (mnt_has_parent(p)) { 1274 if (mnt_has_parent(p)) {
1270 put_mountpoint(p->mnt_mp); 1275 put_mountpoint(p->mnt_mp);
1276 mnt_add_count(p->mnt_parent, -1);
1271 /* move the reference to mountpoint into ->mnt_ex_mountpoint */ 1277 /* move the reference to mountpoint into ->mnt_ex_mountpoint */
1272 p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint; 1278 p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint;
1273 p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt; 1279 p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt;