+ /* pobj is master object of parent */
+ pobj = mdt_object_find_check(info, rr->rr_fid1, 0);
+ if (IS_ERR(pobj))
+ RETURN(PTR_ERR(pobj));
+
+ if (unlikely(!info->mti_big_lmm)) {
+ info->mti_big_lmmsize = lmv_mds_md_size(64, LMV_MAGIC);
+ OBD_ALLOC(info->mti_big_lmm, info->mti_big_lmmsize);
+ if (!info->mti_big_lmm)
+ GOTO(put_parent, rc = -ENOMEM);
+ }
+
+ ma->ma_lmv = info->mti_big_lmm;
+ ma->ma_lmv_size = info->mti_big_lmmsize;
+ ma->ma_valid = 0;
+ rc = mdt_stripe_get(info, pobj, ma, XATTR_NAME_LMV);
+ if (rc)
+ GOTO(put_parent, rc);
+
+ /* lock parent object */
+ lhp = &info->mti_lh[MDT_LH_PARENT];
+ mdt_lock_reg_init(lhp, LCK_PW);
+ rc = mdt_migrate_parent_lock(info, pobj, ma, lhp, peinfo,
+ &parent_slave_locks);
+ if (rc)
+ GOTO(put_parent, rc);
+
+ /*
+ * spobj is the corresponding stripe against name if pobj is striped
+ * directory, which is the real parent, and no need to lock, because
+ * we've taken full lock of pobj.
+ */
+ rc = mdt_migrate_lookup(info, pobj, ma, &rr->rr_name, &spobj, &sobj);
+ if (rc)
+ GOTO(unlock_parent, rc);
+
+ /* lock parents of source links, and revoke LOOKUP lock of links */
+ rc = mdt_lock_links(info, pobj, ma, sobj, &link_locks);
+ if (rc < 0)
+ GOTO(put_source, rc);
+
+ /*
+ * RS_MAX_LOCKS is the limit of number of locks that can be saved along
+ * with one request, if total lock count exceeds this limit, we will
+ * drop all locks after migration, and synchronous device in the end.
+ */
+ do_sync = rc;
+
+ /* TODO: DoM migration is not supported yet */
+ if (S_ISREG(lu_object_attr(&sobj->mot_obj))) {
+ ma->ma_lmm = info->mti_big_lmm;
+ ma->ma_lmm_size = info->mti_big_lmmsize;
+ ma->ma_valid = 0;
+ rc = mdt_stripe_get(info, sobj, ma, XATTR_NAME_LOV);
+ if (rc)
+ GOTO(put_source, rc);
+
+ if (ma->ma_valid & MA_LOV &&
+ mdt_lmm_dom_entry(ma->ma_lmm) != LMM_NO_DOM)
+ GOTO(put_source, rc = -EOPNOTSUPP);
+ }
+
+ /* if migration HSM is allowed */
+ if (!mdt->mdt_opts.mo_migrate_hsm_allowed) {
+ ma->ma_need = MA_HSM;
+ ma->ma_valid = 0;
+ rc = mdt_attr_get_complex(info, sobj, ma);
+ if (rc)
+ GOTO(unlock_links, rc);
+
+ if ((ma->ma_valid & MA_HSM) && ma->ma_hsm.mh_flags != 0)
+ GOTO(unlock_links, rc = -EOPNOTSUPP);
+ }
+
+ /* end lease and close file for regular file */
+ if (info->mti_spec.sp_migrate_close) {
+ /* try to hold open_sem so that nobody else can open the file */
+ if (!down_write_trylock(&sobj->mot_open_sem)) {
+ /* close anyway */
+ mdd_migrate_close(info, sobj);
+ GOTO(unlock_links, rc = -EBUSY);
+ } else {
+ open_sem_locked = true;
+ rc = mdd_migrate_close(info, sobj);
+ if (rc)
+ GOTO(unlock_open_sem, rc);
+ }
+ }
+
+ /* lock source */
+ lhs = &info->mti_lh[MDT_LH_OLD];
+ mdt_lock_reg_init(lhs, LCK_EX);
+ rc = mdt_migrate_object_lock(info, spobj, sobj, lhs, seinfo,
+ &child_slave_locks);
+ if (rc)
+ GOTO(unlock_open_sem, rc);
+
+ /* lock target */
+ tobj = mdt_object_find(env, mdt, rr->rr_fid2);
+ if (IS_ERR(tobj))
+ GOTO(unlock_source, rc = PTR_ERR(tobj));
+
+ lht = &info->mti_lh[MDT_LH_NEW];
+ mdt_lock_reg_init(lht, LCK_EX);
+ rc = mdt_reint_object_lock(info, tobj, lht, MDS_INODELOCK_FULL, true);
+ if (rc)
+ GOTO(put_target, rc);
+
+ /* Don't do lookup sanity check. We know name doesn't exist. */
+ info->mti_spec.sp_cr_lookup = 0;
+ info->mti_spec.sp_feat = &dt_directory_features;
+
+ rc = mdo_migrate(env, mdt_object_child(pobj),
+ mdt_object_child(sobj), &rr->rr_name,
+ mdt_object_child(tobj), &info->mti_spec, ma);
+ EXIT;
+
+ mdt_object_unlock(info, tobj, lht, rc);
+put_target:
+ mdt_object_put(env, tobj);
+unlock_source:
+ mdt_migrate_object_unlock(info, sobj, lhs, seinfo,
+ &child_slave_locks, rc);
+unlock_open_sem:
+ if (open_sem_locked)
+ up_write(&sobj->mot_open_sem);
+unlock_links:
+ mdt_unlock_list(info, &link_locks, rc);
+put_source:
+ mdt_object_put(env, sobj);
+ mdt_object_put(env, spobj);
+unlock_parent:
+ mdt_migrate_object_unlock(info, pobj, lhp, peinfo,
+ &parent_slave_locks, rc);
+put_parent:
+ mdt_object_put(env, pobj);
+
+ if (!rc && do_sync)
+ mdt_device_sync(env, mdt);
+
+ return rc;