Commit c2df1968 authored by Al Viro's avatar Al Viro

lift all calls of step_into() out of follow_dotdot/follow_dotdot_rcu

lift step_into() into handle_dots() (where they merge with each other);
have follow_... return dentry and pass inode/seq to the caller.

[braino fix folded; kudos to Qian Cai <cai@lca.pw> for reporting it]
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6dfd9fe5
...@@ -1687,31 +1687,29 @@ static const char *step_into(struct nameidata *nd, int flags, ...@@ -1687,31 +1687,29 @@ static const char *step_into(struct nameidata *nd, int flags,
return pick_link(nd, &path, inode, seq, flags); return pick_link(nd, &path, inode, seq, flags);
} }
static const char *follow_dotdot_rcu(struct nameidata *nd) static struct dentry *follow_dotdot_rcu(struct nameidata *nd,
struct inode **inodep,
unsigned *seqp)
{ {
struct dentry *parent = NULL;
struct inode *inode = nd->inode;
unsigned seq;
while (1) { while (1) {
if (path_equal(&nd->path, &nd->root)) if (path_equal(&nd->path, &nd->root))
break; break;
if (nd->path.dentry != nd->path.mnt->mnt_root) { if (nd->path.dentry != nd->path.mnt->mnt_root) {
struct dentry *old = nd->path.dentry; struct dentry *old = nd->path.dentry;
struct dentry *parent = old->d_parent;
parent = old->d_parent; *inodep = parent->d_inode;
inode = parent->d_inode; *seqp = read_seqcount_begin(&parent->d_seq);
seq = read_seqcount_begin(&parent->d_seq);
if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq))) if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
if (unlikely(!path_connected(nd->path.mnt, parent))) if (unlikely(!path_connected(nd->path.mnt, parent)))
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
break; return parent;
} else { } else {
struct mount *mnt = real_mount(nd->path.mnt); struct mount *mnt = real_mount(nd->path.mnt);
struct mount *mparent = mnt->mnt_parent; struct mount *mparent = mnt->mnt_parent;
struct dentry *mountpoint = mnt->mnt_mountpoint; struct dentry *mountpoint = mnt->mnt_mountpoint;
struct inode *inode2 = mountpoint->d_inode; struct inode *inode = mountpoint->d_inode;
unsigned seq = read_seqcount_begin(&mountpoint->d_seq); unsigned seq = read_seqcount_begin(&mountpoint->d_seq);
if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
...@@ -1722,54 +1720,51 @@ static const char *follow_dotdot_rcu(struct nameidata *nd) ...@@ -1722,54 +1720,51 @@ static const char *follow_dotdot_rcu(struct nameidata *nd)
/* we know that mountpoint was pinned */ /* we know that mountpoint was pinned */
nd->path.dentry = mountpoint; nd->path.dentry = mountpoint;
nd->path.mnt = &mparent->mnt; nd->path.mnt = &mparent->mnt;
inode = nd->inode = inode2; nd->inode = inode;
nd->seq = seq; nd->seq = seq;
} }
} }
if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH))
if (unlikely(nd->flags & LOOKUP_BENEATH)) return ERR_PTR(-ECHILD);
return ERR_PTR(-ECHILD); return NULL;
return step_into(nd, WALK_NOFOLLOW,
nd->path.dentry, nd->inode, nd->seq);
} else {
return step_into(nd, WALK_NOFOLLOW, parent, inode, seq);
}
} }
static const char *follow_dotdot(struct nameidata *nd) static struct dentry *follow_dotdot(struct nameidata *nd,
struct inode **inodep,
unsigned *seqp)
{ {
struct dentry *parent = NULL;
while (1) { while (1) {
if (path_equal(&nd->path, &nd->root)) if (path_equal(&nd->path, &nd->root))
break; break;
if (nd->path.dentry != nd->path.mnt->mnt_root) { if (nd->path.dentry != nd->path.mnt->mnt_root) {
/* rare case of legitimate dget_parent()... */ /* rare case of legitimate dget_parent()... */
parent = dget_parent(nd->path.dentry); struct dentry *parent = dget_parent(nd->path.dentry);
if (unlikely(!path_connected(nd->path.mnt, parent))) { if (unlikely(!path_connected(nd->path.mnt, parent))) {
dput(parent); dput(parent);
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
break; *seqp = 0;
*inodep = parent->d_inode;
return parent;
} }
if (!follow_up(&nd->path)) if (!follow_up(&nd->path))
break; break;
if (unlikely(nd->flags & LOOKUP_NO_XDEV)) if (unlikely(nd->flags & LOOKUP_NO_XDEV))
return ERR_PTR(-EXDEV); return ERR_PTR(-EXDEV);
} }
if (unlikely(!parent)) { if (unlikely(nd->flags & LOOKUP_BENEATH))
if (unlikely(nd->flags & LOOKUP_BENEATH)) return ERR_PTR(-EXDEV);
return ERR_PTR(-EXDEV); dget(nd->path.dentry);
return step_into(nd, WALK_NOFOLLOW, return NULL;
dget(nd->path.dentry), nd->inode, nd->seq);
} else {
return step_into(nd, WALK_NOFOLLOW, parent, parent->d_inode, 0);
}
} }
static const char *handle_dots(struct nameidata *nd, int type) static const char *handle_dots(struct nameidata *nd, int type)
{ {
if (type == LAST_DOTDOT) { if (type == LAST_DOTDOT) {
const char *error = NULL; const char *error = NULL;
struct dentry *parent;
struct inode *inode;
unsigned seq;
if (!nd->root.mnt) { if (!nd->root.mnt) {
error = ERR_PTR(set_root(nd)); error = ERR_PTR(set_root(nd));
...@@ -1777,10 +1772,18 @@ static const char *handle_dots(struct nameidata *nd, int type) ...@@ -1777,10 +1772,18 @@ static const char *handle_dots(struct nameidata *nd, int type)
return error; return error;
} }
if (nd->flags & LOOKUP_RCU) if (nd->flags & LOOKUP_RCU)
error = follow_dotdot_rcu(nd); parent = follow_dotdot_rcu(nd, &inode, &seq);
else else
error = follow_dotdot(nd); parent = follow_dotdot(nd, &inode, &seq);
if (error) if (IS_ERR(parent))
return ERR_CAST(parent);
if (unlikely(!parent))
error = step_into(nd, WALK_NOFOLLOW,
nd->path.dentry, nd->inode, nd->seq);
else
error = step_into(nd, WALK_NOFOLLOW,
parent, inode, seq);
if (unlikely(error))
return error; return error;
if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) { if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) {
......
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