From: Al Viro <v...@zeniv.linux.org.uk>

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 <v...@zeniv.linux.org.uk>
---
 fs/namei.c | 50 +++++++++++++++++++++++---------------------------
 1 file changed, 23 insertions(+), 27 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 06c7120..46f4266 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)) {
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to