diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-08 23:37:07 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-11 14:12:57 +0200 |
commit | 3bdba28b72f5d2e7f3df031b04008b9a6fbdc775 (patch) | |
tree | c538a12b16e7c2cbd53eff4d07c7116babf96c6f /fs/namei.c | |
parent | namei: path_init() calling conventions change (diff) | |
download | linux-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.c | 50 |
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)) { |