From: Al Viro <viro@xxxxxxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxxxxxx> --- fs/namei.c | 49 ++++++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index c5eb77a..c6ff9da 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -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); } -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html