summaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2015-05-08 23:37:07 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2015-05-11 14:12:57 +0200
commit3bdba28b72f5d2e7f3df031b04008b9a6fbdc775 (patch)
treec538a12b16e7c2cbd53eff4d07c7116babf96c6f /fs/namei.c
parentnamei: path_init() calling conventions change (diff)
downloadlinux-3bdba28b72f5d2e7f3df031b04008b9a6fbdc775.tar.xz
linux-3bdba28b72f5d2e7f3df031b04008b9a6fbdc775.zip
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>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c50
1 files changed, 23 insertions, 27 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 06c71200be48..46f4266d1f7f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -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)) {