Commit 474279dc authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 7eb5e882
...@@ -77,7 +77,8 @@ static inline int is_mounted(struct vfsmount *mnt) ...@@ -77,7 +77,8 @@ static inline int is_mounted(struct vfsmount *mnt)
return !IS_ERR_OR_NULL(real_mount(mnt)); return !IS_ERR_OR_NULL(real_mount(mnt));
} }
extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *, int); extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *);
extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
static inline void get_mnt_ns(struct mnt_namespace *ns) static inline void get_mnt_ns(struct mnt_namespace *ns)
{ {
......
...@@ -1111,7 +1111,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, ...@@ -1111,7 +1111,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
if (!d_mountpoint(path->dentry)) if (!d_mountpoint(path->dentry))
break; break;
mounted = __lookup_mnt(path->mnt, path->dentry, 1); mounted = __lookup_mnt(path->mnt, path->dentry);
if (!mounted) if (!mounted)
break; break;
path->mnt = &mounted->mnt; path->mnt = &mounted->mnt;
...@@ -1132,7 +1132,7 @@ static void follow_mount_rcu(struct nameidata *nd) ...@@ -1132,7 +1132,7 @@ static void follow_mount_rcu(struct nameidata *nd)
{ {
while (d_mountpoint(nd->path.dentry)) { while (d_mountpoint(nd->path.dentry)) {
struct mount *mounted; struct mount *mounted;
mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1); mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
if (!mounted) if (!mounted)
break; break;
nd->path.mnt = &mounted->mnt; nd->path.mnt = &mounted->mnt;
......
...@@ -548,29 +548,33 @@ static void free_vfsmnt(struct mount *mnt) ...@@ -548,29 +548,33 @@ static void free_vfsmnt(struct mount *mnt)
} }
/* /*
* find the first or last mount at @dentry on vfsmount @mnt depending on * find the first mount at @dentry on vfsmount @mnt.
* @dir. If @dir is set return the first mount else return the last mount.
* vfsmount_lock must be held for read or write. * vfsmount_lock must be held for read or write.
*/ */
struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
int dir)
{ {
struct list_head *head = mount_hashtable + hash(mnt, dentry); struct list_head *head = mount_hashtable + hash(mnt, dentry);
struct list_head *tmp = head; struct mount *p;
struct mount *p, *found = NULL;
for (;;) { list_for_each_entry(p, head, mnt_hash)
tmp = dir ? tmp->next : tmp->prev; if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)
p = NULL; return p;
if (tmp == head) return NULL;
break; }
p = list_entry(tmp, struct mount, mnt_hash);
if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) { /*
found = p; * find the last mount at @dentry on vfsmount @mnt.
break; * vfsmount_lock must be held for read or write.
} */
} struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry)
return found; {
struct list_head *head = mount_hashtable + hash(mnt, dentry);
struct mount *p;
list_for_each_entry_reverse(p, head, mnt_hash)
if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)
return p;
return NULL;
} }
/* /*
...@@ -594,7 +598,7 @@ struct vfsmount *lookup_mnt(struct path *path) ...@@ -594,7 +598,7 @@ struct vfsmount *lookup_mnt(struct path *path)
struct mount *child_mnt; struct mount *child_mnt;
br_read_lock(&vfsmount_lock); br_read_lock(&vfsmount_lock);
child_mnt = __lookup_mnt(path->mnt, path->dentry, 1); child_mnt = __lookup_mnt(path->mnt, path->dentry);
if (child_mnt) { if (child_mnt) {
mnt_add_count(child_mnt, 1); mnt_add_count(child_mnt, 1);
br_read_unlock(&vfsmount_lock); br_read_unlock(&vfsmount_lock);
......
...@@ -310,7 +310,7 @@ int propagate_mount_busy(struct mount *mnt, int refcnt) ...@@ -310,7 +310,7 @@ int propagate_mount_busy(struct mount *mnt, int refcnt)
for (m = propagation_next(parent, parent); m; for (m = propagation_next(parent, parent); m;
m = propagation_next(m, parent)) { m = propagation_next(m, parent)) {
child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint, 0); child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
if (child && list_empty(&child->mnt_mounts) && if (child && list_empty(&child->mnt_mounts) &&
(ret = do_refcount_check(child, 1))) (ret = do_refcount_check(child, 1)))
break; break;
...@@ -332,8 +332,8 @@ static void __propagate_umount(struct mount *mnt) ...@@ -332,8 +332,8 @@ static void __propagate_umount(struct mount *mnt)
for (m = propagation_next(parent, parent); m; for (m = propagation_next(parent, parent); m;
m = propagation_next(m, parent)) { m = propagation_next(m, parent)) {
struct mount *child = __lookup_mnt(&m->mnt, struct mount *child = __lookup_mnt_last(&m->mnt,
mnt->mnt_mountpoint, 0); mnt->mnt_mountpoint);
/* /*
* umount the child only if the child has no * umount the child only if the child has no
* other children * other children
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment