Whamcloud - gitweb
LU-11135 mdt: LASSERT(lu_object_exists(o)) fails
[fs/lustre-release.git] / lustre / mdt / mdt_reint.c
index 602072d..62308a8 100644 (file)
@@ -707,6 +707,15 @@ static int mdt_reint_setattr(struct mdt_thread_info *info,
                        if (rc > 0 && mdt_lmm_is_flr(info->mti_big_lmm))
                                GOTO(out_put, rc = -EOPNOTSUPP);
                }
+
+               /* For truncate, the file size sent from client
+                * is believable, but the blocks are incorrect,
+                * which makes the block size in LSOM attribute
+                * inconsisent with the real block size.
+                */
+               rc = mdt_lsom_update(info, mo, true);
+               if (rc)
+                       GOTO(out_put, rc);
        }
 
        if ((ma->ma_valid & MA_INODE) && ma->ma_attr.la_valid) {
@@ -838,7 +847,7 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
        struct mdt_lock_handle *child_lh;
        struct ldlm_enqueue_info *einfo = &info->mti_einfo;
        __u64 lock_ibits;
-       bool cos_incompat = false;
+       bool cos_incompat = false, discard = false;
        int no_name = 0;
        int rc;
 
@@ -1020,7 +1029,7 @@ relock:
                if (rc)
                        GOTO(out_stat, rc);
        } else {
-               mdt_dom_check_and_discard(info, mc);
+               discard = true;
        }
        mdt_handle_last_unlink(info, mc, ma);
 
@@ -1049,6 +1058,8 @@ out_stat:
 unlock_child:
        mdt_reint_striped_unlock(info, mc, child_lh, einfo, rc);
 put_child:
+       if (discard)
+               mdt_dom_check_and_discard(info, mc);
        mdt_object_put(info->mti_env, mc);
 unlock_parent:
        mdt_object_unlock(info, mp, parent_lh, rc);
@@ -1266,45 +1277,6 @@ static void mdt_rename_unlock(struct lustre_handle *lh)
        EXIT;
 }
 
-/*
- * This is is_subdir() variant, it is CMD if cmm forwards it to correct
- * target. Source should not be ancestor of target dir. May be other rename
- * checks can be moved here later.
- */
-static int mdt_is_subdir(struct mdt_thread_info *info,
-                        struct mdt_object *dir,
-                        const struct lu_fid *fid)
-{
-       struct lu_fid dir_fid = dir->mot_header.loh_fid;
-        int rc = 0;
-        ENTRY;
-
-       /* If the source and target are in the same directory, they can not
-        * be parent/child relationship, so subdir check is not needed */
-       if (lu_fid_eq(&dir_fid, fid))
-               return 0;
-
-       if (!mdt_object_exists(dir))
-               RETURN(-ENOENT);
-
-       rc = mdo_is_subdir(info->mti_env, mdt_object_child(dir),
-                          fid, &dir_fid);
-       if (rc < 0) {
-               CERROR("%s: failed subdir check in "DFID" for "DFID
-                      ": rc = %d\n", mdt_obd_name(info->mti_mdt),
-                      PFID(&dir_fid), PFID(fid), rc);
-               /* Return EINVAL only if a parent is the @fid */
-               if (rc == -EINVAL)
-                       rc = -EIO;
-       } else {
-               /* check the found fid */
-               if (lu_fid_eq(&dir_fid, fid))
-                       rc = -EINVAL;
-       }
-
-        RETURN(rc);
-}
-
 /* Update object linkEA */
 struct mdt_lock_list {
        struct mdt_object       *mll_obj;
@@ -1532,6 +1504,13 @@ static int mdt_reint_migrate_internal(struct mdt_thread_info *info,
        if (IS_ERR(mold))
                GOTO(out_unlock_parent, rc = PTR_ERR(mold));
 
+       if (!mdt_object_exists(mold)) {
+               LU_OBJECT_DEBUG(D_INODE, info->mti_env,
+                               &mold->mot_obj,
+                               "object does not exist");
+               GOTO(out_put_child, rc = -ENOENT);
+       }
+
        if (mdt_object_remote(mold)) {
                CDEBUG(D_OTHER, "%s: source "DFID" is on the remote MDT\n",
                       mdt_obd_name(info->mti_mdt), PFID(old_fid));
@@ -1786,6 +1765,98 @@ static int mdt_object_lock_save(struct mdt_thread_info *info,
 }
 
 /*
+ * determine lock order of sobj and tobj
+ *
+ * there are two situations we need to lock tobj before sobj:
+ * 1. sobj is child of tobj
+ * 2. sobj and tobj are stripes of a directory, and stripe index of sobj is
+ *    larger than that of tobj
+ *
+ * \retval     1 lock tobj before sobj
+ * \retval     0 lock sobj before tobj
+ * \retval     -ev negative errno upon error
+ */
+static int mdt_rename_determine_lock_order(struct mdt_thread_info *info,
+                                          struct mdt_object *sobj,
+                                          struct mdt_object *tobj)
+{
+       struct md_attr *ma = &info->mti_attr;
+       struct lu_fid *spfid = &info->mti_tmp_fid1;
+       struct lu_fid *tpfid = &info->mti_tmp_fid2;
+       struct lmv_mds_md_v1 *lmv;
+       __u32 sindex;
+       __u32 tindex;
+       int rc;
+
+       /* sobj and tobj are the same */
+       if (sobj == tobj)
+               return 0;
+
+       if (fid_is_root(mdt_object_fid(sobj)))
+               return 0;
+
+       if (fid_is_root(mdt_object_fid(tobj)))
+               return 1;
+
+       /* check whether sobj is child of tobj */
+       rc = mdo_is_subdir(info->mti_env, mdt_object_child(sobj),
+                          mdt_object_fid(tobj));
+       if (rc < 0)
+               return rc;
+
+       if (rc == 1)
+               return 1;
+
+       /* check whether sobj and tobj are children of the same parent */
+       rc = mdt_attr_get_pfid(info, sobj, spfid);
+       if (rc)
+               return rc;
+
+       rc = mdt_attr_get_pfid(info, tobj, tpfid);
+       if (rc)
+               return rc;
+
+       if (!lu_fid_eq(spfid, tpfid))
+               return 0;
+
+       /* check whether sobj and tobj are sibling stripes */
+       ma->ma_need = MA_LMV;
+       ma->ma_valid = 0;
+       ma->ma_lmv = (union lmv_mds_md *)info->mti_xattr_buf;
+       ma->ma_lmv_size = sizeof(info->mti_xattr_buf);
+       rc = mdt_stripe_get(info, sobj, ma, XATTR_NAME_LMV);
+       if (rc)
+               return rc;
+
+       if (!(ma->ma_valid & MA_LMV))
+               return 0;
+
+       lmv = &ma->ma_lmv->lmv_md_v1;
+       if (!(le32_to_cpu(lmv->lmv_magic) & LMV_MAGIC_STRIPE))
+               return 0;
+       sindex = le32_to_cpu(lmv->lmv_master_mdt_index);
+
+       ma->ma_valid = 0;
+       rc = mdt_stripe_get(info, tobj, ma, XATTR_NAME_LMV);
+       if (rc)
+               return rc;
+
+       if (!(ma->ma_valid & MA_LMV))
+               return -ENODATA;
+
+       lmv = &ma->ma_lmv->lmv_md_v1;
+       if (!(le32_to_cpu(lmv->lmv_magic) & LMV_MAGIC_STRIPE))
+               return -EINVAL;
+       tindex = le32_to_cpu(lmv->lmv_master_mdt_index);
+
+       /* check stripe index of sobj and tobj */
+       if (sindex == tindex)
+               return -EINVAL;
+
+       return sindex < tindex ? 0 : 1;
+}
+
+/*
  * VBR: rename versions in reply: 0 - srcdir parent; 1 - tgtdir parent;
  * 2 - srcdir child; 3 - tgtdir child.
  * Update on disk version of srcdir child.
@@ -1819,7 +1890,7 @@ static int mdt_reint_rename_internal(struct mdt_thread_info *info,
        struct lu_fid *new_fid = &info->mti_tmp_fid2;
        __u64 lock_ibits;
        bool reverse = false;
-       bool cos_incompat;
+       bool cos_incompat, discard = false;
        int rc;
        ENTRY;
 
@@ -1838,19 +1909,17 @@ static int mdt_reint_rename_internal(struct mdt_thread_info *info,
                mtgtdir = msrcdir;
                mdt_object_get(info->mti_env, mtgtdir);
        } else {
-               /* Check if the @msrcdir is not a child of the @mtgtdir,
-                * otherwise a reverse locking must take place. */
-               rc = mdt_is_subdir(info, msrcdir, rr->rr_fid2);
-               if (rc == -EINVAL)
-                       reverse = true;
-               else if (rc)
-                       GOTO(out_put_srcdir, rc);
-
                mtgtdir = mdt_object_find_check(info, rr->rr_fid2, 1);
                if (IS_ERR(mtgtdir))
                        GOTO(out_put_srcdir, rc = PTR_ERR(mtgtdir));
        }
 
+       rc = mdt_rename_determine_lock_order(info, msrcdir, mtgtdir);
+       if (rc < 0)
+               GOTO(out_put_tgtdir, rc);
+
+       reverse = rc;
+
        /* source needs to be looked up after locking source parent, otherwise
         * this rename may race with unlink source, and cause rename hang, see
         * sanityn.sh 55b, so check parents first, if later we found source is
@@ -1925,12 +1994,23 @@ relock:
        if (IS_ERR(mold))
                GOTO(out_unlock_parents, rc = PTR_ERR(mold));
 
+       if (!mdt_object_exists(mold)) {
+               LU_OBJECT_DEBUG(D_INODE, info->mti_env,
+                               &mold->mot_obj,
+                               "object does not exist");
+               GOTO(out_put_old, rc = -ENOENT);
+       }
+
        /* Check if @mtgtdir is subdir of @mold, before locking child
         * to avoid reverse locking. */
        if (mtgtdir != msrcdir) {
-               rc = mdt_is_subdir(info, mtgtdir, old_fid);
-               if (rc)
+               rc = mdo_is_subdir(info->mti_env, mdt_object_child(mtgtdir),
+                                  old_fid);
+               if (rc) {
+                       if (rc == 1)
+                               rc = -EINVAL;
                        GOTO(out_put_old, rc);
+               }
        }
 
        tgt_vbr_obj_set(info->mti_env, mdt_obj2dt(mold));
@@ -1967,6 +2047,13 @@ relock:
                if (IS_ERR(mnew))
                        GOTO(out_put_old, rc = PTR_ERR(mnew));
 
+               if (!mdt_object_exists(mnew)) {
+                       LU_OBJECT_DEBUG(D_INODE, info->mti_env,
+                                       &mnew->mot_obj,
+                                       "object does not exist");
+                       GOTO(out_put_new, rc = -ENOENT);
+               }
+
                if (mdt_object_remote(mnew)) {
                        struct mdt_body  *repbody;
 
@@ -2011,9 +2098,13 @@ relock:
                /* Check if @msrcdir is subdir of @mnew, before locking child
                 * to avoid reverse locking. */
                if (mtgtdir != msrcdir) {
-                       rc = mdt_is_subdir(info, msrcdir, new_fid);
-                       if (rc)
+                       rc = mdo_is_subdir(info->mti_env,
+                                          mdt_object_child(msrcdir), new_fid);
+                       if (rc) {
+                               if (rc == 1)
+                                       rc = -EINVAL;
                                GOTO(out_unlock_old, rc);
+                       }
                }
 
                /* We used to acquire MDS_INODELOCK_FULL here but we
@@ -2082,7 +2173,7 @@ relock:
                mdt_counter_incr(req, LPROC_MDT_RENAME);
                if (mnew) {
                        mdt_handle_last_unlink(info, mnew, ma);
-                       mdt_dom_check_and_discard(info, mnew);
+                       discard = true;
                }
 
                mdt_rename_counter_tally(info, info->mti_mdt, req,
@@ -2095,8 +2186,11 @@ relock:
 out_unlock_old:
        mdt_object_unlock(info, mold, lh_oldp, rc);
 out_put_new:
-       if (mnew != NULL)
+       if (mnew != NULL) {
+               if (discard)
+                       mdt_dom_check_and_discard(info, mnew);
                mdt_object_put(info->mti_env, mnew);
+       }
 out_put_old:
        mdt_object_put(info->mti_env, mold);
 out_unlock_parents: