diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-10-01 16:11:26 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-10-24 23:35:00 -0400 |
commit | 474279dc0f7745124fc76b474c8dc1294f8e87ce (patch) | |
tree | 2ad5e963e698e9524e0eabe466534f03ce324226 /fs | |
parent | 7eb5e8826911f2792179f99e77e75fbb7ef53a4a (diff) |
split __lookup_mnt() in two functions
Instead of passing the direction as argument (and checking it on every
step through the hash chain), just have separate __lookup_mnt() and
__lookup_mnt_last(). And use the standard iterators...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/mount.h | 3 | ||||
-rw-r--r-- | fs/namei.c | 4 | ||||
-rw-r--r-- | fs/namespace.c | 42 | ||||
-rw-r--r-- | fs/pnode.c | 6 |
4 files changed, 30 insertions, 25 deletions
diff --git a/fs/mount.h b/fs/mount.h index 7076f25af35d..f0866076de6e 100644 --- a/fs/mount.h +++ b/fs/mount.h | |||
@@ -77,7 +77,8 @@ static inline int is_mounted(struct vfsmount *mnt) | |||
77 | return !IS_ERR_OR_NULL(real_mount(mnt)); | 77 | return !IS_ERR_OR_NULL(real_mount(mnt)); |
78 | } | 78 | } |
79 | 79 | ||
80 | extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *, int); | 80 | extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *); |
81 | extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *); | ||
81 | 82 | ||
82 | static inline void get_mnt_ns(struct mnt_namespace *ns) | 83 | static inline void get_mnt_ns(struct mnt_namespace *ns) |
83 | { | 84 | { |
diff --git a/fs/namei.c b/fs/namei.c index 645268f23eb6..1f844fbfce72 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1111,7 +1111,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
1111 | if (!d_mountpoint(path->dentry)) | 1111 | if (!d_mountpoint(path->dentry)) |
1112 | break; | 1112 | break; |
1113 | 1113 | ||
1114 | mounted = __lookup_mnt(path->mnt, path->dentry, 1); | 1114 | mounted = __lookup_mnt(path->mnt, path->dentry); |
1115 | if (!mounted) | 1115 | if (!mounted) |
1116 | break; | 1116 | break; |
1117 | path->mnt = &mounted->mnt; | 1117 | path->mnt = &mounted->mnt; |
@@ -1132,7 +1132,7 @@ static void follow_mount_rcu(struct nameidata *nd) | |||
1132 | { | 1132 | { |
1133 | while (d_mountpoint(nd->path.dentry)) { | 1133 | while (d_mountpoint(nd->path.dentry)) { |
1134 | struct mount *mounted; | 1134 | struct mount *mounted; |
1135 | mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1); | 1135 | mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry); |
1136 | if (!mounted) | 1136 | if (!mounted) |
1137 | break; | 1137 | break; |
1138 | nd->path.mnt = &mounted->mnt; | 1138 | nd->path.mnt = &mounted->mnt; |
diff --git a/fs/namespace.c b/fs/namespace.c index 5cbe8cefadb5..500202ce10db 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -548,29 +548,33 @@ static void free_vfsmnt(struct mount *mnt) | |||
548 | } | 548 | } |
549 | 549 | ||
550 | /* | 550 | /* |
551 | * find the first or last mount at @dentry on vfsmount @mnt depending on | 551 | * find the first mount at @dentry on vfsmount @mnt. |
552 | * @dir. If @dir is set return the first mount else return the last mount. | ||
553 | * vfsmount_lock must be held for read or write. | 552 | * vfsmount_lock must be held for read or write. |
554 | */ | 553 | */ |
555 | struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, | 554 | struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) |
556 | int dir) | ||
557 | { | 555 | { |
558 | struct list_head *head = mount_hashtable + hash(mnt, dentry); | 556 | struct list_head *head = mount_hashtable + hash(mnt, dentry); |
559 | struct list_head *tmp = head; | 557 | struct mount *p; |
560 | struct mount *p, *found = NULL; | ||
561 | 558 | ||
562 | for (;;) { | 559 | list_for_each_entry(p, head, mnt_hash) |
563 | tmp = dir ? tmp->next : tmp->prev; | 560 | if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) |
564 | p = NULL; | 561 | return p; |
565 | if (tmp == head) | 562 | return NULL; |
566 | break; | 563 | } |
567 | p = list_entry(tmp, struct mount, mnt_hash); | 564 | |
568 | if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) { | 565 | /* |
569 | found = p; | 566 | * find the last mount at @dentry on vfsmount @mnt. |
570 | break; | 567 | * vfsmount_lock must be held for read or write. |
571 | } | 568 | */ |
572 | } | 569 | struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) |
573 | return found; | 570 | { |
571 | struct list_head *head = mount_hashtable + hash(mnt, dentry); | ||
572 | struct mount *p; | ||
573 | |||
574 | list_for_each_entry_reverse(p, head, mnt_hash) | ||
575 | if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) | ||
576 | return p; | ||
577 | return NULL; | ||
574 | } | 578 | } |
575 | 579 | ||
576 | /* | 580 | /* |
@@ -594,7 +598,7 @@ struct vfsmount *lookup_mnt(struct path *path) | |||
594 | struct mount *child_mnt; | 598 | struct mount *child_mnt; |
595 | 599 | ||
596 | br_read_lock(&vfsmount_lock); | 600 | br_read_lock(&vfsmount_lock); |
597 | child_mnt = __lookup_mnt(path->mnt, path->dentry, 1); | 601 | child_mnt = __lookup_mnt(path->mnt, path->dentry); |
598 | if (child_mnt) { | 602 | if (child_mnt) { |
599 | mnt_add_count(child_mnt, 1); | 603 | mnt_add_count(child_mnt, 1); |
600 | br_read_unlock(&vfsmount_lock); | 604 | br_read_unlock(&vfsmount_lock); |
diff --git a/fs/pnode.c b/fs/pnode.c index 58933fd149ad..c7221bb19801 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -310,7 +310,7 @@ int propagate_mount_busy(struct mount *mnt, int refcnt) | |||
310 | 310 | ||
311 | for (m = propagation_next(parent, parent); m; | 311 | for (m = propagation_next(parent, parent); m; |
312 | m = propagation_next(m, parent)) { | 312 | m = propagation_next(m, parent)) { |
313 | child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint, 0); | 313 | child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint); |
314 | if (child && list_empty(&child->mnt_mounts) && | 314 | if (child && list_empty(&child->mnt_mounts) && |
315 | (ret = do_refcount_check(child, 1))) | 315 | (ret = do_refcount_check(child, 1))) |
316 | break; | 316 | break; |
@@ -332,8 +332,8 @@ static void __propagate_umount(struct mount *mnt) | |||
332 | for (m = propagation_next(parent, parent); m; | 332 | for (m = propagation_next(parent, parent); m; |
333 | m = propagation_next(m, parent)) { | 333 | m = propagation_next(m, parent)) { |
334 | 334 | ||
335 | struct mount *child = __lookup_mnt(&m->mnt, | 335 | struct mount *child = __lookup_mnt_last(&m->mnt, |
336 | mnt->mnt_mountpoint, 0); | 336 | mnt->mnt_mountpoint); |
337 | /* | 337 | /* |
338 | * umount the child only if the child has no | 338 | * umount the child only if the child has no |
339 | * other children | 339 | * other children |