diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-03-22 00:46:23 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-03-27 20:47:58 -0400 |
commit | c35038becad0adb0e25261fff66d85b1a6ddd0c2 (patch) | |
tree | 1d375d74ef5b4c3641768697b2ff8f4992916dc5 /fs/namespace.c | |
parent | bcc5c7d2b692e5319db00b0dd020ce98723103b1 (diff) |
[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) | |||
581 | } | 581 | } |
582 | } | 582 | } |
583 | 583 | ||
584 | static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); | ||
585 | |||
584 | static int do_umount(struct vfsmount *mnt, int flags) | 586 | static int do_umount(struct vfsmount *mnt, int flags) |
585 | { | 587 | { |
586 | struct super_block *sb = mnt->mnt_sb; | 588 | struct super_block *sb = mnt->mnt_sb; |
@@ -653,6 +655,9 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
653 | spin_lock(&vfsmount_lock); | 655 | spin_lock(&vfsmount_lock); |
654 | event++; | 656 | event++; |
655 | 657 | ||
658 | if (!(flags & MNT_DETACH)) | ||
659 | shrink_submounts(mnt, &umount_list); | ||
660 | |||
656 | retval = -EBUSY; | 661 | retval = -EBUSY; |
657 | if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { | 662 | if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { |
658 | if (!list_empty(&mnt->mnt_list)) | 663 | if (!list_empty(&mnt->mnt_list)) |
@@ -1302,30 +1307,22 @@ resume: | |||
1302 | * process a list of expirable mountpoints with the intent of discarding any | 1307 | * process a list of expirable mountpoints with the intent of discarding any |
1303 | * submounts of a specific parent mountpoint | 1308 | * submounts of a specific parent mountpoint |
1304 | */ | 1309 | */ |
1305 | void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts) | 1310 | static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts) |
1306 | { | 1311 | { |
1307 | LIST_HEAD(graveyard); | 1312 | LIST_HEAD(graveyard); |
1308 | LIST_HEAD(umounts); | 1313 | struct vfsmount *m; |
1309 | struct vfsmount *mnt; | ||
1310 | 1314 | ||
1311 | down_write(&namespace_sem); | ||
1312 | spin_lock(&vfsmount_lock); | ||
1313 | /* extract submounts of 'mountpoint' from the expiration list */ | 1315 | /* extract submounts of 'mountpoint' from the expiration list */ |
1314 | while (select_submounts(mountpoint, &graveyard)) { | 1316 | while (select_submounts(mnt, &graveyard)) { |
1315 | while (!list_empty(&graveyard)) { | 1317 | while (!list_empty(&graveyard)) { |
1316 | mnt = list_first_entry(&graveyard, struct vfsmount, | 1318 | m = list_first_entry(&graveyard, struct vfsmount, |
1317 | mnt_expire); | 1319 | mnt_expire); |
1318 | touch_mnt_namespace(mnt->mnt_ns); | 1320 | touch_mnt_namespace(mnt->mnt_ns); |
1319 | umount_tree(mnt, 1, &umounts); | 1321 | umount_tree(mnt, 1, umounts); |
1320 | } | 1322 | } |
1321 | } | 1323 | } |
1322 | spin_unlock(&vfsmount_lock); | ||
1323 | up_write(&namespace_sem); | ||
1324 | release_mounts(&umounts); | ||
1325 | } | 1324 | } |
1326 | 1325 | ||
1327 | EXPORT_SYMBOL_GPL(shrink_submounts); | ||
1328 | |||
1329 | /* | 1326 | /* |
1330 | * Some copy_from_user() implementations do not return the exact number of | 1327 | * Some copy_from_user() implementations do not return the exact number of |
1331 | * bytes remaining to copy on a fault. But copy_mount_options() requires that. | 1328 | * bytes remaining to copy on a fault. But copy_mount_options() requires that. |