diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-01-10 19:01:08 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-01-25 23:17:29 -0500 |
commit | 87b95ce0964c016ede92763be9c164e49f1019e9 (patch) | |
tree | 168ea89fd898a2a0c70601d252171fc1a76f15f9 /fs/namespace.c | |
parent | 59eda0e07f43c950d31756213b607af673e551f0 (diff) |
switch the IO-triggering parts of umount to fs_pin
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 44 |
1 files changed, 17 insertions, 27 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index cd1e9681a0cf..4a985ff0ddfc 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -190,6 +190,14 @@ unsigned int mnt_get_count(struct mount *mnt) | |||
190 | #endif | 190 | #endif |
191 | } | 191 | } |
192 | 192 | ||
193 | static void drop_mountpoint(struct fs_pin *p) | ||
194 | { | ||
195 | struct mount *m = container_of(p, struct mount, mnt_umount); | ||
196 | dput(m->mnt_ex_mountpoint); | ||
197 | pin_remove(p); | ||
198 | mntput(&m->mnt); | ||
199 | } | ||
200 | |||
193 | static struct mount *alloc_vfsmnt(const char *name) | 201 | static struct mount *alloc_vfsmnt(const char *name) |
194 | { | 202 | { |
195 | struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); | 203 | struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); |
@@ -229,6 +237,7 @@ static struct mount *alloc_vfsmnt(const char *name) | |||
229 | #ifdef CONFIG_FSNOTIFY | 237 | #ifdef CONFIG_FSNOTIFY |
230 | INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); | 238 | INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); |
231 | #endif | 239 | #endif |
240 | init_fs_pin(&mnt->mnt_umount, drop_mountpoint); | ||
232 | } | 241 | } |
233 | return mnt; | 242 | return mnt; |
234 | 243 | ||
@@ -1289,7 +1298,6 @@ static HLIST_HEAD(unmounted); /* protected by namespace_sem */ | |||
1289 | 1298 | ||
1290 | static void namespace_unlock(void) | 1299 | static void namespace_unlock(void) |
1291 | { | 1300 | { |
1292 | struct mount *mnt; | ||
1293 | struct hlist_head head = unmounted; | 1301 | struct hlist_head head = unmounted; |
1294 | 1302 | ||
1295 | if (likely(hlist_empty(&head))) { | 1303 | if (likely(hlist_empty(&head))) { |
@@ -1299,23 +1307,11 @@ static void namespace_unlock(void) | |||
1299 | 1307 | ||
1300 | head.first->pprev = &head.first; | 1308 | head.first->pprev = &head.first; |
1301 | INIT_HLIST_HEAD(&unmounted); | 1309 | INIT_HLIST_HEAD(&unmounted); |
1302 | |||
1303 | /* undo decrements we'd done in umount_tree() */ | ||
1304 | hlist_for_each_entry(mnt, &head, mnt_hash) | ||
1305 | if (mnt->mnt_ex_mountpoint.mnt) | ||
1306 | mntget(mnt->mnt_ex_mountpoint.mnt); | ||
1307 | |||
1308 | up_write(&namespace_sem); | 1310 | up_write(&namespace_sem); |
1309 | 1311 | ||
1310 | synchronize_rcu(); | 1312 | synchronize_rcu(); |
1311 | 1313 | ||
1312 | while (!hlist_empty(&head)) { | 1314 | group_pin_kill(&head); |
1313 | mnt = hlist_entry(head.first, struct mount, mnt_hash); | ||
1314 | hlist_del_init(&mnt->mnt_hash); | ||
1315 | if (mnt->mnt_ex_mountpoint.mnt) | ||
1316 | path_put(&mnt->mnt_ex_mountpoint); | ||
1317 | mntput(&mnt->mnt); | ||
1318 | } | ||
1319 | } | 1315 | } |
1320 | 1316 | ||
1321 | static inline void namespace_lock(void) | 1317 | static inline void namespace_lock(void) |
@@ -1334,7 +1330,6 @@ void umount_tree(struct mount *mnt, int how) | |||
1334 | { | 1330 | { |
1335 | HLIST_HEAD(tmp_list); | 1331 | HLIST_HEAD(tmp_list); |
1336 | struct mount *p; | 1332 | struct mount *p; |
1337 | struct mount *last = NULL; | ||
1338 | 1333 | ||
1339 | for (p = mnt; p; p = next_mnt(p, mnt)) { | 1334 | for (p = mnt; p; p = next_mnt(p, mnt)) { |
1340 | hlist_del_init_rcu(&p->mnt_hash); | 1335 | hlist_del_init_rcu(&p->mnt_hash); |
@@ -1347,33 +1342,28 @@ void umount_tree(struct mount *mnt, int how) | |||
1347 | if (how) | 1342 | if (how) |
1348 | propagate_umount(&tmp_list); | 1343 | propagate_umount(&tmp_list); |
1349 | 1344 | ||
1350 | hlist_for_each_entry(p, &tmp_list, mnt_hash) { | 1345 | while (!hlist_empty(&tmp_list)) { |
1346 | p = hlist_entry(tmp_list.first, struct mount, mnt_hash); | ||
1347 | hlist_del_init_rcu(&p->mnt_hash); | ||
1351 | list_del_init(&p->mnt_expire); | 1348 | list_del_init(&p->mnt_expire); |
1352 | list_del_init(&p->mnt_list); | 1349 | list_del_init(&p->mnt_list); |
1353 | __touch_mnt_namespace(p->mnt_ns); | 1350 | __touch_mnt_namespace(p->mnt_ns); |
1354 | p->mnt_ns = NULL; | 1351 | p->mnt_ns = NULL; |
1355 | if (how < 2) | 1352 | if (how < 2) |
1356 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; | 1353 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; |
1354 | |||
1355 | pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, &unmounted); | ||
1357 | if (mnt_has_parent(p)) { | 1356 | if (mnt_has_parent(p)) { |
1358 | hlist_del_init(&p->mnt_mp_list); | 1357 | hlist_del_init(&p->mnt_mp_list); |
1359 | put_mountpoint(p->mnt_mp); | 1358 | put_mountpoint(p->mnt_mp); |
1360 | mnt_add_count(p->mnt_parent, -1); | 1359 | mnt_add_count(p->mnt_parent, -1); |
1361 | /* move the reference to mountpoint into ->mnt_ex_mountpoint */ | 1360 | /* old mountpoint will be dropped when we can do that */ |
1362 | p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint; | 1361 | p->mnt_ex_mountpoint = p->mnt_mountpoint; |
1363 | p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt; | ||
1364 | p->mnt_mountpoint = p->mnt.mnt_root; | 1362 | p->mnt_mountpoint = p->mnt.mnt_root; |
1365 | p->mnt_parent = p; | 1363 | p->mnt_parent = p; |
1366 | p->mnt_mp = NULL; | 1364 | p->mnt_mp = NULL; |
1367 | } | 1365 | } |
1368 | change_mnt_propagation(p, MS_PRIVATE); | 1366 | change_mnt_propagation(p, MS_PRIVATE); |
1369 | last = p; | ||
1370 | } | ||
1371 | if (last) { | ||
1372 | last->mnt_hash.next = unmounted.first; | ||
1373 | if (unmounted.first) | ||
1374 | unmounted.first->pprev = &last->mnt_hash.next; | ||
1375 | unmounted.first = tmp_list.first; | ||
1376 | unmounted.first->pprev = &unmounted.first; | ||
1377 | } | 1367 | } |
1378 | } | 1368 | } |
1379 | 1369 | ||