+ 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)
+{
+ int rc;
+
+ /* we lock the target dir if it is local */
+ rc = mdt_object_lock(info, dir, lh, MDS_INODELOCK_UPDATE,
+ MDT_LOCAL_LOCK);
+ if (rc != 0)
+ return rc;
+
+ /* get and save correct version after locking */
+ mdt_version_get_save(info, dir, idx);
+ return 0;
+}
+
+
+static int mdt_rename_parents_lock(struct mdt_thread_info *info,
+ struct mdt_object **srcp,
+ struct mdt_object **tgtp)
+{
+ struct mdt_reint_record *rr = &info->mti_rr;
+ const struct lu_fid *fid_src = rr->rr_fid1;
+ const struct lu_fid *fid_tgt = rr->rr_fid2;
+ struct mdt_lock_handle *lh_src = &info->mti_lh[MDT_LH_PARENT];
+ struct mdt_lock_handle *lh_tgt = &info->mti_lh[MDT_LH_CHILD];
+ struct mdt_object *src;
+ struct mdt_object *tgt;
+ int reverse = 0;
+ int rc;
+ ENTRY;
+
+ /* find both parents. */
+ src = mdt_object_find_check(info, fid_src, 0);
+ if (IS_ERR(src))
+ RETURN(PTR_ERR(src));
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME3, 5);
+
+ if (lu_fid_eq(fid_src, fid_tgt)) {
+ tgt = src;
+ mdt_object_get(info->mti_env, tgt);
+ } else {
+ /* Check if the @src is not a child of the @tgt, otherwise a
+ * reverse locking must take place. */
+ rc = mdt_is_subdir(info, src, fid_tgt);
+ if (rc == -EINVAL)
+ reverse = 1;
+ else if (rc)
+ GOTO(err_src_put, rc);
+
+ tgt = mdt_object_find_check(info, fid_tgt, 1);
+ if (IS_ERR(tgt))
+ GOTO(err_src_put, rc = PTR_ERR(tgt));
+
+ if (unlikely(mdt_object_remote(tgt))) {
+ CDEBUG(D_INFO, "Source dir "DFID" target dir "DFID
+ "on different MDTs\n", PFID(fid_src),
+ PFID(fid_tgt));
+ GOTO(err_tgt_put, rc = -EXDEV);
+ }
+ }
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME4, 5);
+
+ /* lock parents in the proper order. */
+ if (reverse) {
+ rc = mdt_object_lock_save(info, tgt, lh_tgt, 1);
+ if (rc)
+ GOTO(err_tgt_put, rc);
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME, 5);
+
+ rc = mdt_object_lock_save(info, src, lh_src, 0);
+ } else {
+ rc = mdt_object_lock_save(info, src, lh_src, 0);
+ if (rc)
+ GOTO(err_tgt_put, rc);
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME, 5);
+
+ if (tgt != src)
+ rc = mdt_object_lock_save(info, tgt, lh_tgt, 1);
+ else if (lh_src->mlh_pdo_hash != lh_tgt->mlh_pdo_hash) {
+ rc = mdt_pdir_hash_lock(info, lh_tgt, tgt,
+ MDS_INODELOCK_UPDATE);
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_PDO_LOCK2, 10);
+ }
+ }
+ if (rc)
+ GOTO(err_unlock, rc);
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME4, 5);
+
+ *srcp = src;
+ *tgtp = tgt;
+ RETURN(0);
+
+err_unlock:
+ /* The order does not matter as the handle is checked inside,
+ * as well as not used handle. */
+ mdt_object_unlock(info, src, lh_src, rc);
+ mdt_object_unlock(info, tgt, lh_tgt, rc);
+err_tgt_put:
+ mdt_object_put(info->mti_env, tgt);
+err_src_put:
+ mdt_object_put(info->mti_env, src);
+ RETURN(rc);
+}
+
+/*
+ * VBR: rename versions in reply: 0 - src parent; 1 - tgt parent;
+ * 2 - src child; 3 - tgt child.
+ * Update on disk version of src 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;
+ 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));
+
+ lh_srcdirp = &info->mti_lh[MDT_LH_PARENT];
+ mdt_lock_pdo_init(lh_srcdirp, LCK_PW, &rr->rr_name);
+ lh_tgtdirp = &info->mti_lh[MDT_LH_CHILD];
+ mdt_lock_pdo_init(lh_tgtdirp, LCK_PW, &rr->rr_tgt_name);
+
+ /* step 1&2: lock the source and target dirs. */
+ rc = mdt_rename_parents_lock(info, &msrcdir, &mtgtdir);
+ if (rc)
+ RETURN(rc);
+
+ OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_RENAME2, 5);
+
+ /* step 3: find & lock the old 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. */
+ 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);
+ mdt_set_capainfo(info, 2, old_fid, BYPASS_CAPA);
+
+ /* step 4: find & lock the new object. */
+ /* new 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);
+
+ if (mdt_object_remote(mold)) {
+ CDEBUG(D_INFO, "Src child "DFID" is on another MDT\n",
+ PFID(old_fid));
+ GOTO(out_put_old, rc = -EXDEV);
+ }
+
+ mnew = mdt_object_find(info->mti_env, info->mti_mdt, new_fid);
+ if (IS_ERR(mnew))
+ GOTO(out_put_old, rc = PTR_ERR(mnew));
+
+ if (mdt_object_remote(mnew)) {
+ CDEBUG(D_INFO, "src child "DFID" is on another MDT\n",
+ PFID(new_fid));
+ GOTO(out_put_new, rc = -EXDEV);
+ }
+
+ /* Before locking the target dir, check we do not replace
+ * a dir with a non-dir, otherwise it may deadlock with
+ * link op which tries to create a link in this dir
+ * back to this non-dir. */
+ if (S_ISDIR(lu_object_attr(&mnew->mot_obj)) &&
+ !S_ISDIR(lu_object_attr(&mold->mot_obj)))
+ GOTO(out_put_new, rc = -EISDIR);
+
+ lh_oldp = &info->mti_lh[MDT_LH_OLD];
+ mdt_lock_reg_init(lh_oldp, LCK_EX);
+ rc = mdt_object_lock(info, mold, lh_oldp, MDS_INODELOCK_LOOKUP |
+ MDS_INODELOCK_XATTR, MDT_CROSS_LOCK);
+ if (rc != 0)
+ GOTO(out_put_new, rc);
+
+ /* Check if @msrcdir is subdir of @mnew, before locking child
+ * to avoid reverse locking. */
+ rc = mdt_is_subdir(info, msrcdir, new_fid);
+ if (rc)
+ GOTO(out_unlock_old, rc);
+
+ /* We used to acquire MDS_INODELOCK_FULL here but we
+ * can't do this now because a running HSM restore on
+ * the rename onto victim will hold the layout
+ * lock. See LU-4002. */
+
+ lh_newp = &info->mti_lh[MDT_LH_NEW];
+ mdt_lock_reg_init(lh_newp, LCK_EX);
+ rc = mdt_object_lock(info, mnew, lh_newp,
+ MDS_INODELOCK_LOOKUP |
+ MDS_INODELOCK_UPDATE,
+ MDT_LOCAL_LOCK);
+ if (rc != 0)
+ GOTO(out_unlock_old, rc);
+
+ /* get and save version after locking */
+ mdt_version_get_save(info, mnew, 3);
+ mdt_set_capainfo(info, 3, new_fid, BYPASS_CAPA);
+ } else if (rc != -EREMOTE && rc != -ENOENT) {
+ GOTO(out_put_old, rc);
+ } else {
+ /* If mnew does not exist and mold are remote directory,
+ * it only allows rename if they are under same directory */
+ if (mtgtdir != msrcdir && mdt_object_remote(mold)) {
+ CDEBUG(D_INFO, "Src child "DFID" is on another MDT\n",
+ PFID(old_fid));
+ GOTO(out_put_old, rc = -EXDEV);
+ }
+
+ lh_oldp = &info->mti_lh[MDT_LH_OLD];
+ mdt_lock_reg_init(lh_oldp, LCK_EX);
+ rc = mdt_object_lock(info, mold, lh_oldp, MDS_INODELOCK_LOOKUP |
+ MDS_INODELOCK_XATTR, MDT_CROSS_LOCK);
+ if (rc != 0)
+ GOTO(out_put_old, rc);
+
+ mdt_enoent_version_save(info, 3);
+ }
+
+ /* step 5: rename it */
+ mdt_reint_init_ma(info, ma);
+
+ mdt_fail_write(info->mti_env, info->mti_mdt->mdt_bottom,
+ OBD_FAIL_MDS_REINT_RENAME_WRITE);
+
+ if (mnew != NULL)
+ mutex_lock(&mnew->mot_lov_mutex);
+
+ rc = mdo_rename(info->mti_env, mdt_object_child(msrcdir),
+ mdt_object_child(mtgtdir), old_fid, &rr->rr_name,
+ mnew != NULL ? mdt_object_child(mnew) : NULL,
+ &rr->rr_tgt_name, ma);
+
+ if (mnew != NULL)
+ mutex_unlock(&mnew->mot_lov_mutex);
+
+ /* handle last link of tgt object */
+ if (rc == 0) {