Whamcloud - gitweb
LU-9868 llite: handle DCACHE_PAR_LOOKUP in ll_dcompare
[fs/lustre-release.git] / lustre / llite / dcache.c
index 0c0ee69..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,
@@ -88,12 +94,15 @@ static int ll_dcompare(const struct dentry *parent, const struct inode *pinode,
 static int ll_dcompare(const struct dentry *parent, const struct dentry *dentry,
                       unsigned int len, const char *str,
                       const struct qstr *name)
+#elif defined(HAVE_D_COMPARE_4ARGS)
+static int ll_dcompare(const struct dentry *dentry, unsigned int len,
+                      const char *str, const struct qstr *name)
 #else
 static int ll_dcompare(struct dentry *parent, struct qstr *d_name,
                       struct qstr *name)
 #endif
 {
-#if !defined(HAVE_D_COMPARE_7ARGS) && !defined(HAVE_D_COMPARE_5ARGS)
+#if !defined(HAVE_D_COMPARE_7ARGS) && !defined(HAVE_D_COMPARE_5ARGS) && !defined(HAVE_D_COMPARE_4ARGS)
        /* XXX: (ugh !) d_name must be in-dentry structure */
        struct dentry *dentry = container_of(d_name, struct dentry, d_name);
        unsigned int len = d_name->len;
@@ -115,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);
 
@@ -167,12 +180,13 @@ int ll_d_init(struct dentry *de)
                if (likely(lld != NULL)) {
                        spin_lock(&de->d_lock);
                        if (likely(de->d_fsdata == NULL)) {
-                               de->d_fsdata = lld;
-                               __d_lustre_invalidate(de);
 #ifdef HAVE_DCACHE_LOCK
                                /* kernel >= 2.6.38 d_op is set in d_alloc() */
                                de->d_op = &ll_d_ops;
+                               smp_mb();
 #endif
+                               de->d_fsdata = lld;
+                               __d_lustre_invalidate(de);
                        } else {
                                OBD_FREE_PTR(lld);
                        }
@@ -248,14 +262,6 @@ void ll_invalidate_aliases(struct inode *inode)
                       dentry->d_name.name, dentry, dentry->d_parent,
                       dentry->d_inode, dentry->d_flags);
 
-               if (unlikely(dentry == dentry->d_sb->s_root)) {
-                       CERROR("%s: called on root dentry=%p, fid="DFID"\n",
-                              ll_get_fsname(dentry->d_sb, NULL, 0),
-                              dentry, PFID(ll_inode2fid(inode)));
-                       lustre_dump_dentry(dentry, 1);
-                        libcfs_debug_dumpstack(NULL);
-                }
-
                d_lustre_invalidate(dentry, 0);
        }
        ll_unlock_dcache(inode);
@@ -332,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;
 }