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 /fs | |
parent | 84d17192d2afd52aeba88c71ae4959a015f56a38 (diff) |
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>
Diffstat (limited to 'fs')
-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) | |||
1119 | 1119 | ||
1120 | EXPORT_SYMBOL(may_umount); | 1120 | EXPORT_SYMBOL(may_umount); |
1121 | 1121 | ||
1122 | static LIST_HEAD(unmounted); /* protected by namespace_sem */ | ||
1123 | |||
1122 | void release_mounts(struct list_head *head) | 1124 | void release_mounts(struct list_head *head) |
1123 | { | 1125 | { |
1124 | struct mount *mnt; | 1126 | struct mount *mnt; |
@@ -1143,6 +1145,14 @@ void release_mounts(struct list_head *head) | |||
1143 | } | 1145 | } |
1144 | } | 1146 | } |
1145 | 1147 | ||
1148 | static void namespace_unlock(void) | ||
1149 | { | ||
1150 | LIST_HEAD(head); | ||
1151 | list_splice_init(&unmounted, &head); | ||
1152 | up_write(&namespace_sem); | ||
1153 | release_mounts(&head); | ||
1154 | } | ||
1155 | |||
1146 | /* | 1156 | /* |
1147 | * vfsmount lock must be held for write | 1157 | * vfsmount lock must be held for write |
1148 | * namespace_sem must be held for write | 1158 | * namespace_sem must be held for write |
@@ -1252,17 +1262,16 @@ static int do_umount(struct mount *mnt, int flags) | |||
1252 | event++; | 1262 | event++; |
1253 | 1263 | ||
1254 | if (!(flags & MNT_DETACH)) | 1264 | if (!(flags & MNT_DETACH)) |
1255 | shrink_submounts(mnt, &umount_list); | 1265 | shrink_submounts(mnt, &unmounted); |
1256 | 1266 | ||
1257 | retval = -EBUSY; | 1267 | retval = -EBUSY; |
1258 | if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { | 1268 | if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { |
1259 | if (!list_empty(&mnt->mnt_list)) | 1269 | if (!list_empty(&mnt->mnt_list)) |
1260 | umount_tree(mnt, 1, &umount_list); | 1270 | umount_tree(mnt, 1, &unmounted); |
1261 | retval = 0; | 1271 | retval = 0; |
1262 | } | 1272 | } |
1263 | br_write_unlock(&vfsmount_lock); | 1273 | br_write_unlock(&vfsmount_lock); |
1264 | up_write(&namespace_sem); | 1274 | namespace_unlock(); |
1265 | release_mounts(&umount_list); | ||
1266 | return retval; | 1275 | return retval; |
1267 | } | 1276 | } |
1268 | 1277 | ||