+/* Locate MDT of op_data->op_fid2 for link/rename */
+static struct lmv_tgt_desc *
+lmv_locate_tgt2(struct lmv_obd *lmv, struct md_op_data *op_data)
+{
+ struct lmv_tgt_desc *tgt;
+ int rc;
+
+ LASSERT(op_data->op_name);
+ if (lmv_dir_layout_changing(op_data->op_mea2)) {
+ struct lu_fid fid1 = op_data->op_fid1;
+ struct lmv_stripe_md *lsm1 = op_data->op_mea1;
+ struct ptlrpc_request *request = NULL;
+
+ /*
+ * avoid creating new file under old layout of migrating
+ * directory, check it here.
+ */
+ tgt = lmv_locate_tgt_by_name(lmv, op_data->op_mea2,
+ op_data->op_name, op_data->op_namelen,
+ &op_data->op_fid2, &op_data->op_mds, false);
+ if (IS_ERR(tgt))
+ RETURN(tgt);
+
+ op_data->op_fid1 = op_data->op_fid2;
+ op_data->op_mea1 = op_data->op_mea2;
+ rc = md_getattr_name(tgt->ltd_exp, op_data, &request);
+ op_data->op_fid1 = fid1;
+ op_data->op_mea1 = lsm1;
+ if (!rc) {
+ ptlrpc_req_finished(request);
+ RETURN(ERR_PTR(-EEXIST));
+ }
+
+ if (rc != -ENOENT)
+ RETURN(ERR_PTR(rc));
+ }
+
+ return lmv_locate_tgt_by_name(lmv, op_data->op_mea2, op_data->op_name,
+ op_data->op_namelen, &op_data->op_fid2,
+ &op_data->op_mds, true);
+}
+
+int lmv_old_layout_lookup(struct lmv_obd *lmv, struct md_op_data *op_data)
+{
+ struct lu_tgt_desc *tgt;
+ struct ptlrpc_request *request;
+ int rc;
+
+ LASSERT(lmv_dir_layout_changing(op_data->op_mea1));
+ LASSERT(!op_data->op_new_layout);
+
+ tgt = lmv_locate_tgt(lmv, op_data);
+ if (IS_ERR(tgt))
+ return PTR_ERR(tgt);
+
+ rc = md_getattr_name(tgt->ltd_exp, op_data, &request);
+ if (!rc) {
+ ptlrpc_req_finished(request);
+ return -EEXIST;
+ }
+
+ return rc;
+}
+
+static inline bool lmv_op_user_qos_mkdir(const struct md_op_data *op_data)
+{
+ const struct lmv_user_md *lum = op_data->op_data;
+
+ return (op_data->op_cli_flags & CLI_SET_MEA) && lum &&
+ le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC &&
+ le32_to_cpu(lum->lum_stripe_offset) == LMV_OFFSET_DEFAULT;
+}
+
+static inline bool lmv_op_default_qos_mkdir(const struct md_op_data *op_data)
+{
+ const struct lmv_stripe_md *lsm = op_data->op_default_mea1;
+
+ return lsm && lsm->lsm_md_master_mdt_index == LMV_OFFSET_DEFAULT;
+}
+
+/* mkdir by QoS in two cases:
+ * 1. 'lfs mkdir -i -1'
+ * 2. parent default LMV master_mdt_index is -1
+ *
+ * NB, mkdir by QoS only if parent is not striped, this is to avoid remote
+ * directories under striped directory.
+ */
+static inline bool lmv_op_qos_mkdir(const struct md_op_data *op_data)
+{
+ if (op_data->op_code != LUSTRE_OPC_MKDIR)
+ return false;
+
+ if (lmv_dir_striped(op_data->op_mea1))
+ return false;
+
+ if (lmv_op_user_qos_mkdir(op_data))
+ return true;
+
+ if (lmv_op_default_qos_mkdir(op_data))
+ return true;
+
+ return false;
+}
+
+/* if default LMV is set, and its index is LMV_OFFSET_DEFAULT, and
+ * 1. max_inherit_rr is set and is not LMV_INHERIT_RR_NONE
+ * 2. or parent is ROOT
+ * mkdir roundrobin.
+ * NB, this also needs to check server is balanced, which is checked by caller.
+ */
+static inline bool lmv_op_default_rr_mkdir(const struct md_op_data *op_data)
+{
+ const struct lmv_stripe_md *lsm = op_data->op_default_mea1;
+
+ if (!lmv_op_default_qos_mkdir(op_data))
+ return false;
+
+ return lsm->lsm_md_max_inherit_rr != LMV_INHERIT_RR_NONE ||
+ fid_is_root(&op_data->op_fid1);
+}
+
+/* 'lfs mkdir -i <specific_MDT>' */
+static inline bool lmv_op_user_specific_mkdir(const struct md_op_data *op_data)
+{
+ const struct lmv_user_md *lum = op_data->op_data;
+
+ return op_data->op_code == LUSTRE_OPC_MKDIR &&
+ op_data->op_cli_flags & CLI_SET_MEA && lum &&
+ (le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC ||
+ le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC_SPECIFIC) &&
+ le32_to_cpu(lum->lum_stripe_offset) != LMV_OFFSET_DEFAULT;
+}
+
+/* parent default LMV master_mdt_index is not -1. */
+static inline bool
+lmv_op_default_specific_mkdir(const struct md_op_data *op_data)
+{
+ return op_data->op_code == LUSTRE_OPC_MKDIR &&
+ op_data->op_default_mea1 &&
+ op_data->op_default_mea1->lsm_md_master_mdt_index !=
+ LMV_OFFSET_DEFAULT;
+}
+