Whamcloud - gitweb
LU-4684 llite: add lock for dir layout data 46/32946/15
authorLai Siyao <lai.siyao@intel.com>
Fri, 20 Jul 2018 04:26:41 +0000 (12:26 +0800)
committerOleg Drokin <green@whamcloud.com>
Fri, 2 Nov 2018 07:19:06 +0000 (07:19 +0000)
Directory layout data should be accessed with lock, because
directory migration may change it, if it's accessed without lock,
it may cause crash.

Introduce an rw_semaphore 'lli_lsm_sem', any MD operation that uses
directory layout data will take read lock, and ll_update_lsm_md()
will take write lock when setting lsm.

Signed-off-by: Lai Siyao <lai.siyao@whamcloud.com>
Change-Id: Ice3b15c90eefd6c9dbefbea87cd65f436bec96b1
Reviewed-on: https://review.whamcloud.com/32946
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Mike Pershin <mpershin@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/lustre_lmv.h
lustre/include/obd.h
lustre/llite/dir.c
lustre/llite/file.c
lustre/llite/llite_internal.h
lustre/llite/llite_lib.c
lustre/llite/namei.c
lustre/llite/statahead.c
lustre/lmv/lmv_obd.c

index ff91ff1..d5fb751 100644 (file)
@@ -82,6 +82,23 @@ lsm_md_eq(const struct lmv_stripe_md *lsm1, const struct lmv_stripe_md *lsm2)
 
        return true;
 }
+
+static inline void lsm_md_dump(int mask, const struct lmv_stripe_md *lsm)
+{
+       int i;
+
+       CDEBUG(mask, "magic %#x stripe count %d master mdt %d hash type %#x "
+               "version %d migrate offset %d migrate hash %#x pool %s\n",
+               lsm->lsm_md_magic, lsm->lsm_md_stripe_count,
+               lsm->lsm_md_master_mdt_index, lsm->lsm_md_hash_type,
+               lsm->lsm_md_layout_version, lsm->lsm_md_migrate_offset,
+               lsm->lsm_md_migrate_hash, lsm->lsm_md_pool_name);
+
+       for (i = 0; i < lsm->lsm_md_stripe_count; i++)
+               CDEBUG(mask, "stripe[%d] "DFID"\n",
+                      i, PFID(&lsm->lsm_md_oinfo[i].lmo_fid));
+}
+
 union lmv_mds_md;
 
 void lmv_free_memmd(struct lmv_stripe_md *lsm);
index 78cb375..d005aec 100644 (file)
@@ -843,6 +843,8 @@ struct md_op_data {
        s64                     op_mod_time;
        const char              *op_name;
        size_t                  op_namelen;
+       struct rw_semaphore     *op_mea1_sem;
+       struct rw_semaphore     *op_mea2_sem;
        struct lmv_stripe_md    *op_mea1;
        struct lmv_stripe_md    *op_mea2;
        __u32                   op_suppgids[2];
index 9e07036..e85e975 100644 (file)
@@ -321,6 +321,7 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
        int                     hash64  = sbi->ll_flags & LL_SBI_64BIT_HASH;
        int                     api32   = ll_need_32bit_api(sbi);
        struct md_op_data       *op_data;
+       struct lu_fid           pfid = { 0 };
        __u64                   pos;
        int                     rc;
        ENTRY;
@@ -340,12 +341,7 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
                 */
                GOTO(out, rc = 0);
 
-       op_data = ll_prep_md_op_data(NULL, inode, inode, NULL, 0, 0,
-                                    LUSTRE_OPC_ANY, inode);
-       if (IS_ERR(op_data))
-               GOTO(out, rc = PTR_ERR(op_data));
-
-       if (unlikely(op_data->op_mea1 != NULL)) {
+       if (unlikely(ll_i2info(inode)->lli_lsm_md != NULL)) {
                /* This is only needed for striped dir to fill ..,
                 * see lmv_read_entry */
                if (file_dentry(filp)->d_parent != NULL &&
@@ -355,19 +351,24 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
                                file_dentry(filp)->d_parent->d_inode;
 
                        if (ll_have_md_lock(parent, &ibits, LCK_MINMODE))
-                               op_data->op_fid3 = *ll_inode2fid(parent);
+                               pfid = *ll_inode2fid(parent);
                }
 
                /* If it can not find in cache, do lookup .. on the master
                 * object */
-               if (fid_is_zero(&op_data->op_fid3)) {
-                       rc = ll_dir_get_parent_fid(inode, &op_data->op_fid3);
-                       if (rc != 0) {
-                               ll_finish_md_op_data(op_data);
+               if (fid_is_zero(&pfid)) {
+                       rc = ll_dir_get_parent_fid(inode, &pfid);
+                       if (rc != 0)
                                RETURN(rc);
-                       }
                }
        }
+
+       op_data = ll_prep_md_op_data(NULL, inode, inode, NULL, 0, 0,
+                                    LUSTRE_OPC_ANY, inode);
+       if (IS_ERR(op_data))
+               GOTO(out, rc = PTR_ERR(op_data));
+       op_data->op_fid3 = pfid;
+
 #ifdef HAVE_DIR_CONTEXT
        ctx->pos = pos;
        rc = ll_dir_read(inode, &pos, op_data, ctx);
index a1b43b6..157bd4b 100644 (file)
@@ -4428,12 +4428,15 @@ out:
 
 static int ll_merge_md_attr(struct inode *inode)
 {
+       struct ll_inode_info *lli = ll_i2info(inode);
        struct cl_attr attr = { 0 };
        int rc;
 
-       LASSERT(ll_i2info(inode)->lli_lsm_md != NULL);
+       LASSERT(lli->lli_lsm_md != NULL);
+       down_read(&lli->lli_lsm_sem);
        rc = md_merge_attr(ll_i2mdexp(inode), ll_i2info(inode)->lli_lsm_md,
                           &attr, ll_md_blocking_ast);
+       up_read(&lli->lli_lsm_sem);
        if (rc != 0)
                RETURN(rc);
 
index a9a7d96..45cf1a0 100644 (file)
@@ -166,6 +166,8 @@ struct ll_inode_info {
                        unsigned int                    lli_sa_enabled:1;
                        /* generation for statahead */
                        unsigned int                    lli_sa_generation;
+                       /* rw lock protects lli_lsm_md */
+                       struct rw_semaphore             lli_lsm_sem;
                        /* directory stripe information */
                        struct lmv_stripe_md            *lli_lsm_md;
                        /* default directory stripe offset.  This is extracted
@@ -978,6 +980,7 @@ enum {
        LUSTRE_OPC_ANY          = 5,
 };
 
+void ll_unlock_md_op_lsm(struct md_op_data *op_data);
 struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
                                      struct inode *i1, struct inode *i2,
                                      const char *name, size_t namelen,
index 28acbb6..654c874 100644 (file)
@@ -953,6 +953,7 @@ void ll_lli_init(struct ll_inode_info *lli)
                lli->lli_opendir_pid = 0;
                lli->lli_sa_enabled = 0;
                lli->lli_def_stripe_offset = -1;
+               init_rwsem(&lli->lli_lsm_sem);
        } else {
                mutex_init(&lli->lli_size_mutex);
                lli->lli_symlink_name = NULL;
@@ -1308,9 +1309,16 @@ static int ll_init_lsm_md(struct inode *inode, struct lustre_md *md)
 {
        struct lu_fid *fid;
        struct lmv_stripe_md *lsm = md->lmv;
+       struct ll_inode_info *lli = ll_i2info(inode);
        int i;
 
        LASSERT(lsm != NULL);
+
+       CDEBUG(D_INODE, "%s: "DFID" set dir layout:\n",
+               ll_get_fsname(inode->i_sb, NULL, 0),
+               PFID(&lli->lli_fid));
+       lsm_md_dump(D_INODE, lsm);
+
        /* XXX sigh, this lsm_root initialization should be in
         * LMV layer, but it needs ll_iget right now, so we
         * put this here right now. */
@@ -1327,10 +1335,16 @@ static int ll_init_lsm_md(struct inode *inode, struct lustre_md *md)
                        int rc = PTR_ERR(lsm->lsm_md_oinfo[i].lmo_root);
 
                        lsm->lsm_md_oinfo[i].lmo_root = NULL;
+                       while (i-- > 0) {
+                               iput(lsm->lsm_md_oinfo[i].lmo_root);
+                               lsm->lsm_md_oinfo[i].lmo_root = NULL;
+                       }
                        return rc;
                }
        }
 
+       lli->lli_lsm_md = lsm;
+
        return 0;
 }
 
@@ -1338,7 +1352,8 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
 {
        struct ll_inode_info *lli = ll_i2info(inode);
        struct lmv_stripe_md *lsm = md->lmv;
-       int     rc;
+       int rc = 0;
+
        ENTRY;
 
        LASSERT(S_ISDIR(inode->i_mode));
@@ -1352,75 +1367,65 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
        if (!lsm)
                RETURN(0);
 
-       /* Compare the old and new stripe information */
+       /*
+        * normally dir layout doesn't change, only take read lock to check
+        * that to avoid blocking other MD operations.
+        */
+       if (lli->lli_lsm_md)
+               down_read(&lli->lli_lsm_sem);
+       else
+               down_write(&lli->lli_lsm_sem);
+
+       /*
+        * if dir layout mismatch, check whether version is increased, which
+        * means layout is changed, this happens in dir migration and lfsck.
+        */
        if (lli->lli_lsm_md && !lsm_md_eq(lli->lli_lsm_md, lsm)) {
-               struct lmv_stripe_md *old_lsm = lli->lli_lsm_md;
-               int idx;
-               bool layout_changed = lsm->lsm_md_layout_version >
-                                     old_lsm->lsm_md_layout_version;
-
-               int mask = layout_changed ? D_INODE : D_ERROR;
-
-               CDEBUG(mask,
-                       "%s: inode@%p "DFID" lmv layout %s magic %#x/%#x "
-                       "stripe count %d/%d master_mdt %d/%d "
-                       "hash_type %#x/%#x version %d/%d migrate offset %d/%d "
-                       "migrate hash %#x/%#x pool %s/%s\n",
-                      ll_get_fsname(inode->i_sb, NULL, 0), inode,
-                      PFID(&lli->lli_fid),
-                      layout_changed ? "changed" : "mismatch",
-                      lsm->lsm_md_magic, old_lsm->lsm_md_magic,
-                      lsm->lsm_md_stripe_count,
-                      old_lsm->lsm_md_stripe_count,
-                      lsm->lsm_md_master_mdt_index,
-                      old_lsm->lsm_md_master_mdt_index,
-                      lsm->lsm_md_hash_type, old_lsm->lsm_md_hash_type,
-                      lsm->lsm_md_layout_version,
-                      old_lsm->lsm_md_layout_version,
-                      lsm->lsm_md_migrate_offset,
-                      old_lsm->lsm_md_migrate_offset,
-                      lsm->lsm_md_migrate_hash,
-                      old_lsm->lsm_md_migrate_hash,
-                      lsm->lsm_md_pool_name,
-                      old_lsm->lsm_md_pool_name);
-
-               for (idx = 0; idx < old_lsm->lsm_md_stripe_count; idx++)
-                       CDEBUG(mask, "old stripe[%d] "DFID"\n",
-                              idx, PFID(&old_lsm->lsm_md_oinfo[idx].lmo_fid));
-
-               for (idx = 0; idx < lsm->lsm_md_stripe_count; idx++)
-                       CDEBUG(mask, "new stripe[%d] "DFID"\n",
-                              idx, PFID(&lsm->lsm_md_oinfo[idx].lmo_fid));
-
-               if (!layout_changed)
-                       RETURN(-EINVAL);
+               if (lsm->lsm_md_layout_version <=
+                   lli->lli_lsm_md->lsm_md_layout_version) {
+                       CERROR("%s: "DFID" dir layout mismatch:\n",
+                               ll_get_fsname(inode->i_sb, NULL, 0),
+                               PFID(&lli->lli_fid));
+                       lsm_md_dump(D_ERROR, lli->lli_lsm_md);
+                       lsm_md_dump(D_ERROR, lsm);
+                       GOTO(unlock, rc = -EINVAL);
+               }
 
+               /* layout changed, switch to write lock */
+               up_read(&lli->lli_lsm_sem);
+               down_write(&lli->lli_lsm_sem);
                ll_dir_clear_lsm_md(inode);
        }
 
-       /* set the directory layout */
+       /* set directory layout */
        if (!lli->lli_lsm_md) {
                struct cl_attr  *attr;
 
                rc = ll_init_lsm_md(inode, md);
+               up_write(&lli->lli_lsm_sem);
                if (rc != 0)
                        RETURN(rc);
 
                /* set md->lmv to NULL, so the following free lustre_md
                 * will not free this lsm */
                md->lmv = NULL;
-               lli->lli_lsm_md = lsm;
+
+               /*
+                * md_merge_attr() may take long, since lsm is already set,
+                * switch to read lock.
+                */
+               down_read(&lli->lli_lsm_sem);
 
                OBD_ALLOC_PTR(attr);
                if (attr == NULL)
-                       RETURN(-ENOMEM);
+                       GOTO(unlock, rc = -ENOMEM);
 
                /* validate the lsm */
                rc = md_merge_attr(ll_i2mdexp(inode), lsm, attr,
                                   ll_md_blocking_ast);
                if (rc != 0) {
                        OBD_FREE_PTR(attr);
-                       RETURN(rc);
+                       GOTO(unlock, rc);
                }
 
                if (md->body->mbo_valid & OBD_MD_FLNLINK)
@@ -1435,49 +1440,11 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
                        md->body->mbo_mtime = attr->cat_mtime;
 
                OBD_FREE_PTR(attr);
-
-               CDEBUG(D_INODE, "Set lsm %p magic %x to "DFID"\n", lsm,
-                      lsm->lsm_md_magic, PFID(ll_inode2fid(inode)));
-               RETURN(0);
-       }
-
-       /* Compare the old and new stripe information */
-       if (!lsm_md_eq(lli->lli_lsm_md, lsm)) {
-               struct lmv_stripe_md    *old_lsm = lli->lli_lsm_md;
-               int                     idx;
-
-               CERROR("%s: inode "DFID"(%p)'s lmv layout mismatch (%p)/(%p)"
-                      "magic:0x%x/0x%x stripe count: %d/%d master_mdt: %d/%d"
-                      "hash_type:0x%x/0x%x layout: 0x%x/0x%x pool:%s/%s\n",
-                      ll_get_fsname(inode->i_sb, NULL, 0), PFID(&lli->lli_fid),
-                      inode, lsm, old_lsm,
-                      lsm->lsm_md_magic, old_lsm->lsm_md_magic,
-                      lsm->lsm_md_stripe_count,
-                      old_lsm->lsm_md_stripe_count,
-                      lsm->lsm_md_master_mdt_index,
-                      old_lsm->lsm_md_master_mdt_index,
-                      lsm->lsm_md_hash_type, old_lsm->lsm_md_hash_type,
-                      lsm->lsm_md_layout_version,
-                      old_lsm->lsm_md_layout_version,
-                      lsm->lsm_md_pool_name,
-                      old_lsm->lsm_md_pool_name);
-
-               for (idx = 0; idx < old_lsm->lsm_md_stripe_count; idx++) {
-                       CERROR("%s: sub FIDs in old lsm idx %d, old: "DFID"\n",
-                              ll_get_fsname(inode->i_sb, NULL, 0), idx,
-                              PFID(&old_lsm->lsm_md_oinfo[idx].lmo_fid));
-               }
-
-               for (idx = 0; idx < lsm->lsm_md_stripe_count; idx++) {
-                       CERROR("%s: sub FIDs in new lsm idx %d, new: "DFID"\n",
-                              ll_get_fsname(inode->i_sb, NULL, 0), idx,
-                              PFID(&lsm->lsm_md_oinfo[idx].lmo_fid));
-               }
-
-               RETURN(-EIO);
        }
+unlock:
+       up_read(&lli->lli_lsm_sem);
 
-       RETURN(0);
+       RETURN(rc);
 }
 
 void ll_clear_inode(struct inode *inode)
@@ -2502,6 +2469,23 @@ out_statfs:
        return rc;
 }
 
+/*
+ * this is normally called in ll_fini_md_op_data(), but sometimes it needs to
+ * be called early to avoid deadlock.
+ */
+void ll_unlock_md_op_lsm(struct md_op_data *op_data)
+{
+       if (op_data->op_mea2_sem) {
+               up_read(op_data->op_mea2_sem);
+               op_data->op_mea2_sem = NULL;
+       }
+
+       if (op_data->op_mea1_sem) {
+               up_read(op_data->op_mea1_sem);
+               op_data->op_mea1_sem = NULL;
+       }
+}
+
 /* this function prepares md_op_data hint for passing it down to MD stack. */
 struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
                                      struct inode *i1, struct inode *i2,
@@ -2531,7 +2515,10 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
        ll_i2gids(op_data->op_suppgids, i1, i2);
        op_data->op_fid1 = *ll_inode2fid(i1);
        op_data->op_default_stripe_offset = -1;
+
        if (S_ISDIR(i1->i_mode)) {
+               down_read(&ll_i2info(i1)->lli_lsm_sem);
+               op_data->op_mea1_sem = &ll_i2info(i1)->lli_lsm_sem;
                op_data->op_mea1 = ll_i2info(i1)->lli_lsm_md;
                if (opc == LUSTRE_OPC_MKDIR)
                        op_data->op_default_stripe_offset =
@@ -2540,8 +2527,14 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
 
        if (i2) {
                op_data->op_fid2 = *ll_inode2fid(i2);
-               if (S_ISDIR(i2->i_mode))
+               if (S_ISDIR(i2->i_mode)) {
+                       if (i2 != i1) {
+                               down_read(&ll_i2info(i2)->lli_lsm_sem);
+                               op_data->op_mea2_sem =
+                                               &ll_i2info(i2)->lli_lsm_sem;
+                       }
                        op_data->op_mea2 = ll_i2info(i2)->lli_lsm_md;
+               }
        } else {
                fid_zero(&op_data->op_fid2);
        }
@@ -2571,6 +2564,7 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
 
 void ll_finish_md_op_data(struct md_op_data *op_data)
 {
+       ll_unlock_md_op_lsm(op_data);
        security_release_secctx(op_data->op_file_secctx,
                                op_data->op_file_secctx_size);
         OBD_FREE_PTR(op_data);
index 8abf542..3c63e23 100644 (file)
@@ -775,6 +775,8 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
        if (rc < 0)
                GOTO(out, retval = ERR_PTR(rc));
 
+       /* dir layout may change */
+       ll_unlock_md_op_lsm(op_data);
        rc = ll_lookup_it_finish(req, it, parent, &dentry);
         if (rc != 0) {
                 ll_intent_release(it);
index 22203ce..3977129 100644 (file)
@@ -330,6 +330,58 @@ __sa_make_ready(struct ll_statahead_info *sai, struct sa_entry *entry, int ret)
        return (index == sai->sai_index_wait);
 }
 
+/* finish async stat RPC arguments */
+static void sa_fini_data(struct md_enqueue_info *minfo)
+{
+       ll_unlock_md_op_lsm(&minfo->mi_data);
+       iput(minfo->mi_dir);
+       OBD_FREE_PTR(minfo);
+}
+
+static int ll_statahead_interpret(struct ptlrpc_request *req,
+                                 struct md_enqueue_info *minfo, int rc);
+
+/*
+ * prepare arguments for async stat RPC.
+ */
+static struct md_enqueue_info *
+sa_prep_data(struct inode *dir, struct inode *child, struct sa_entry *entry)
+{
+       struct md_enqueue_info   *minfo;
+       struct ldlm_enqueue_info *einfo;
+       struct md_op_data        *op_data;
+
+       OBD_ALLOC_PTR(minfo);
+       if (minfo == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       op_data = ll_prep_md_op_data(&minfo->mi_data, dir, child,
+                                    entry->se_qstr.name, entry->se_qstr.len, 0,
+                                    LUSTRE_OPC_ANY, NULL);
+       if (IS_ERR(op_data)) {
+               OBD_FREE_PTR(minfo);
+               return (struct md_enqueue_info *)op_data;
+       }
+
+       if (child == NULL)
+               op_data->op_fid2 = entry->se_fid;
+
+       minfo->mi_it.it_op = IT_GETATTR;
+       minfo->mi_dir = igrab(dir);
+       minfo->mi_cb = ll_statahead_interpret;
+       minfo->mi_cbdata = entry;
+
+       einfo = &minfo->mi_einfo;
+       einfo->ei_type   = LDLM_IBITS;
+       einfo->ei_mode   = it_to_lock_mode(&minfo->mi_it);
+       einfo->ei_cb_bl  = ll_md_blocking_ast;
+       einfo->ei_cb_cp  = ldlm_completion_ast;
+       einfo->ei_cb_gl  = NULL;
+       einfo->ei_cbdata = NULL;
+
+       return minfo;
+}
+
 /*
  * release resources used in async stat RPC, update entry state and wakeup if
  * scanner process it waiting on this entry.
@@ -346,8 +398,7 @@ sa_make_ready(struct ll_statahead_info *sai, struct sa_entry *entry, int ret)
        if (minfo) {
                entry->se_minfo = NULL;
                ll_intent_release(&minfo->mi_it);
-               iput(minfo->mi_dir);
-               OBD_FREE_PTR(minfo);
+               sa_fini_data(minfo);
        }
 
        if (req) {
@@ -582,14 +633,14 @@ static void sa_instantiate(struct ll_statahead_info *sai,
        int rc = 0;
        ENTRY;
 
-        LASSERT(entry->se_handle != 0);
+       LASSERT(entry->se_handle != 0);
 
-        minfo = entry->se_minfo;
-        it = &minfo->mi_it;
-        req = entry->se_req;
-        body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
-        if (body == NULL)
-                GOTO(out, rc = -EFAULT);
+       minfo = entry->se_minfo;
+       it = &minfo->mi_it;
+       req = entry->se_req;
+       body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+       if (body == NULL)
+               GOTO(out, rc = -EFAULT);
 
        child = entry->se_inode;
        if (child != NULL) {
@@ -604,25 +655,25 @@ static void sa_instantiate(struct ll_statahead_info *sai,
 
        it->it_lock_handle = entry->se_handle;
        rc = md_revalidate_lock(ll_i2mdexp(dir), it, ll_inode2fid(dir), NULL);
-        if (rc != 1)
-                GOTO(out, rc = -EAGAIN);
+       if (rc != 1)
+               GOTO(out, rc = -EAGAIN);
 
-        rc = ll_prep_inode(&child, req, dir->i_sb, it);
-        if (rc)
-                GOTO(out, rc);
+       rc = ll_prep_inode(&child, req, dir->i_sb, it);
+       if (rc)
+               GOTO(out, rc);
 
        CDEBUG(D_READA, "%s: setting %.*s"DFID" l_data to inode %p\n",
               ll_get_fsname(child->i_sb, NULL, 0),
               entry->se_qstr.len, entry->se_qstr.name,
               PFID(ll_inode2fid(child)), child);
-        ll_set_lock_data(ll_i2sbi(dir)->ll_md_exp, child, it, NULL);
+       ll_set_lock_data(ll_i2sbi(dir)->ll_md_exp, child, it, NULL);
 
-        entry->se_inode = child;
+       entry->se_inode = child;
 
-        if (agl_should_run(sai, child))
-                ll_agl_add(sai, child, entry->se_index);
+       if (agl_should_run(sai, child))
+               ll_agl_add(sai, child, entry->se_index);
 
-        EXIT;
+       EXIT;
 
 out:
        /* sa_make_ready() will drop ldlm ibits lock refcount by calling
@@ -686,8 +737,7 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
 
        if (rc != 0) {
                ll_intent_release(it);
-               iput(dir);
-               OBD_FREE_PTR(minfo);
+               sa_fini_data(minfo);
        } else {
                /* release ibits lock ASAP to avoid deadlock when statahead
                 * thread enqueues lock on parent in readdir and another
@@ -695,6 +745,7 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
                 * unlink. */
                handle = it->it_lock_handle;
                ll_intent_drop_lock(it);
+               ll_unlock_md_op_lsm(&minfo->mi_data);
        }
 
        spin_lock(&lli->lli_sa_lock);
@@ -724,54 +775,6 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
        RETURN(rc);
 }
 
-/* finish async stat RPC arguments */
-static void sa_fini_data(struct md_enqueue_info *minfo)
-{
-        iput(minfo->mi_dir);
-        OBD_FREE_PTR(minfo);
-}
-
-/*
- * prepare arguments for async stat RPC.
- */
-static struct md_enqueue_info *
-sa_prep_data(struct inode *dir, struct inode *child, struct sa_entry *entry)
-{
-       struct md_enqueue_info   *minfo;
-       struct ldlm_enqueue_info *einfo;
-       struct md_op_data        *op_data;
-
-       OBD_ALLOC_PTR(minfo);
-       if (minfo == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       op_data = ll_prep_md_op_data(&minfo->mi_data, dir, child,
-                                    entry->se_qstr.name, entry->se_qstr.len, 0,
-                                    LUSTRE_OPC_ANY, NULL);
-       if (IS_ERR(op_data)) {
-               OBD_FREE_PTR(minfo);
-               return (struct md_enqueue_info *)op_data;
-       }
-
-       if (child == NULL)
-               op_data->op_fid2 = entry->se_fid;
-
-       minfo->mi_it.it_op = IT_GETATTR;
-       minfo->mi_dir = igrab(dir);
-       minfo->mi_cb = ll_statahead_interpret;
-       minfo->mi_cbdata = entry;
-
-       einfo = &minfo->mi_einfo;
-       einfo->ei_type   = LDLM_IBITS;
-       einfo->ei_mode   = it_to_lock_mode(&minfo->mi_it);
-       einfo->ei_cb_bl  = ll_md_blocking_ast;
-       einfo->ei_cb_cp  = ldlm_completion_ast;
-       einfo->ei_cb_gl  = NULL;
-       einfo->ei_cbdata = NULL;
-
-       return minfo;
-}
-
 /* async stat for file not found in dcache */
 static int sa_lookup(struct inode *dir, struct sa_entry *entry)
 {
@@ -813,22 +816,20 @@ static int sa_revalidate(struct inode *dir, struct sa_entry *entry,
        if (d_mountpoint(dentry))
                RETURN(1);
 
+       minfo = sa_prep_data(dir, inode, entry);
+       if (IS_ERR(minfo))
+               RETURN(PTR_ERR(minfo));
+
        entry->se_inode = igrab(inode);
        rc = md_revalidate_lock(ll_i2mdexp(dir), &it, ll_inode2fid(inode),
                                NULL);
        if (rc == 1) {
                entry->se_handle = it.it_lock_handle;
                ll_intent_release(&it);
+               sa_fini_data(minfo);
                RETURN(1);
        }
 
-       minfo = sa_prep_data(dir, inode, entry);
-       if (IS_ERR(minfo)) {
-               entry->se_inode = NULL;
-               iput(inode);
-               RETURN(PTR_ERR(minfo));
-       }
-
        rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo);
        if (rc < 0) {
                entry->se_inode = NULL;
@@ -1003,8 +1004,7 @@ static int ll_statahead_thread(void *arg)
        CDEBUG(D_READA, "statahead thread starting: sai %p, parent %.*s\n",
               sai, parent->d_name.len, parent->d_name.name);
 
-       op_data = ll_prep_md_op_data(NULL, dir, dir, NULL, 0, 0,
-                                    LUSTRE_OPC_ANY, dir);
+       OBD_ALLOC_PTR(op_data);
        if (IS_ERR(op_data))
                GOTO(out, rc = PTR_ERR(op_data));
 
@@ -1026,8 +1026,16 @@ static int ll_statahead_thread(void *arg)
                struct lu_dirpage *dp;
                struct lu_dirent  *ent;
 
+               op_data = ll_prep_md_op_data(op_data, dir, dir, NULL, 0, 0,
+                                    LUSTRE_OPC_ANY, dir);
+               if (IS_ERR(op_data)) {
+                       rc = PTR_ERR(op_data);
+                       break;
+               }
+
                sai->sai_in_readpage = 1;
                page = ll_get_dir_page(dir, op_data, pos, &chain);
+               ll_unlock_md_op_lsm(op_data);
                sai->sai_in_readpage = 0;
                if (IS_ERR(page)) {
                        rc = PTR_ERR(page);
index f2db29f..090f3b1 100644 (file)
@@ -1937,8 +1937,6 @@ static int lmv_migrate(struct obd_export *exp, struct md_op_data *op_data,
        ENTRY;
 
        LASSERT(op_data->op_cli_flags & CLI_MIGRATE);
-       LASSERTF(fid_is_sane(&op_data->op_fid3), "invalid FID "DFID"\n",
-                PFID(&op_data->op_fid3));
 
        CDEBUG(D_INODE, "MIGRATE "DFID"/%.*s\n",
               PFID(&op_data->op_fid1), (int)namelen, name);