namei: take the treatment of absolute symlinks to get_link()
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 10 May 2015 15:01:00 +0000 (11:01 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 11 May 2015 02:20:17 +0000 (22:20 -0400)
rather than letting the callers handle the jump-to-root part of
semantics, do it right in get_link() and return the rest of the
body for the caller to deal with - at that point it's treated
the same way as relative symlinks would be.  And return NULL
when there's no "rest of the body" - those are treated the same
as pure jump symlink would be.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namei.c

index c5eb77a..c6ff9da 100644 (file)
@@ -918,9 +918,24 @@ const char *get_link(struct nameidata *nd)
        res = inode->i_link;
        if (!res) {
                res = inode->i_op->follow_link(dentry, &last->cookie);
-               if (IS_ERR_OR_NULL(res))
+               if (IS_ERR_OR_NULL(res)) {
                        last->cookie = NULL;
+                       return res;
+               }
+       }
+       if (*res == '/') {
+               if (!nd->root.mnt)
+                       set_root(nd);
+               path_put(&nd->path);
+               nd->path = nd->root;
+               path_get(&nd->root);
+               nd->inode = nd->path.dentry->d_inode;
+               nd->flags |= LOOKUP_JUMPED;
+               while (unlikely(*++res == '/'))
+                       ;
        }
+       if (!*res)
+               res = NULL;
        return res;
 }
 
@@ -1854,24 +1869,9 @@ OK:
                                /* jumped */
                                put_link(nd);
                        } else {
-                               if (*s == '/') {
-                                       if (!nd->root.mnt)
-                                               set_root(nd);
-                                       path_put(&nd->path);
-                                       nd->path = nd->root;
-                                       path_get(&nd->root);
-                                       nd->flags |= LOOKUP_JUMPED;
-                                       while (unlikely(*++s == '/'))
-                                               ;
-                               }
-                               nd->inode = nd->path.dentry->d_inode;
-                               if (unlikely(!*s)) {
-                                       put_link(nd);
-                               } else {
-                                       nd->stack[nd->depth - 1].name = name;
-                                       name = s;
-                                       continue;
-                               }
+                               nd->stack[nd->depth - 1].name = name;
+                               name = s;
+                               continue;
                        }
                }
                if (!d_can_lookup(nd->path.dentry)) {
@@ -2002,6 +2002,7 @@ static int trailing_symlink(struct nameidata *nd)
        if (unlikely(error))
                return error;
        nd->flags |= LOOKUP_PARENT;
+       nd->stack[0].name = NULL;
        s = get_link(nd);
        if (unlikely(IS_ERR(s))) {
                terminate_walk(nd);
@@ -2009,16 +2010,6 @@ static int trailing_symlink(struct nameidata *nd)
        }
        if (unlikely(!s))
                return 0;
-       if (*s == '/') {
-               if (!nd->root.mnt)
-                       set_root(nd);
-               path_put(&nd->path);
-               nd->path = nd->root;
-               path_get(&nd->root);
-               nd->flags |= LOOKUP_JUMPED;
-       }
-       nd->inode = nd->path.dentry->d_inode;
-       nd->stack[0].name = NULL;
        return link_path_walk(s, nd);
 }