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 | |
| parent | 59eda0e07f43c950d31756213b607af673e551f0 (diff) | |
switch the IO-triggering parts of umount to fs_pin
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/fs_pin.c | 1 | ||||
| -rw-r--r-- | fs/mount.h | 4 | ||||
| -rw-r--r-- | fs/namespace.c | 44 |
3 files changed, 20 insertions, 29 deletions
diff --git a/fs/fs_pin.c b/fs/fs_pin.c index 0c77bdc238b2..b06c98796afb 100644 --- a/fs/fs_pin.c +++ b/fs/fs_pin.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | #include <linux/fs.h> | 1 | #include <linux/fs.h> |
| 2 | #include <linux/sched.h> | 2 | #include <linux/sched.h> |
| 3 | #include <linux/slab.h> | 3 | #include <linux/slab.h> |
| 4 | #include <linux/fs_pin.h> | ||
| 5 | #include "internal.h" | 4 | #include "internal.h" |
| 6 | #include "mount.h" | 5 | #include "mount.h" |
| 7 | 6 | ||
diff --git a/fs/mount.h b/fs/mount.h index 0ad6f760ce52..6a61c2b3e385 100644 --- a/fs/mount.h +++ b/fs/mount.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #include <linux/seq_file.h> | 2 | #include <linux/seq_file.h> |
| 3 | #include <linux/poll.h> | 3 | #include <linux/poll.h> |
| 4 | #include <linux/ns_common.h> | 4 | #include <linux/ns_common.h> |
| 5 | #include <linux/fs_pin.h> | ||
| 5 | 6 | ||
| 6 | struct mnt_namespace { | 7 | struct mnt_namespace { |
| 7 | atomic_t count; | 8 | atomic_t count; |
| @@ -62,7 +63,8 @@ struct mount { | |||
| 62 | int mnt_group_id; /* peer group identifier */ | 63 | int mnt_group_id; /* peer group identifier */ |
| 63 | int mnt_expiry_mark; /* true if marked for expiry */ | 64 | int mnt_expiry_mark; /* true if marked for expiry */ |
| 64 | struct hlist_head mnt_pins; | 65 | struct hlist_head mnt_pins; |
| 65 | struct path mnt_ex_mountpoint; | 66 | struct fs_pin mnt_umount; |
| 67 | struct dentry *mnt_ex_mountpoint; | ||
| 66 | }; | 68 | }; |
| 67 | 69 | ||
| 68 | #define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */ | 70 | #define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */ |
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 | ||
