From: NeilBrown <[email protected]>

fuse uses the results of readdir to prime the dcache.  Using
d_alloc_parallel() can block if there is a concurrent lookup.  Blocking
in that case is pointless as the lookup will add info to the dcache and
there is no value in the readdir waiting to see if it should add the
info too.

Also this call to d_alloc_parallel() is made while the parent
directory is locked.  A proposed change to locking will lock the parent
later, after d_alloc_parallel().  This means it won't be safe to wait in
d_alloc_parallel() while holding the directory lock.

So change to use d_alloc_noblock(), and use try_lookup_noperm() rather
than full_name_hash and d_lookup.

Signed-off-by: NeilBrown <[email protected]>
---
 fs/fuse/readdir.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
index f588252891af..400a1a24f659 100644
--- a/fs/fuse/readdir.c
+++ b/fs/fuse/readdir.c
@@ -12,6 +12,7 @@
 #include <linux/posix_acl.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
+#include <linux/namei.h>
 
 static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx)
 {
@@ -192,14 +193,18 @@ static int fuse_direntplus_link(struct file *file,
        fc = get_fuse_conn(dir);
        epoch = atomic_read(&fc->epoch);
 
-       name.hash = full_name_hash(parent, name.name, name.len);
-       dentry = d_lookup(parent, &name);
+       dentry = try_lookup_noperm(&name, parent);
        if (!dentry) {
 retry:
-               dentry = d_alloc_parallel(parent, &name);
-               if (IS_ERR(dentry))
-                       return PTR_ERR(dentry);
+               dentry = d_alloc_noblock(parent, &name);
+       }
+       if (IS_ERR(dentry)) {
+               if (PTR_ERR(dentry) == -EWOULDBLOCK)
+                       /* harmless */
+                       return 0;
+               return PTR_ERR(dentry);
        }
+
        if (!d_in_lookup(dentry)) {
                struct fuse_inode *fi;
                inode = d_inode(dentry);
-- 
2.50.0.107.gf914562f5916.dirty


Reply via email to