namei: take put_link() into {lookup,mountpoint,do}_last()
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 4 May 2015 12:26:45 +0000 (08:26 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 11 May 2015 02:20:11 +0000 (22:20 -0400)
rationale: we'll need to have terminate_walk() do put_link() on
everything, which will mean that in some cases ..._last() will do
put_link() anyway.  Easier to have them do it in all cases.

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

index db21e042619383336426bac93f7d7dc6adb67786..26466fbc5b563e0e3eeb143bceed8dbc3b7db488 100644 (file)
@@ -2018,6 +2018,8 @@ static inline int lookup_last(struct nameidata *nd)
 
        nd->flags &= ~LOOKUP_PARENT;
        err = walk_component(nd, nd->flags & LOOKUP_FOLLOW);
+       if (nd->depth)
+               put_link(nd);
        if (err < 0)
                terminate_walk(nd);
        return err;
@@ -2045,13 +2047,10 @@ static int path_lookupat(int dfd, const struct filename *name,
         */
        err = path_init(dfd, name, flags, nd);
        if (!err && !(flags & LOOKUP_PARENT)) {
-               err = lookup_last(nd);
-               while (err > 0) {
+               while ((err = lookup_last(nd)) > 0) {
                        err = trailing_symlink(nd);
                        if (err)
                                break;
-                       err = lookup_last(nd);
-                       put_link(nd);
                }
        }
 
@@ -2362,6 +2361,8 @@ done:
                dput(dentry);
                goto out;
        }
+       if (nd->depth)
+               put_link(nd);
        path->dentry = dentry;
        path->mnt = nd->path.mnt;
        if (should_follow_link(dentry, nd->flags & LOOKUP_FOLLOW)) {
@@ -2373,6 +2374,8 @@ done:
        error = 0;
 out:
        terminate_walk(nd);
+       if (nd->depth)
+               put_link(nd);
        return error;
 }
 
@@ -2394,13 +2397,10 @@ path_mountpoint(int dfd, const struct filename *name, struct path *path,
        if (unlikely(err))
                goto out;
 
-       err = mountpoint_last(nd, path);
-       while (err > 0) {
+       while ((err = mountpoint_last(nd, path)) > 0) {
                err = trailing_symlink(nd);
                if (err)
                        break;
-               err = mountpoint_last(nd, path);
-               put_link(nd);
        }
 out:
        path_cleanup(nd);
@@ -2978,6 +2978,8 @@ static int do_last(struct nameidata *nd,
                error = handle_dots(nd, nd->last_type);
                if (unlikely(error)) {
                        terminate_walk(nd);
+                       if (nd->depth)
+                               put_link(nd);
                        return error;
                }
                goto finish_open;
@@ -3003,8 +3005,11 @@ static int do_last(struct nameidata *nd,
                 * about to look up
                 */
                error = complete_walk(nd);
-               if (error)
+               if (error) {
+                       if (nd->depth)
+                               put_link(nd);
                        return error;
+               }
 
                audit_inode(name, dir, LOOKUP_PARENT);
                error = -EISDIR;
@@ -3093,6 +3098,8 @@ finish_lookup:
                        }
                }
                BUG_ON(inode != path.dentry->d_inode);
+               if (nd->depth)
+                       put_link(nd);
                nd->link = path;
                return 1;
        }
@@ -3116,6 +3123,8 @@ finish_lookup:
 finish_open:
        error = complete_walk(nd);
        if (error) {
+               if (nd->depth)
+                       put_link(nd);
                path_put(&save_parent);
                return error;
        }
@@ -3167,6 +3176,8 @@ out:
                mnt_drop_write(nd->path.mnt);
        path_put(&save_parent);
        terminate_walk(nd);
+       if (nd->depth)
+               put_link(nd);
        return error;
 
 exit_dput:
@@ -3279,14 +3290,11 @@ static struct file *path_openat(int dfd, struct filename *pathname,
        if (unlikely(error))
                goto out;
 
-       error = do_last(nd, file, op, &opened, pathname);
-       while (unlikely(error > 0)) { /* trailing symlink */
+       while ((error = do_last(nd, file, op, &opened, pathname)) > 0) {
                nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
                error = trailing_symlink(nd);
                if (unlikely(error))
                        break;
-               error = do_last(nd, file, op, &opened, pathname);
-               put_link(nd);
        }
 out:
        path_cleanup(nd);