namei: lift link_path_walk() call out of trailing_symlink()

Make trailing_symlink() return the pathname to traverse or ERR_PTR(-E...).
A subtle point is that for "magic" symlinks it returns "" now - that
leads to link_path_walk("", nd), which is immediately returning 0 and
we are back to the treatment of the last component, at whereever the
damn thing has left us.

Reduces the stack footprint - link_path_walk() called on more shallow
stack now.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2015-05-08 17:37:07 -04:00
parent 368ee9ba56
commit 3bdba28b72

View File

@ -1970,24 +1970,24 @@ static void path_cleanup(struct nameidata *nd)
}
}
static int trailing_symlink(struct nameidata *nd)
static const char *trailing_symlink(struct nameidata *nd)
{
const char *s;
int error = may_follow_link(nd);
if (unlikely(error)) {
terminate_walk(nd);
return error;
return ERR_PTR(error);
}
nd->flags |= LOOKUP_PARENT;
nd->stack[0].name = NULL;
s = get_link(nd);
if (unlikely(IS_ERR(s))) {
terminate_walk(nd);
return PTR_ERR(s);
return s;
}
if (unlikely(!s))
return 0;
return link_path_walk(s, nd);
s = "";
return s;
}
static inline int lookup_last(struct nameidata *nd)
@ -2017,12 +2017,12 @@ static int path_lookupat(int dfd, const struct filename *name,
if (IS_ERR(s))
return PTR_ERR(s);
err = link_path_walk(s, nd);
if (!err) {
while ((err = lookup_last(nd)) > 0) {
err = trailing_symlink(nd);
if (err)
break;
while (!(err = link_path_walk(s, nd))
&& ((err = lookup_last(nd)) > 0)) {
s = trailing_symlink(nd);
if (IS_ERR(s)) {
err = PTR_ERR(s);
break;
}
}
@ -2401,16 +2401,14 @@ path_mountpoint(int dfd, const struct filename *name, struct path *path,
int err;
if (IS_ERR(s))
return PTR_ERR(s);
err = link_path_walk(s, nd);
if (unlikely(err))
goto out;
while ((err = mountpoint_last(nd, path)) > 0) {
err = trailing_symlink(nd);
if (err)
while (!(err = link_path_walk(s, nd)) &&
(err = mountpoint_last(nd, path)) > 0) {
s = trailing_symlink(nd);
if (IS_ERR(s)) {
err = PTR_ERR(s);
break;
}
}
out:
path_cleanup(nd);
return err;
}
@ -3282,17 +3280,15 @@ static struct file *path_openat(int dfd, struct filename *pathname,
put_filp(file);
return ERR_CAST(s);
}
error = link_path_walk(s, nd);
if (unlikely(error))
goto out;
while ((error = do_last(nd, file, op, &opened, pathname)) > 0) {
while (!(error = link_path_walk(s, nd)) &&
(error = do_last(nd, file, op, &opened, pathname)) > 0) {
nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
error = trailing_symlink(nd);
if (unlikely(error))
s = trailing_symlink(nd);
if (IS_ERR(s)) {
error = PTR_ERR(s);
break;
}
}
out:
path_cleanup(nd);
out2:
if (!(opened & FILE_OPENED)) {