diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-03-22 05:46:23 +0100 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-03-28 01:47:58 +0100 |
commit | c35038becad0adb0e25261fff66d85b1a6ddd0c2 (patch) | |
tree | 1d375d74ef5b4c3641768697b2ff8f4992916dc5 /fs/namespace.c | |
parent | [PATCH] sanitize locking in mark_mounts_for_expiry() and shrink_submounts() (diff) | |
download | linux-c35038becad0adb0e25261fff66d85b1a6ddd0c2.tar.xz linux-c35038becad0adb0e25261fff66d85b1a6ddd0c2.zip |
[PATCH] do shrink_submounts() for all fs types
... and take it out of ->umount_begin() instances. Call with all locks
already taken (by do_umount()) and leave calling release_mounts() to
caller (it will do release_mounts() anyway, so we can just put into
the same list).
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 23 |
1 files changed, 10 insertions, 13 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 1c78917ec930..7bd74b25930c 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -581,6 +581,8 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) } } +static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); + static int do_umount(struct vfsmount *mnt, int flags) { struct super_block *sb = mnt->mnt_sb; @@ -653,6 +655,9 @@ static int do_umount(struct vfsmount *mnt, int flags) spin_lock(&vfsmount_lock); event++; + if (!(flags & MNT_DETACH)) + shrink_submounts(mnt, &umount_list); + retval = -EBUSY; if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { if (!list_empty(&mnt->mnt_list)) @@ -1302,30 +1307,22 @@ resume: * process a list of expirable mountpoints with the intent of discarding any * submounts of a specific parent mountpoint */ -void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts) +static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts) { LIST_HEAD(graveyard); - LIST_HEAD(umounts); - struct vfsmount *mnt; + struct vfsmount *m; - down_write(&namespace_sem); - spin_lock(&vfsmount_lock); /* extract submounts of 'mountpoint' from the expiration list */ - while (select_submounts(mountpoint, &graveyard)) { + while (select_submounts(mnt, &graveyard)) { while (!list_empty(&graveyard)) { - mnt = list_first_entry(&graveyard, struct vfsmount, + m = list_first_entry(&graveyard, struct vfsmount, mnt_expire); touch_mnt_namespace(mnt->mnt_ns); - umount_tree(mnt, 1, &umounts); + umount_tree(mnt, 1, umounts); } } - spin_unlock(&vfsmount_lock); - up_write(&namespace_sem); - release_mounts(&umounts); } -EXPORT_SYMBOL_GPL(shrink_submounts); - /* * Some copy_from_user() implementations do not return the exact number of * bytes remaining to copy on a fault. But copy_mount_options() requires that. |