diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-03-16 14:35:16 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-04-09 14:12:52 -0400 |
commit | e3197d83d6f5b9bd0e57a05592437ffa459ee106 (patch) | |
tree | ad0a4f5f256f55ed8115c30823c0c967cbedba13 | |
parent | 84d17192d2afd52aeba88c71ae4959a015f56a38 (diff) | |
download | linux-e3197d83d6f5b9bd0e57a05592437ffa459ee106.tar.bz2 |
saner umount_tree()/release_mounts(), part 1
global list of release_mounts() fodder, protected by namespace_sem;
eventually, all umount_tree() callers will use it as kill list.
Helper picking the contents of that list, releasing namespace_sem
and doing release_mounts() on what it got.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/namespace.c | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index d7bb5a55cf36..0d91711a3160 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1119,6 +1119,8 @@ int may_umount(struct vfsmount *mnt) EXPORT_SYMBOL(may_umount); +static LIST_HEAD(unmounted); /* protected by namespace_sem */ + void release_mounts(struct list_head *head) { struct mount *mnt; @@ -1143,6 +1145,14 @@ void release_mounts(struct list_head *head) } } +static void namespace_unlock(void) +{ + LIST_HEAD(head); + list_splice_init(&unmounted, &head); + up_write(&namespace_sem); + release_mounts(&head); +} + /* * vfsmount lock must be held for write * namespace_sem must be held for write @@ -1252,17 +1262,16 @@ static int do_umount(struct mount *mnt, int flags) event++; if (!(flags & MNT_DETACH)) - shrink_submounts(mnt, &umount_list); + shrink_submounts(mnt, &unmounted); retval = -EBUSY; if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { if (!list_empty(&mnt->mnt_list)) - umount_tree(mnt, 1, &umount_list); + umount_tree(mnt, 1, &unmounted); retval = 0; } br_write_unlock(&vfsmount_lock); - up_write(&namespace_sem); - release_mounts(&umount_list); + namespace_unlock(); return retval; } |