Commit d63ff28f authored by Al Viro's avatar Al Viro

namei: make should_follow_link() store the link in nd->link

... if it decides to follow, that is.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 4693a547
...@@ -1566,15 +1566,31 @@ static void terminate_walk(struct nameidata *nd) ...@@ -1566,15 +1566,31 @@ static void terminate_walk(struct nameidata *nd)
put_link(nd); put_link(nd);
} }
static int pick_link(struct nameidata *nd, struct path *link)
{
if (nd->flags & LOOKUP_RCU) {
if (unlikely(nd->path.mnt != link->mnt ||
unlazy_walk(nd, link->dentry))) {
return -ECHILD;
}
}
nd->link = *link;
return 1;
}
/* /*
* Do we need to follow links? We _really_ want to be able * Do we need to follow links? We _really_ want to be able
* to do this check without having to look at inode->i_op, * to do this check without having to look at inode->i_op,
* so we keep a cache of "no, this doesn't need follow_link" * so we keep a cache of "no, this doesn't need follow_link"
* for the common case. * for the common case.
*/ */
static inline int should_follow_link(struct dentry *dentry, int follow) static inline int should_follow_link(struct nameidata *nd, struct path *link, int follow)
{ {
return unlikely(d_is_symlink(dentry)) ? follow : 0; if (likely(!d_is_symlink(link->dentry)))
return 0;
if (!follow)
return 0;
return pick_link(nd, link);
} }
enum {WALK_GET = 1, WALK_PUT = 2}; enum {WALK_GET = 1, WALK_PUT = 2};
...@@ -1612,17 +1628,9 @@ static int walk_component(struct nameidata *nd, int flags) ...@@ -1612,17 +1628,9 @@ static int walk_component(struct nameidata *nd, int flags)
if (flags & WALK_PUT) if (flags & WALK_PUT)
put_link(nd); put_link(nd);
if (should_follow_link(path.dentry, flags & WALK_GET)) { err = should_follow_link(nd, &path, flags & WALK_GET);
if (nd->flags & LOOKUP_RCU) { if (unlikely(err))
if (unlikely(nd->path.mnt != path.mnt || return err;
unlazy_walk(nd, path.dentry))) {
return -ECHILD;
}
}
BUG_ON(inode != path.dentry->d_inode);
nd->link = path;
return 1;
}
path_to_nameidata(&path, nd); path_to_nameidata(&path, nd);
nd->inode = inode; nd->inode = inode;
return 0; return 0;
...@@ -2375,9 +2383,11 @@ mountpoint_last(struct nameidata *nd, struct path *path) ...@@ -2375,9 +2383,11 @@ mountpoint_last(struct nameidata *nd, struct path *path)
put_link(nd); put_link(nd);
path->dentry = dentry; path->dentry = dentry;
path->mnt = nd->path.mnt; path->mnt = nd->path.mnt;
if (should_follow_link(dentry, nd->flags & LOOKUP_FOLLOW)) { error = should_follow_link(nd, path, nd->flags & LOOKUP_FOLLOW);
nd->link = *path; if (unlikely(error)) {
return 1; if (error < 0)
goto out;
return error;
} }
mntget(path->mnt); mntget(path->mnt);
follow_mount(path); follow_mount(path);
...@@ -3095,19 +3105,13 @@ static int do_last(struct nameidata *nd, ...@@ -3095,19 +3105,13 @@ static int do_last(struct nameidata *nd,
goto out; goto out;
} }
finish_lookup: finish_lookup:
if (should_follow_link(path.dentry, nd->flags & LOOKUP_FOLLOW)) {
if (nd->flags & LOOKUP_RCU) {
if (unlikely(nd->path.mnt != path.mnt ||
unlazy_walk(nd, path.dentry))) {
error = -ECHILD;
goto out;
}
}
BUG_ON(inode != path.dentry->d_inode);
if (nd->depth) if (nd->depth)
put_link(nd); put_link(nd);
nd->link = path; error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW);
return 1; if (unlikely(error)) {
if (error < 0)
goto out;
return error;
} }
if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) { if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) {
......
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