namei: lift link_path_walk() call out of trailing_symlink()
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 8 May 2015 21:37:07 +0000 (17:37 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 11 May 2015 12:12:57 +0000 (08:12 -0400)
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>
fs/namei.c

index 06c71200be4839680a1817deb0be8a2972771ffa..46f4266d1f7febc90a6467a0f0475edb85148fc6 100644 (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)) {