All path-forming primitives boil down to sequence of prepend_name() on dentries encountered along the way toward root. Each time we prepend / + dentry name to the buffer. Normally that does exactly what we want, but there's a corner case when we don't call prepend_name() at all (in case of __dentry_path() that happens if we are given root dentry). We obviously want to end up with "/", rather than "", so this corner case needs to be handled. __dentry_path() used to manually put '/' in the end of buffer before doing anything else, to be overwritten by the first call of prepend_name() if one happens and to be left in place if we don't call prepend_name() at all. That required manually checking that we had space in the buffer (prepend_name() and prepend() take care of such checks themselves) and lead to clumsy keeping track of return value. A better approach is to check if the main loop has added anything into the buffer and prepend "/" if it hasn't. A side benefit of using prepend() is that it does the right thing if we'd already run out of buffer, making the overflow-handling logics simpler. Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> --- fs/d_path.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/fs/d_path.c b/fs/d_path.c index 1a1cf05e7780..b3324ae7cfe2 100644 --- a/fs/d_path.c +++ b/fs/d_path.c @@ -329,31 +329,22 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen) static char *__dentry_path(const struct dentry *d, char *p, int buflen) { const struct dentry *dentry; - char *end, *retval; + char *end; int len, seq = 0; - int error = 0; - - if (buflen < 1) - goto Elong; rcu_read_lock(); restart: dentry = d; end = p; len = buflen; - /* Get '/' right */ - retval = end-1; - *retval = '/'; read_seqbegin_or_lock(&rename_lock, &seq); while (!IS_ROOT(dentry)) { const struct dentry *parent = dentry->d_parent; prefetch(parent); - error = prepend_name(&end, &len, &dentry->d_name); - if (error) + if (unlikely(prepend_name(&end, &len, &dentry->d_name) < 0)) break; - retval = end; dentry = parent; } if (!(seq & 1)) @@ -363,11 +354,9 @@ static char *__dentry_path(const struct dentry *d, char *p, int buflen) goto restart; } done_seqretry(&rename_lock, seq); - if (error) - goto Elong; - return retval; -Elong: - return ERR_PTR(-ENAMETOOLONG); + if (len == buflen) + prepend(&end, &len, "/", 1); + return len >= 0 ? end : ERR_PTR(-ENAMETOOLONG); } char *dentry_path_raw(const struct dentry *dentry, char *buf, int buflen) -- 2.11.0