namei: massage lookup_slow() to be usable by lookup_one_len_unlocked()
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 6 Mar 2016 19:03:27 +0000 (14:03 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 14 Mar 2016 04:15:40 +0000 (00:15 -0400)
Return dentry and don't pass nameidata or path; lift crossing mountpoints
into the caller.

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

index ae67335..cb70a81 100644 (file)
@@ -1445,7 +1445,8 @@ static int follow_dotdot(struct nameidata *nd)
  * allocates a new one if not found or not valid.  In the need_lookup argument
  * returns whether i_op->lookup is necessary.
  */
-static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
+static struct dentry *lookup_dcache(const struct qstr *name,
+                                   struct dentry *dir,
                                    unsigned int flags)
 {
        struct dentry *dentry;
@@ -1491,7 +1492,7 @@ static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
        return dentry;
 }
 
-static struct dentry *__lookup_hash(struct qstr *name,
+static struct dentry *__lookup_hash(const struct qstr *name,
                struct dentry *base, unsigned int flags)
 {
        struct dentry *dentry = lookup_dcache(name, base, flags);
@@ -1598,21 +1599,15 @@ static int lookup_fast(struct nameidata *nd,
 }
 
 /* Fast lookup failed, do it the slow way */
-static int lookup_slow(struct nameidata *nd, struct path *path)
+static struct dentry *lookup_slow(const struct qstr *name,
+                                 struct dentry *dir,
+                                 unsigned int flags)
 {
-       struct dentry *dentry, *parent;
-
-       parent = nd->path.dentry;
-       BUG_ON(nd->inode != parent->d_inode);
-
-       inode_lock(parent->d_inode);
-       dentry = __lookup_hash(&nd->last, parent, nd->flags);
-       inode_unlock(parent->d_inode);
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
-       path->mnt = nd->path.mnt;
-       path->dentry = dentry;
-       return follow_managed(path, nd);
+       struct dentry *dentry;
+       inode_lock(dir->d_inode);
+       dentry = __lookup_hash(name, dir, flags);
+       inode_unlock(dir->d_inode);
+       return dentry;
 }
 
 static inline int may_lookup(struct nameidata *nd)
@@ -1719,15 +1714,20 @@ static int walk_component(struct nameidata *nd, int flags)
        if (unlikely(err <= 0)) {
                if (err < 0)
                        return err;
-
-               err = lookup_slow(nd, &path);
-               if (err < 0)
+               path.dentry = lookup_slow(&nd->last, nd->path.dentry,
+                                         nd->flags);
+               if (IS_ERR(path.dentry))
+                       return PTR_ERR(path.dentry);
+               if (unlikely(d_is_negative(path.dentry))) {
+                       dput(path.dentry);
+                       return -ENOENT;
+               }
+               path.mnt = nd->path.mnt;
+               err = follow_managed(&path, nd);
+               if (unlikely(err < 0))
                        return err;
 
                seq = 0;        /* we are already out of RCU mode */
-               err = -ENOENT;
-               if (d_is_negative(path.dentry))
-                       goto out_path_put;
                inode = d_backing_inode(path.dentry);
        }
 
@@ -1740,10 +1740,6 @@ static int walk_component(struct nameidata *nd, int flags)
        nd->inode = inode;
        nd->seq = seq;
        return 0;
-
-out_path_put:
-       path_to_nameidata(&path, nd);
-       return err;
 }
 
 /*
@@ -2350,12 +2346,8 @@ struct dentry *lookup_one_len_unlocked(const char *name,
                return ERR_PTR(err);
 
        ret = lookup_dcache(&this, base, 0);
-       if (ret)
-               return ret;
-
-       inode_lock(base->d_inode);
-       ret =  __lookup_hash(&this, base, 0);
-       inode_unlock(base->d_inode);
+       if (!ret)
+               ret = lookup_slow(&this, base, 0);
        return ret;
 }
 EXPORT_SYMBOL(lookup_one_len_unlocked);