namei: teach lookup_slow() to skip revalidate
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 6 Mar 2016 19:20:52 +0000 (14:20 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 14 Mar 2016 04:15:46 +0000 (00:15 -0400)
... and make mountpoint_last() use it.  That makes all
candidates for lookup with parent locked shared go
through lookup_slow().

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

index cb70a817d439d81181a7cbf5fc8e0717707a1101..dbb8ec1a2006b0829ab2181c6581e9aeb21d8909 100644 (file)
@@ -1605,7 +1605,29 @@ static struct dentry *lookup_slow(const struct qstr *name,
 {
        struct dentry *dentry;
        inode_lock(dir->d_inode);
-       dentry = __lookup_hash(name, dir, flags);
+       dentry = d_lookup(dir, name);
+       if (unlikely(dentry)) {
+               if ((dentry->d_flags & DCACHE_OP_REVALIDATE) &&
+                   !(flags & LOOKUP_NO_REVAL)) {
+                       int error = d_revalidate(dentry, flags);
+                       if (unlikely(error <= 0)) {
+                               if (!error)
+                                       d_invalidate(dentry);
+                               dput(dentry);
+                               dentry = ERR_PTR(error);
+                       }
+               }
+               if (dentry) {
+                       inode_unlock(dir->d_inode);
+                       return dentry;
+               }
+       }
+       dentry = d_alloc(dir, name);
+       if (unlikely(!dentry)) {
+               inode_unlock(dir->d_inode);
+               return ERR_PTR(-ENOMEM);
+       }
+       dentry = lookup_real(dir->d_inode, dentry, flags);
        inode_unlock(dir->d_inode);
        return dentry;
 }
@@ -2425,31 +2447,21 @@ mountpoint_last(struct nameidata *nd, struct path *path)
                if (error)
                        return error;
                dentry = dget(nd->path.dentry);
-               goto done;
-       }
-
-       inode_lock(dir->d_inode);
-       dentry = d_lookup(dir, &nd->last);
-       if (!dentry) {
-               /*
-                * No cached dentry. Mounted dentries are pinned in the cache,
-                * so that means that this dentry is probably a symlink or the
-                * path doesn't actually point to a mounted dentry.
-                */
-               dentry = d_alloc(dir, &nd->last);
+       } else {
+               dentry = d_lookup(dir, &nd->last);
                if (!dentry) {
-                       inode_unlock(dir->d_inode);
-                       return -ENOMEM;
-               }
-               dentry = lookup_real(dir->d_inode, dentry, nd->flags);
-               if (IS_ERR(dentry)) {
-                       inode_unlock(dir->d_inode);
-                       return PTR_ERR(dentry);
+                       /*
+                        * No cached dentry. Mounted dentries are pinned in the
+                        * cache, so that means that this dentry is probably
+                        * a symlink or the path doesn't actually point
+                        * to a mounted dentry.
+                        */
+                       dentry = lookup_slow(&nd->last, dir,
+                                            nd->flags | LOOKUP_NO_REVAL);
+                       if (IS_ERR(dentry))
+                               return PTR_ERR(dentry);
                }
        }
-       inode_unlock(dir->d_inode);
-
-done:
        if (d_is_negative(dentry)) {
                dput(dentry);
                return -ENOENT;
index d0f25d81b46a6c2f488c34e2cd14e91c49fb8145..77d01700daf7b826bdf19c2022d5260adb640e0b 100644 (file)
@@ -31,6 +31,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 #define LOOKUP_PARENT          0x0010
 #define LOOKUP_REVAL           0x0020
 #define LOOKUP_RCU             0x0040
+#define LOOKUP_NO_REVAL                0x0080
 
 /*
  * Intent data