Whamcloud - gitweb
LU-9868 llite: handle DCACHE_PAR_LOOKUP in ll_dcompare
[fs/lustre-release.git] / lustre / llite / dcache.c
index 6b2fdf3..5790afb 100644 (file)
@@ -23,7 +23,7 @@
  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, 2016, Intel Corporation.
+ * Copyright (c) 2011, 2017, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -38,7 +38,6 @@
 #define DEBUG_SUBSYSTEM S_LLITE
 
 #include <obd_support.h>
-#include <lustre/lustre_idl.h>
 #include <lustre_dlm.h>
 
 #include "llite_internal.h"
@@ -78,7 +77,14 @@ static void ll_release(struct dentry *de)
  * This avoids a race where ll_lookup_it() instantiates a dentry, but we get
  * an AST before calling d_revalidate_it().  The dentry still exists (marked
  * INVALID) so d_lookup() matches it, but we have no lock on it (so
- * lock_match() fails) and we spin around real_lookup(). */
+ * lock_match() fails) and we spin around real_lookup().
+ *
+ * This race doesn't apply to lookups in d_alloc_parallel(), and for
+ * those we want to ensure that only one dentry with a given name is
+ * in ll_lookup_nd() at a time.  So allow invalid dentries to match
+ * while d_in_lookup().  We will be called again when the lookup
+ * completes, and can give a different answer then.
+ */
 #ifdef HAVE_D_COMPARE_7ARGS
 static int ll_dcompare(const struct dentry *parent, const struct inode *pinode,
                       const struct dentry *dentry, const struct inode *inode,
@@ -118,6 +124,10 @@ static int ll_dcompare(struct dentry *parent, struct qstr *d_name,
        if (d_mountpoint((struct dentry *)dentry))
                RETURN(0);
 
+       /* ensure exclusion against parallel lookup of the same name */
+       if (d_in_lookup((struct dentry *)dentry))
+               return 0;
+
        if (d_lustre_invalid(dentry))
                RETURN(1);
 
@@ -328,15 +338,14 @@ static int ll_revalidate_dentry(struct dentry *dentry,
        if (lookup_flags & LOOKUP_REVAL)
                return 0;
 
-       if (!dentry_may_statahead(dir, dentry))
-               return 1;
-
 #ifndef HAVE_DCACHE_LOCK
        if (lookup_flags & LOOKUP_RCU)
                return -ECHILD;
 #endif
 
-       ll_statahead(dir, &dentry, dentry->d_inode == NULL);
+       if (dentry_may_statahead(dir, dentry))
+               ll_statahead(dir, &dentry, dentry->d_inode == NULL);
+
        return 1;
 }