+ return rc;
+}
+
+/*
+ * lookup source by name, if parent is striped directory, we need to find the
+ * corresponding stripe where source is located, and then lookup there.
+ *
+ * besides, if parent is migrating too, and file is already in target stripe,
+ * this should be a redo of 'lfs migrate' on client side.
+ */
+static int mdt_migrate_lookup(struct mdt_thread_info *info,
+ struct mdt_object *pobj,
+ const struct md_attr *ma,
+ const struct lu_name *lname,
+ struct mdt_object **spobj,
+ struct mdt_object **sobj)
+{
+ const struct lu_env *env = info->mti_env;
+ struct lu_fid *fid = &info->mti_tmp_fid1;
+ struct mdt_object *stripe;
+ int rc;
+
+ if (ma->ma_valid & MA_LMV) {
+ /* if parent is striped, lookup on corresponding stripe */
+ struct lmv_mds_md_v1 *lmv = &ma->ma_lmv->lmv_md_v1;
+ __u32 hash_type = le32_to_cpu(lmv->lmv_hash_type);
+ __u32 stripe_count = le32_to_cpu(lmv->lmv_stripe_count);
+ bool is_migrating = le32_to_cpu(lmv->lmv_hash_type) &
+ LMV_HASH_FLAG_MIGRATION;
+
+ if (is_migrating) {
+ hash_type = le32_to_cpu(lmv->lmv_migrate_hash);
+ stripe_count -= le32_to_cpu(lmv->lmv_migrate_offset);
+ }
+
+ rc = lmv_name_to_stripe_index(hash_type, stripe_count,
+ lname->ln_name,
+ lname->ln_namelen);
+ if (rc < 0)
+ return rc;
+
+ if (le32_to_cpu(lmv->lmv_hash_type) & LMV_HASH_FLAG_MIGRATION)
+ rc += le32_to_cpu(lmv->lmv_migrate_offset);
+
+ fid_le_to_cpu(fid, &lmv->lmv_stripe_fids[rc]);
+
+ stripe = mdt_object_find(env, info->mti_mdt, fid);
+ if (IS_ERR(stripe))
+ return PTR_ERR(stripe);
+
+ fid_zero(fid);
+ rc = mdo_lookup(env, mdt_object_child(stripe), lname, fid,
+ &info->mti_spec);
+ if (rc == -ENOENT && is_migrating) {
+ /*
+ * if parent is migrating, and lookup child failed on
+ * source stripe, lookup again on target stripe, if it
+ * exists, it means previous migration was interrupted,
+ * and current file was migrated already.
+ */
+ mdt_object_put(env, stripe);
+
+ hash_type = le32_to_cpu(lmv->lmv_hash_type);
+ stripe_count = le32_to_cpu(lmv->lmv_migrate_offset);
+
+ rc = lmv_name_to_stripe_index(hash_type, stripe_count,
+ lname->ln_name,
+ lname->ln_namelen);
+ if (rc < 0)
+ return rc;
+
+ fid_le_to_cpu(fid, &lmv->lmv_stripe_fids[rc]);
+
+ stripe = mdt_object_find(env, info->mti_mdt, fid);
+ if (IS_ERR(stripe))
+ return PTR_ERR(stripe);
+
+ fid_zero(fid);
+ rc = mdo_lookup(env, mdt_object_child(stripe), lname,
+ fid, &info->mti_spec);
+ mdt_object_put(env, stripe);
+ return rc ?: -EALREADY;
+ } else if (rc) {
+ mdt_object_put(env, stripe);
+ return rc;
+ }
+ } else {
+ fid_zero(fid);
+ rc = mdo_lookup(env, mdt_object_child(pobj), lname, fid,
+ &info->mti_spec);
+ if (rc)
+ return rc;
+
+ stripe = pobj;
+ mdt_object_get(env, stripe);