diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 3ae815a1bf94baf432b6b1f412f71b1864e2fe50..10fed7c7e0038814059fed1771528942e40e269c 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -56,6 +56,7 @@ struct ll_dentry_data { #ifndef HAVE_VFS_INTENT_PATCHES struct lookup_intent *lld_it; #endif + unsigned int lld_sa_generation; cfs_waitq_t lld_waitq; }; @@ -883,6 +884,7 @@ int ll_statahead_enter(struct inode *dir, struct dentry **dentryp, int lookup) { struct ll_sb_info *sbi = ll_i2sbi(dir); struct ll_inode_info *lli = ll_i2info(dir); + struct ll_dentry_data *ldd = ll_d2d(*dentryp); if (sbi->ll_sa_max == 0) return -ENOTSUPP; @@ -891,6 +893,25 @@ int ll_statahead_enter(struct inode *dir, struct dentry **dentryp, int lookup) if (lli->lli_opendir_pid != cfs_curproc_pid()) return -EBADF; + /* + * When "ls" a dentry, the system trigger more than once "revalidate" or + * "lookup", for "getattr", for "getxattr", and maybe for others. + * Under patchless client mode, the operation intent is not accurate, + * it maybe misguide the statahead thread. For example: + * The "revalidate" call for "getattr" and "getxattr" of a dentry maybe + * have the same operation intent -- "IT_GETATTR". + * In fact, one dentry should has only one chance to interact with the + * statahead thread, otherwise the statahead windows will be confused. + * The solution is as following: + * Assign "lld_sa_generation" with "sai_generation" when a dentry + * "IT_GETATTR" for the first time, and the subsequent "IT_GETATTR" + * will bypass interacting with statahead thread for checking: + * "lld_sa_generation == lli_sai->sai_generation" + */ + if (ldd && lli->lli_sai && + ldd->lld_sa_generation == lli->lli_sai->sai_generation) + return -EAGAIN; + return do_statahead_enter(dir, dentryp, lookup); } diff --git a/lustre/llite/statahead.c b/lustre/llite/statahead.c index 24b245d8655c214eceb38d48cceb57e0c35f02de..2692b96dd7fb0dde7635db5117ef8982d4b3c3f9 100644 --- a/lustre/llite/statahead.c +++ b/lustre/llite/statahead.c @@ -58,6 +58,8 @@ static struct ll_statahead_info *ll_sai_alloc(void) spin_lock(&sai_generation_lock); sai->sai_generation = ++sai_generation; + if (unlikely(sai_generation == 0)) + sai->sai_generation = ++sai_generation; spin_unlock(&sai_generation_lock); atomic_set(&sai->sai_refcount, 1); sai->sai_max = LL_SA_RPC_MIN; @@ -90,8 +92,8 @@ static void ll_sai_put(struct ll_statahead_info *sai) LASSERT(sai->sai_thread.t_flags & SVC_STOPPED); if (sai->sai_sent > sai->sai_replied) - CWARN("statahead for dir %lu/%u does not finish: " - "[sent:%u] [replied:%u]\n", + CDEBUG(D_READA,"statahead for dir %lu/%u does not " + "finish: [sent:%u] [replied:%u]\n", inode->i_ino, inode->i_generation, sai->sai_sent, sai->sai_replied); @@ -886,9 +888,10 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, int lookup) /* update hit/miss count */ void ll_statahead_exit(struct dentry *dentry, int result) { - struct dentry *parent = dentry->d_parent; - struct ll_inode_info *lli = ll_i2info(parent->d_inode); - struct ll_sb_info *sbi = ll_i2sbi(parent->d_inode); + struct dentry *parent = dentry->d_parent; + struct ll_inode_info *lli = ll_i2info(parent->d_inode); + struct ll_sb_info *sbi = ll_i2sbi(parent->d_inode); + struct ll_dentry_data *ldd = ll_d2d(dentry); if (lli->lli_opendir_pid != cfs_curproc_pid()) return; @@ -921,7 +924,11 @@ void ll_statahead_exit(struct dentry *dentry, int result) spin_unlock(&lli->lli_lock); } } + cfs_waitq_signal(&sai->sai_thread.t_ctl_waitq); ll_sai_entry_put(sai); + + if (likely(ldd != NULL)) + ldd->lld_sa_generation = sai->sai_generation; } }