Whamcloud - gitweb
add workaround for race in dcache with patchless client.
authorshadow <shadow>
Mon, 8 Sep 2008 09:04:09 +0000 (09:04 +0000)
committershadow <shadow>
Mon, 8 Sep 2008 09:04:09 +0000 (09:04 +0000)
Branch HEAD
b=15975
i=johann
i=adilger

lustre/ChangeLog
lustre/llite/dcache.c
lustre/llite/file.c
lustre/llite/llite_internal.h
lustre/llite/namei.c

index 797184c..f82850f 100644 (file)
@@ -12,6 +12,11 @@ tbd  Sun Microsystems, Inc.
        * RHEL 4 and RHEL 5/SLES 10 clients behaves differently on 'cd' to a
         removed cwd "./" (refer to Bugzilla 14399).
 
+Severity   : normal
+Bugzilla   : 15975
+Frequency  : only patchless client
+Description: add workaround for race between add/remove dentry from hash
+
 Severity   : enhancement 
 Bugzilla   : 16845 
 Description: Allow OST glimpses to return PW locks
index 117dde7..afb1a85 100644 (file)
@@ -51,6 +51,8 @@
 
 #include "llite_internal.h"
 
+spinlock_t ll_lookup_lock = SPIN_LOCK_UNLOCKED;
+
 /* should NOT be called with the dcache lock, see fs/dcache.c */
 void ll_release(struct dentry *de)
 {
@@ -209,7 +211,9 @@ int ll_drop_dentry(struct dentry *dentry)
                 __d_drop(dentry);
                 unlock_dentry(dentry);
                 spin_unlock(&dcache_lock);
+                spin_unlock(&ll_lookup_lock);
                 dput(dentry);
+                spin_lock(&ll_lookup_lock);
                 spin_lock(&dcache_lock);
                 return 1;
         }
@@ -257,6 +261,7 @@ void ll_unhash_aliases(struct inode *inode)
                inode->i_ino, inode->i_generation, inode);
 
         head = &inode->i_dentry;
+        spin_lock(&ll_lookup_lock);
         spin_lock(&dcache_lock);
 restart:
         tmp = head;
@@ -290,6 +295,8 @@ restart:
                           goto restart;
         }
         spin_unlock(&dcache_lock);
+        spin_unlock(&ll_lookup_lock);
+
         EXIT;
 }
 
@@ -506,12 +513,14 @@ revalidate_finish:
 
         /* unfortunately ll_intent_lock may cause a callback and revoke our
          * dentry */
+        spin_lock(&ll_lookup_lock);
         spin_lock(&dcache_lock);
         lock_dentry(de);
         __d_drop(de);
         unlock_dentry(de);
         d_rehash_cond(de, 0);
         spin_unlock(&dcache_lock);
+        spin_unlock(&ll_lookup_lock);
 
 out:
         /* We do not free request as it may be reused during following lookup
index ce1169f..c46aa0b 100644 (file)
@@ -3044,9 +3044,11 @@ int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it)
                    here to preserve get_cwd functionality on 2.6.
                    Bug 10503 */
                 if (!dentry->d_inode->i_nlink) {
+                        spin_lock(&ll_lookup_lock);
                         spin_lock(&dcache_lock);
                         ll_drop_dentry(dentry);
                         spin_unlock(&dcache_lock);
+                        spin_unlock(&ll_lookup_lock);
                 }
 
                 ll_lookup_finish_locks(&oit, dentry);
index b5d9257..8631e1e 100644 (file)
@@ -813,6 +813,11 @@ int ll_extent_lock_cancel_cb(struct ldlm_lock *lock, struct ldlm_lock_desc *new,
                              void *data, int flag);
 
 /* llite/dcache.c */
+/* llite/namei.c */
+/**
+ * protect race ll_find_aliases vs ll_revalidate_it vs ll_unhash_aliases
+ */
+extern spinlock_t ll_lookup_lock;
 extern struct dentry_operations ll_init_d_ops;
 extern struct dentry_operations ll_d_ops;
 extern struct dentry_operations ll_fini_d_ops;
index fac47a3..1bd7c2c 100644 (file)
@@ -141,6 +141,7 @@ static void ll_drop_negative_dentry(struct inode *dir)
 { 
         struct dentry *dentry, *tmp_alias, *tmp_subdir;
 
+        spin_lock(&ll_lookup_lock);
         spin_lock(&dcache_lock);
 restart:
         list_for_each_entry_safe(dentry, tmp_alias,
@@ -161,6 +162,7 @@ restart:
                 }
         }
         spin_unlock(&dcache_lock);
+        spin_unlock(&ll_lookup_lock);
 }
 
 
@@ -335,6 +337,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
         struct dentry *dentry;
         struct dentry *last_discon = NULL;
  
+        spin_lock(&ll_lookup_lock);
         spin_lock(&dcache_lock);
         list_for_each(tmp, &inode->i_dentry) {
                 dentry = list_entry(tmp, struct dentry, d_alias);
@@ -373,6 +376,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                 unlock_dentry(dentry);
                 d_rehash_cond(dentry, 0); /* avoid taking dcache_lock inside */
                 spin_unlock(&dcache_lock);
+                spin_unlock(&ll_lookup_lock);
                 iput(inode);
                 CDEBUG(D_DENTRY, "alias dentry %.*s (%p) parent %p inode %p "
                        "refc %d\n", de->d_name.len, de->d_name.name, de,
@@ -386,6 +390,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                         atomic_read(&last_discon->d_count));
                 dget_locked(last_discon);
                 spin_unlock(&dcache_lock);
+                spin_unlock(&ll_lookup_lock);
                 d_rehash(de);
                 d_move(last_discon, de);
                 iput(inode);
@@ -395,6 +400,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
         ll_d_add(de, inode);
 
         spin_unlock(&dcache_lock);
+        spin_unlock(&ll_lookup_lock);
 
         return de;
 }