diff --git a/lustre/llite/dcache.c b/lustre/llite/dcache.c index afb1a85371aec3b72a825ffe29eb768a6ba5a07d..2627a4503046fe3174bc8b5a1f4f8e2b220c7356 100644 --- a/lustre/llite/dcache.c +++ b/lustre/llite/dcache.c @@ -54,7 +54,7 @@ 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) +static void ll_release(struct dentry *de) { struct ll_dentry_data *lld; ENTRY; @@ -143,7 +143,6 @@ void ll_set_dd(struct dentry *de) OBD_ALLOC_PTR(lld); if (likely(lld != NULL)) { - cfs_waitq_init(&lld->lld_waitq); lock_dentry(de); if (likely(de->d_fsdata == NULL)) de->d_fsdata = lld; @@ -479,6 +478,8 @@ do_lock: ll_finish_md_op_data(op_data); if (it->it_op == IT_GETATTR && !first) ll_statahead_exit(de, rc); + else if (first == -EEXIST) + ll_statahead_mark(de); /* If req is NULL, then md_intent_lock only tried to do a lock match; * if all was well, it will return 1 if it found locks, 0 otherwise. */ @@ -614,6 +615,8 @@ out_sa: first = ll_statahead_enter(de->d_parent->d_inode, &de, 0); if (!first) ll_statahead_exit(de, rc); + else if (first == -EEXIST) + ll_statahead_mark(de); } return rc; @@ -800,45 +803,3 @@ struct dentry_operations ll_d_ops = { .d_unpin = ll_unpin, #endif }; - -static int ll_fini_revalidate_nd(struct dentry *dentry, struct nameidata *nd) -{ - ENTRY; - /* need lookup */ - RETURN(0); -} - -struct dentry_operations ll_fini_d_ops = { - .d_revalidate = ll_fini_revalidate_nd, - .d_release = ll_release, -}; - -/* - * It is for the following race condition: - * When someone (maybe statahead thread) adds the dentry to the dentry hash - * table, the dentry's "d_op" maybe NULL, at the same time, another (maybe - * "ls -l") process finds such dentry by "do_lookup()" without "do_revalidate()" - * called. It causes statahead window lost, and maybe other issues. --Fan Yong - */ -static int ll_init_revalidate_nd(struct dentry *dentry, struct nameidata *nd) -{ - struct l_wait_info lwi = { 0 }; - struct ll_dentry_data *lld; - ENTRY; - - ll_set_dd(dentry); - lld = ll_d2d(dentry); - if (unlikely(lld == NULL)) - RETURN(-ENOMEM); - - l_wait_event(lld->lld_waitq, dentry->d_op != &ll_init_d_ops, &lwi); - if (likely(dentry->d_op == &ll_d_ops)) - RETURN(ll_revalidate_nd(dentry, nd)); - else - RETURN(dentry->d_op == &ll_fini_d_ops ? 0 : -EINVAL); -} - -struct dentry_operations ll_init_d_ops = { - .d_revalidate = ll_init_revalidate_nd, - .d_release = ll_release, -}; diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 9a4601a95aee13b0d3283346a8fe0937fffbb4f8..9da786feda82990a29be9db7886d480fd87508d3 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -300,8 +300,8 @@ int ll_file_release(struct inode *inode, struct file *file) struct ll_inode_info *lli = ll_i2info(inode); struct lov_stripe_md *lsm = lli->lli_smd; int rc; - ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino, inode->i_generation, inode); @@ -327,7 +327,7 @@ int ll_file_release(struct inode *inode, struct file *file) /* The last ref on @file, maybe not the the owner pid of statahead. * Different processes can open the same dir, "ll_opendir_key" means: * it is me that should stop the statahead thread. */ - if (lli->lli_opendir_key == fd) + if (lli->lli_opendir_key == fd && lli->lli_opendir_pid != 0) ll_stop_statahead(inode, fd); if (inode->i_sb->s_root == file->f_dentry) { @@ -507,24 +507,29 @@ int ll_file_open(struct inode *inode, struct file *file) RETURN(-ENOMEM); if (S_ISDIR(inode->i_mode)) { +again: spin_lock(&lli->lli_lock); - /* "lli->lli_opendir_pid != 0" means someone has set it. - * "lli->lli_sai != NULL" means the previous statahead has not - * been cleanup. */ - if (lli->lli_opendir_pid == 0 && lli->lli_sai == NULL) { - opendir_set = 1; - lli->lli_opendir_pid = cfs_curproc_pid(); + if (lli->lli_opendir_key == NULL && lli->lli_opendir_pid == 0) { + LASSERT(lli->lli_sai == NULL); lli->lli_opendir_key = fd; - } else if (unlikely(lli->lli_opendir_pid == cfs_curproc_pid())) { + lli->lli_opendir_pid = cfs_curproc_pid(); + opendir_set = 1; + } else if (unlikely(lli->lli_opendir_pid == cfs_curproc_pid() && + lli->lli_opendir_key != NULL)) { /* Two cases for this: * (1) The same process open such directory many times. * (2) The old process opened the directory, and exited * before its children processes. Then new process * with the same pid opens such directory before the * old process's children processes exit. - * Change the owner to the latest one. */ - opendir_set = 2; - lli->lli_opendir_key = fd; + * reset stat ahead for such cases. */ + spin_unlock(&lli->lli_lock); + CDEBUG(D_INFO, "Conflict statahead for %.*s "DFID + " reset it.\n", file->f_dentry->d_name.len, + file->f_dentry->d_name.name, + PFID(&lli->lli_fid)); + ll_stop_statahead(inode, lli->lli_opendir_key); + goto again; } spin_unlock(&lli->lli_lock); } @@ -680,12 +685,8 @@ out_och_free: } up(&lli->lli_och_sem); out_openerr: - if (opendir_set == 1) { - lli->lli_opendir_key = NULL; - lli->lli_opendir_pid = 0; - } else if (unlikely(opendir_set == 2)) { + if (opendir_set != 0) ll_stop_statahead(inode, fd); - } } return rc; diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 18addb31f689cd8b2ce9335a15d44820323b5e0f..07e2976a0c20c234c9a2c715f58879605bcd3efd 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -67,7 +67,6 @@ struct ll_dentry_data { struct lookup_intent *lld_it; #endif unsigned int lld_sa_generation; - cfs_waitq_t lld_waitq; }; #define ll_d2d(de) ((struct ll_dentry_data*)((de)->d_fsdata)) @@ -825,10 +824,7 @@ int ll_extent_lock_cancel_cb(struct ldlm_lock *lock, struct ldlm_lock_desc *new, * 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; -void ll_release(struct dentry *de); void ll_intent_drop_lock(struct lookup_intent *); void ll_intent_release(struct lookup_intent *); int ll_drop_dentry(struct dentry *dentry); @@ -1074,7 +1070,6 @@ void et_fini(struct eacl_table *et); /* per inode struct, for dir only */ struct ll_statahead_info { struct inode *sai_inode; - struct dentry *sai_first; /* first dentry item */ unsigned int sai_generation; /* generation for statahead */ atomic_t sai_refcount; /* when access this struct, hold * refcount */ @@ -1112,13 +1107,19 @@ int ll_statahead_exit(struct dentry *dentry, int result); void ll_stop_statahead(struct inode *inode, void *key); static inline -void ll_d_wakeup(struct dentry *dentry) +int ll_statahead_mark(struct dentry *dentry) { - struct ll_dentry_data *lld = ll_d2d(dentry); + struct ll_inode_info *lli = ll_i2info(dentry->d_parent->d_inode); + struct ll_statahead_info *sai = lli->lli_sai; + struct ll_dentry_data *ldd = ll_d2d(dentry); + int rc = 0; - LASSERT(dentry->d_op != &ll_init_d_ops); - if (lld != NULL) - cfs_waitq_broadcast(&lld->lld_waitq); + if (likely(ldd != NULL)) + ldd->lld_sa_generation = sai->sai_generation; + else + rc = -ENOMEM; + + return rc; } static inline @@ -1157,6 +1158,21 @@ int ll_statahead_enter(struct inode *dir, struct dentry **dentryp, int lookup) return do_statahead_enter(dir, dentryp, lookup); } +static void inline ll_dops_init(struct dentry *de, int block) +{ + struct ll_dentry_data *lld = ll_d2d(de); + + if (lld == NULL && block != 0) { + ll_set_dd(de); + lld = ll_d2d(de); + } + + if (lld != NULL) + lld->lld_sa_generation = 0; + + de->d_op = &ll_d_ops; +} + /* llite ioctl register support rountine */ #ifdef __KERNEL__ enum llioc_iter { diff --git a/lustre/llite/llite_nfs.c b/lustre/llite/llite_nfs.c index 49549f5b6ba4945400b0916352f062e1720fa6de..f20bf657be5ddbb32950d08d1121b89f14f566e9 100644 --- a/lustre/llite/llite_nfs.c +++ b/lustre/llite/llite_nfs.c @@ -137,18 +137,7 @@ static struct dentry *ll_iget_for_nfs(struct super_block *sb, RETURN(ERR_PTR(-ENOMEM)); } - ll_set_dd(result); - - lock_dentry(result); - if (unlikely(result->d_op == &ll_init_d_ops)) { - result->d_op = &ll_d_ops; - unlock_dentry(result); - smp_wmb(); - ll_d_wakeup(result); - } else { - result->d_op = &ll_d_ops; - unlock_dentry(result); - } + ll_dops_init(result, 1); RETURN(result); } diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index cd46159dad027be8b1d96ccafc1a8387697bb3d5..a7d87c6586de3e191b6898db0aaad7a36f3fb1fa 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -336,7 +336,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de) struct list_head *tmp; struct dentry *dentry; struct dentry *last_discon = NULL; - + spin_lock(&ll_lookup_lock); spin_lock(&dcache_lock); list_for_each(tmp, &inode->i_dentry) { @@ -374,6 +374,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de) dentry->d_flags &= ~DCACHE_LUSTRE_INVALID; #endif unlock_dentry(dentry); + ll_dops_init(dentry, 0); d_rehash_cond(dentry, 0); /* avoid taking dcache_lock inside */ spin_unlock(&dcache_lock); spin_unlock(&ll_lookup_lock); @@ -391,6 +392,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de) dget_locked(last_discon); spin_unlock(&dcache_lock); spin_unlock(&ll_lookup_lock); + ll_dops_init(last_discon, 1); d_rehash(de); d_move(last_discon, de); iput(inode); @@ -405,34 +407,6 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de) return de; } -static inline void ll_dop_init(struct dentry *de, int *set) -{ - lock_dentry(de); - if (likely(de->d_op != &ll_d_ops)) { - de->d_op = &ll_init_d_ops; - *set = 1; - } - unlock_dentry(de); -} - -static inline void ll_dop_fini(struct dentry *de, int succ) -{ - lock_dentry(de); - if (likely(de->d_op == &ll_init_d_ops)) { - if (succ) - de->d_op = &ll_d_ops; - else - de->d_op = &ll_fini_d_ops; - unlock_dentry(de); - smp_wmb(); - ll_d_wakeup(de); - } else { - if (succ) - de->d_op = &ll_d_ops; - unlock_dentry(de); - } -} - int ll_lookup_it_finish(struct ptlrpc_request *request, struct lookup_intent *it, void *data) { @@ -441,22 +415,17 @@ int ll_lookup_it_finish(struct ptlrpc_request *request, struct inode *parent = icbd->icbd_parent; struct ll_sb_info *sbi = ll_i2sbi(parent); struct inode *inode = NULL; - int set = 0, rc; + int rc; ENTRY; - ll_dop_init(*de, &set); - /* NB 1 request reference will be taken away by ll_intent_lock() * when I return */ if (!it_disposition(it, DISP_LOOKUP_NEG)) { struct dentry *save = *de; rc = ll_prep_inode(&inode, request, (*de)->d_sb); - if (rc) { - if (set) - ll_dop_fini(*de, 0); + if (rc) RETURN(rc); - } CDEBUG(D_DLMTRACE, "setting l_data to inode %p (%lu/%u)\n", inode, inode->i_ino, inode->i_generation); @@ -472,10 +441,21 @@ int ll_lookup_it_finish(struct ptlrpc_request *request, ll_glimpse_size or some equivalent themselves anyway. Also see bug 7198. */ + ll_dops_init(*de, 1); *de = ll_find_alias(inode, *de); - if (set && *de != save) - ll_dop_fini(save, 0); + if (*de != save) { + struct ll_dentry_data *lld = ll_d2d(*de); + + /* just make sure the ll_dentry_data is ready */ + if (unlikely(lld == NULL)) { + ll_set_dd(*de); + lld = ll_d2d(*de); + if (likely(lld != NULL)) + lld->lld_sa_generation = 0; + } + } } else { + ll_dops_init(*de, 1); /* Check that parent has UPDATE lock. If there is none, we cannot afford to hash this dentry (done by ll_d_add) as it might get picked up later when UPDATE lock will appear */ @@ -495,10 +475,6 @@ int ll_lookup_it_finish(struct ptlrpc_request *request, } } - ll_set_dd(*de); - - ll_dop_fini(*de, 1); - RETURN(0); } @@ -511,7 +487,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, struct md_op_data *op_data; struct it_cb_data icbd; __u32 opc; - int rc; + int rc, first = 0; ENTRY; if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen) @@ -536,10 +512,10 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, } if (it->it_op == IT_GETATTR) { - rc = ll_statahead_enter(parent, &dentry, 1); - if (rc >= 0) { - ll_statahead_exit(dentry, rc); - if (rc == 1) + first = ll_statahead_enter(parent, &dentry, 1); + if (first >= 0) { + ll_statahead_exit(dentry, first); + if (first == 1) RETURN(retval = dentry); } } @@ -573,6 +549,9 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, GOTO(out, retval = ERR_PTR(rc)); } + if (first == -EEXIST) + ll_statahead_mark(dentry); + if ((it->it_op & IT_OPEN) && dentry->d_inode && !S_ISREG(dentry->d_inode->i_mode) && !S_ISDIR(dentry->d_inode->i_mode)) { diff --git a/lustre/llite/statahead.c b/lustre/llite/statahead.c index e8e5572017dd17cd462368323da31f45fe157be1..e5fff85a5c2b7bf82bedb06ccf0c39309ff52696 100644 --- a/lustre/llite/statahead.c +++ b/lustre/llite/statahead.c @@ -62,10 +62,6 @@ enum { SA_ENTRY_STATED }; -struct dentry_operations ll_sai_d_ops = { - .d_release = ll_release, -}; - static unsigned int sai_generation = 0; static spinlock_t sai_generation_lock = SPIN_LOCK_UNLOCKED; @@ -96,7 +92,7 @@ static inline int sa_received_empty(struct ll_statahead_info *sai) static inline int sa_not_full(struct ll_statahead_info *sai) { - return sai->sai_index < sai->sai_hit + sai->sai_miss + sai->sai_max; + return (sai->sai_index < sai->sai_hit + sai->sai_miss + sai->sai_max); } static inline int sa_is_running(struct ll_statahead_info *sai) @@ -132,7 +128,7 @@ static inline int sa_low_hit(struct ll_statahead_info *sai) * (3) drop dentry's ref count * (4) release request's ref count */ -static void ll_sai_entry_cleanup(struct ll_sai_entry *entry) +static void ll_sai_entry_cleanup(struct ll_sai_entry *entry, int free) { struct ptlrpc_request *req = entry->se_req; struct md_enqueue_info *minfo = entry->se_minfo; @@ -151,7 +147,10 @@ static void ll_sai_entry_cleanup(struct ll_sai_entry *entry) entry->se_req = NULL; ptlrpc_req_finished(req); } - OBD_FREE_PTR(entry); + if (free) { + LASSERT(list_empty(&entry->se_list)); + OBD_FREE_PTR(entry); + } EXIT; } @@ -190,13 +189,17 @@ struct ll_statahead_info *ll_sai_get(struct ll_statahead_info *sai) static void ll_sai_put(struct ll_statahead_info *sai) { struct inode *inode = sai->sai_inode; - struct ll_inode_info *lli = ll_i2info(inode); + struct ll_inode_info *lli; ENTRY; + LASSERT(inode != NULL); + lli = ll_i2info(inode); if (atomic_dec_and_lock(&sai->sai_refcount, &lli->lli_lock)) { struct ll_sai_entry *entry, *next; + LASSERT(lli->lli_opendir_key == NULL); lli->lli_sai = NULL; + lli->lli_opendir_pid = 0; spin_unlock(&lli->lli_lock); LASSERT(sa_is_stopped(sai)); @@ -209,20 +212,19 @@ static void ll_sai_put(struct ll_statahead_info *sai) list_for_each_entry_safe(entry, next, &sai->sai_entries_sent, se_list) { - list_del(&entry->se_list); - ll_sai_entry_cleanup(entry); + list_del_init(&entry->se_list); + ll_sai_entry_cleanup(entry, 1); } list_for_each_entry_safe(entry, next, &sai->sai_entries_received, se_list) { - list_del(&entry->se_list); - ll_sai_entry_cleanup(entry); + list_del_init(&entry->se_list); + ll_sai_entry_cleanup(entry, 1); } list_for_each_entry_safe(entry, next, &sai->sai_entries_stated, se_list) { - list_del(&entry->se_list); - ll_sai_entry_cleanup(entry); + list_del_init(&entry->se_list); + ll_sai_entry_cleanup(entry, 1); } - dput(sai->sai_first); OBD_FREE_PTR(sai); iput(inode); } @@ -294,8 +296,7 @@ ll_sai_entry_set(struct ll_statahead_info *sai, unsigned int index, int stat, ENTRY; if (!list_empty(&sai->sai_entries_sent)) { - list_for_each_entry(entry, &sai->sai_entries_sent, - se_list) { + list_for_each_entry(entry, &sai->sai_entries_sent, se_list) { if (entry->se_index == index) { entry->se_stat = stat; entry->se_req = ptlrpc_request_addref(req); @@ -332,13 +333,15 @@ ll_sai_entry_to_stated(struct ll_statahead_info *sai, struct ll_sai_entry *entry struct ll_sai_entry *se; ENTRY; + ll_sai_entry_cleanup(entry, 0); + spin_lock(&lli->lli_lock); if (!list_empty(&entry->se_list)) list_del_init(&entry->se_list); if (unlikely(entry->se_index < sai->sai_index_next)) { spin_unlock(&lli->lli_lock); - ll_sai_entry_cleanup(entry); + OBD_FREE_PTR(entry); RETURN(0); } @@ -381,18 +384,18 @@ static int do_statahead_interpret(struct ll_statahead_info *sai) spin_unlock(&lli->lli_lock); if (unlikely(entry->se_index < sai->sai_index_next)) { - ll_sai_entry_cleanup(entry); + ll_sai_entry_cleanup(entry, 1); RETURN(0); } + if (entry->se_stat != SA_ENTRY_STATED) + GOTO(out, rc = entry->se_stat); + req = entry->se_req; minfo = entry->se_minfo; dentry = minfo->mi_dentry; it = &minfo->mi_it; - if (entry->se_stat != SA_ENTRY_STATED) - GOTO(out, rc = entry->se_stat); - body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); if (body == NULL) GOTO(out, rc = -EFAULT); @@ -444,6 +447,7 @@ static int do_statahead_interpret(struct ll_statahead_info *sai) GOTO(out, rc); } + spin_lock(&ll_lookup_lock); spin_lock(&dcache_lock); lock_dentry(dentry); __d_drop(dentry); @@ -453,21 +457,15 @@ static int do_statahead_interpret(struct ll_statahead_info *sai) unlock_dentry(dentry); d_rehash_cond(dentry, 0); spin_unlock(&dcache_lock); + spin_unlock(&ll_lookup_lock); ll_lookup_finish_locks(it, dentry); } EXIT; out: - if (likely(ll_sai_entry_to_stated(sai, entry))) { - entry->se_minfo = NULL; - entry->se_req = NULL; + if (likely(ll_sai_entry_to_stated(sai, entry))) cfs_waitq_signal(&sai->sai_waitq); - ll_intent_release(it); - OBD_FREE_PTR(minfo); - dput(dentry); - ptlrpc_req_finished(req); - } return rc; } @@ -495,7 +493,7 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, OBD_FREE_PTR(minfo); RETURN(-ESTALE); } else { - sai = lli->lli_sai; + sai = ll_sai_get(lli->lli_sai); if (rc || dir == NULL) rc = -ESTALE; @@ -514,8 +512,9 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, list_del_init(&entry->se_list); sai->sai_replied++; spin_unlock(&lli->lli_lock); - ll_sai_entry_cleanup(entry); + ll_sai_entry_cleanup(entry, 1); } + ll_sai_put(sai); RETURN(rc); } } @@ -662,18 +661,11 @@ static int do_sa_revalidate(struct dentry *dentry) RETURN(rc); } -static inline void ll_name2qstr(struct qstr *this, const char *name, int namelen) +static inline void ll_name2qstr(struct qstr *q, const char *name, int namelen) { - unsigned long hash = init_name_hash(); - unsigned int c; - - this->name = name; - this->len = namelen; - for (; namelen > 0; namelen--, name++) { - c = *(const unsigned char *)name; - hash = partial_name_hash(c, hash); - } - this->hash = end_name_hash(hash); + q->name = name; + q->len = namelen; + q->hash = full_name_hash(name, namelen); } static int ll_statahead_one(struct dentry *parent, const char* entry_name, @@ -905,22 +897,22 @@ out: void ll_stop_statahead(struct inode *inode, void *key) { struct ll_inode_info *lli = ll_i2info(inode); - struct ptlrpc_thread *thread; + + if (unlikely(key == NULL)) + return; spin_lock(&lli->lli_lock); - if (lli->lli_opendir_pid == 0 || - unlikely(lli->lli_opendir_key != key)) { + if (lli->lli_opendir_key != key || lli->lli_opendir_pid == 0) { spin_unlock(&lli->lli_lock); return; } lli->lli_opendir_key = NULL; - lli->lli_opendir_pid = 0; if (lli->lli_sai) { struct l_wait_info lwi = { 0 }; + struct ptlrpc_thread *thread = &lli->lli_sai->sai_thread; - thread = &lli->lli_sai->sai_thread; if (!sa_is_stopped(lli->lli_sai)) { thread->t_flags = SVC_STOPPING; spin_unlock(&lli->lli_lock); @@ -941,9 +933,10 @@ void ll_stop_statahead(struct inode *inode, void *key) * maybe inflight. */ ll_sai_put(lli->lli_sai); - return; + } else { + lli->lli_opendir_pid = 0; + spin_unlock(&lli->lli_lock); } - spin_unlock(&lli->lli_lock); } enum { @@ -1022,7 +1015,7 @@ static int is_first_dirent(struct inode *dir, struct dentry *dentry) } if (target->len == namelen && - !strncmp(target->name, name, target->len)) + memcmp(target->name, name, namelen) == 0) rc = LS_FIRST_DE + dot_de; else rc = LS_NONE_FIRST_DE; @@ -1081,16 +1074,6 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, int lookup) list_empty(&sai->sai_entries_stated))) RETURN(-EBADFD); - /* - * skip the first dentry. - */ - if (unlikely((*dentryp)->d_name.len == - sai->sai_first->d_name.len && - !strncmp((*dentryp)->d_name.name, - sai->sai_first->d_name.name, - sai->sai_first->d_name.len))) - RETURN(-EEXIST); - if ((*dentryp)->d_name.name[0] == '.') { if (likely(sai->sai_ls_all || sai->sai_miss_hidden >= sai->sai_skip_hidden)) { @@ -1170,9 +1153,16 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, int lookup) if (sai == NULL) RETURN(-ENOMEM); - sai->sai_inode = igrab(dir); - sai->sai_first = dget(*dentryp); sai->sai_ls_all = (rc == LS_FIRST_DOT_DE); + sai->sai_inode = igrab(dir); + if (unlikely(sai->sai_inode == NULL)) { + CWARN("Do not start stat ahead on dying inode "DFID" .\n", + PFID(&lli->lli_fid)); + OBD_FREE_PTR(sai); + RETURN(-ESTALE); + } + + LASSERT(sai->sai_inode == (*dentryp)->d_parent->d_inode); sta.sta_parent = (*dentryp)->d_parent; sta.sta_pid = cfs_curproc_pid(); @@ -1181,6 +1171,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, int lookup) rc = cfs_kernel_thread(ll_statahead_thread, &sta, 0); if (rc < 0) { CERROR("can't start ll_sa thread, rc: %d\n", rc); + lli->lli_opendir_key = NULL; sai->sai_thread.t_flags = SVC_STOPPED; ll_sai_put(sai); LASSERT(lli->lli_sai == NULL); @@ -1206,7 +1197,7 @@ int 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 ll_dentry_data *ldd = ll_d2d(dentry); + int rc = 0; ENTRY; if (lli->lli_opendir_pid != cfs_curproc_pid()) @@ -1244,21 +1235,7 @@ int ll_statahead_exit(struct dentry *dentry, int result) if (!sa_is_stopped(sai)) cfs_waitq_signal(&sai->sai_thread.t_ctl_waitq); ll_sai_entry_fini(sai); - - if (unlikely(ldd == NULL)) { - ll_set_dd(dentry); - ldd = ll_d2d(dentry); - if (ldd != NULL && dentry->d_op == NULL) { - lock_dentry(dentry); - dentry->d_op = dentry->d_op ? : &ll_sai_d_ops; - unlock_dentry(dentry); - } - } - - if (likely(ldd != NULL)) - ldd->lld_sa_generation = sai->sai_generation; - else - RETURN(-ENOMEM); + rc = ll_statahead_mark(dentry); } - RETURN(0); + RETURN(rc); }