+ rc = mdo_migrate(info->mti_env, mdt_object_child(msrcdir),
+ mdt_object_child(mold), &rr->rr_name,
+ mdt_object_child(mnew), ma);
+ if (rc != 0)
+ GOTO(out_unlock_new, rc);
+
+out_unlock_new:
+ if (lh_tgtp != NULL)
+ mdt_object_unlock(info, mnew, lh_tgtp, rc);
+out_put_new:
+ if (mnew)
+ mdt_object_put(info->mti_env, mnew);
+out_unlock_child:
+ mdt_object_unlock(info, mold, lh_childp, rc);
+out_unlock_list:
+ /* we don't really modify linkea objects, so we can safely decref these
+ * locks, and this can avoid saving them as COS locks, which may prevent
+ * subsequent migrate. */
+ mdt_unlock_list(info, &lock_list, 1);
+ if (lease != NULL) {
+ ldlm_reprocess_all(lease->l_resource);
+ LDLM_LOCK_PUT(lease);
+ }
+
+ if (lock_open_sem)
+ up_write(&mold->mot_open_sem);
+out_put_child:
+ mdt_object_put(info->mti_env, mold);
+out_unlock_parent:
+ mdt_object_unlock(info, msrcdir, lh_dirp, rc);
+out_put_parent:
+ mdt_object_put(info->mti_env, msrcdir);
+
+ RETURN(rc);
+}
+
+static struct mdt_object *mdt_object_find_check(struct mdt_thread_info *info,
+ const struct lu_fid *fid,
+ int idx)
+{
+ struct mdt_object *dir;
+ int rc;
+ ENTRY;
+
+ dir = mdt_object_find(info->mti_env, info->mti_mdt, fid);
+ if (IS_ERR(dir))
+ RETURN(dir);
+
+ /* check early, the real version will be saved after locking */
+ rc = mdt_version_get_check(info, dir, idx);
+ if (rc)
+ GOTO(out_put, rc);
+
+ RETURN(dir);
+out_put:
+ mdt_object_put(info->mti_env, dir);
+ return ERR_PTR(rc);
+}
+
+static int mdt_object_lock_save(struct mdt_thread_info *info,
+ struct mdt_object *dir,
+ struct mdt_lock_handle *lh,
+ int idx, bool cos_incompat)
+{
+ int rc;
+
+ /* we lock the target dir if it is local */
+ rc = mdt_reint_object_lock(info, dir, lh, MDS_INODELOCK_UPDATE,
+ cos_incompat);
+ if (rc != 0)
+ return rc;
+
+ /* get and save correct version after locking */
+ mdt_version_get_save(info, dir, idx);
+ return 0;
+}
+
+/*
+ * VBR: rename versions in reply: 0 - srcdir parent; 1 - tgtdir parent;
+ * 2 - srcdir child; 3 - tgtdir child.
+ * Update on disk version of srcdir child.
+ */
+/**
+ * For DNE phase I, only these renames are allowed
+ * mv src_p/src_c tgt_p/tgt_c
+ * 1. src_p/src_c/tgt_p/tgt_c are in the same MDT.
+ * 2. src_p and tgt_p are same directory, and tgt_c does not
+ * exists. In this case, all of modification will happen
+ * in the MDT where ithesource parent is, only one remote
+ * update is needed, i.e. set c_time/m_time on the child.
+ * And tgt_c will be still in the same MDT as the original
+ * src_c.
+ */
+static int mdt_reint_rename_internal(struct mdt_thread_info *info,
+ struct mdt_lock_handle *lhc)
+{
+ struct mdt_reint_record *rr = &info->mti_rr;
+ struct md_attr *ma = &info->mti_attr;
+ struct ptlrpc_request *req = mdt_info_req(info);
+ struct mdt_object *msrcdir = NULL;
+ struct mdt_object *mtgtdir = NULL;
+ struct mdt_object *mold;
+ struct mdt_object *mnew = NULL;
+ struct mdt_lock_handle *lh_srcdirp;
+ struct mdt_lock_handle *lh_tgtdirp;
+ struct mdt_lock_handle *lh_oldp = NULL;
+ struct mdt_lock_handle *lh_newp = NULL;
+ struct lu_fid *old_fid = &info->mti_tmp_fid1;
+ struct lu_fid *new_fid = &info->mti_tmp_fid2;
+ __u64 lock_ibits;
+ bool reverse = false;
+ bool cos_incompat;
+ int rc;
+ ENTRY;
+
+ DEBUG_REQ(D_INODE, req, "rename "DFID"/"DNAME" to "DFID"/"DNAME,
+ PFID(rr->rr_fid1), PNAME(&rr->rr_name),
+ PFID(rr->rr_fid2), PNAME(&rr->rr_tgt_name));
+
+ /* find both parents. */
+ msrcdir = mdt_object_find_check(info, rr->rr_fid1, 0);
+ if (IS_ERR(msrcdir))
+ RETURN(PTR_ERR(msrcdir));
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME3, 5);
+
+ if (lu_fid_eq(rr->rr_fid1, rr->rr_fid2)) {
+ 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));
+ }
+
+ /* 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
+ * remote, relock parents. */
+ cos_incompat = (mdt_object_remote(msrcdir) ||
+ mdt_object_remote(mtgtdir));
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME4, 5);
+
+ /* lock parents in the proper order. */
+ lh_srcdirp = &info->mti_lh[MDT_LH_PARENT];
+ lh_tgtdirp = &info->mti_lh[MDT_LH_CHILD];
+
+relock:
+ mdt_lock_pdo_init(lh_srcdirp, LCK_PW, &rr->rr_name);
+ mdt_lock_pdo_init(lh_tgtdirp, LCK_PW, &rr->rr_tgt_name);
+
+ if (reverse) {
+ rc = mdt_object_lock_save(info, mtgtdir, lh_tgtdirp, 1,
+ cos_incompat);
+ if (rc)
+ GOTO(out_put_tgtdir, rc);
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME, 5);
+
+ rc = mdt_object_lock_save(info, msrcdir, lh_srcdirp, 0,
+ cos_incompat);
+ if (rc != 0) {
+ mdt_object_unlock(info, mtgtdir, lh_tgtdirp, rc);
+ GOTO(out_put_tgtdir, rc);
+ }
+ } else {
+ rc = mdt_object_lock_save(info, msrcdir, lh_srcdirp, 0,
+ cos_incompat);
+ if (rc)
+ GOTO(out_put_tgtdir, rc);
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME, 5);
+
+ if (mtgtdir != msrcdir) {
+ rc = mdt_object_lock_save(info, mtgtdir, lh_tgtdirp, 1,
+ cos_incompat);
+ } else if (lh_srcdirp->mlh_pdo_hash !=
+ lh_tgtdirp->mlh_pdo_hash) {
+ rc = mdt_pdir_hash_lock(info, lh_tgtdirp, mtgtdir,
+ MDS_INODELOCK_UPDATE,
+ cos_incompat);
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_PDO_LOCK2, 10);
+ }
+ if (rc != 0) {
+ mdt_object_unlock(info, msrcdir, lh_srcdirp, rc);
+ GOTO(out_put_tgtdir, rc);
+ }
+ }
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME4, 5);
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME2, 5);
+
+ /* find mold object. */
+ fid_zero(old_fid);
+ rc = mdt_lookup_version_check(info, msrcdir, &rr->rr_name, old_fid, 2);
+ if (rc != 0)
+ GOTO(out_unlock_parents, rc);
+
+ if (lu_fid_eq(old_fid, rr->rr_fid1) || lu_fid_eq(old_fid, rr->rr_fid2))
+ GOTO(out_unlock_parents, rc = -EINVAL);
+
+ if (!fid_is_md_operative(old_fid))
+ GOTO(out_unlock_parents, rc = -EPERM);
+
+ mold = mdt_object_find(info->mti_env, info->mti_mdt, old_fid);
+ if (IS_ERR(mold))
+ GOTO(out_unlock_parents, rc = PTR_ERR(mold));
+
+ /* 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)
+ GOTO(out_put_old, rc);
+ }
+
+ tgt_vbr_obj_set(info->mti_env, mdt_obj2dt(mold));
+ /* save version after locking */
+ mdt_version_get_save(info, mold, 2);
+
+ if (!cos_incompat && mdt_object_remote(mold)) {
+ cos_incompat = true;
+ mdt_object_put(info->mti_env, mold);
+ mdt_object_unlock(info, mtgtdir, lh_tgtdirp, -EAGAIN);
+ mdt_object_unlock(info, msrcdir, lh_srcdirp, -EAGAIN);
+ goto relock;
+ }
+
+ /* find mnew object:
+ * mnew target object may not exist now
+ * lookup with version checking */
+ fid_zero(new_fid);
+ rc = mdt_lookup_version_check(info, mtgtdir, &rr->rr_tgt_name, new_fid,
+ 3);
+ if (rc == 0) {
+ /* the new_fid should have been filled at this moment */
+ if (lu_fid_eq(old_fid, new_fid))
+ GOTO(out_put_old, rc);
+
+ if (lu_fid_eq(new_fid, rr->rr_fid1) ||
+ lu_fid_eq(new_fid, rr->rr_fid2))
+ GOTO(out_put_old, rc = -EINVAL);
+
+ if (!fid_is_md_operative(new_fid))
+ GOTO(out_put_old, rc = -EPERM);
+
+ mnew = mdt_object_find(info->mti_env, info->mti_mdt, new_fid);
+ if (IS_ERR(mnew))
+ GOTO(out_put_old, rc = PTR_ERR(mnew));