+ if (op_data->op_code != LUSTRE_OPC_MKDIR)
+ return false;
+
+ if (lmv_dir_striped(op_data->op_mea1))
+ return false;
+
+ 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;
+}
+
+/* mkdir by QoS if either ROOT or parent default LMV is space balanced. */
+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;
+
+ if (op_data->op_code != LUSTRE_OPC_MKDIR)
+ return false;
+
+ if (lmv_dir_striped(op_data->op_mea1))
+ return false;
+
+ return (op_data->op_flags & MF_QOS_MKDIR) ||
+ (lsm && lsm->lsm_md_master_mdt_index == LMV_OFFSET_DEFAULT);
+}
+
+/* if parent default LMV is space balanced, and
+ * 1. max_inherit_rr is set
+ * 2. or parent is ROOT
+ * mkdir roundrobin. Or if parent doesn't have default LMV, while ROOT default
+ * LMV requests roundrobin mkdir, do the same.
+ * NB, this needs to check server is balanced, which is done 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 (op_data->op_flags & MF_RR_MKDIR) ||
+ (lsm && 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;
+}
+
+/* locate MDT by space usage */
+static struct lu_tgt_desc *lmv_locate_tgt_by_space(struct lmv_obd *lmv,
+ struct md_op_data *op_data,
+ struct lmv_tgt_desc *tgt)
+{
+ struct lmv_tgt_desc *tmp = tgt;
+
+ tgt = lmv_locate_tgt_qos(lmv, op_data->op_mds, op_data->op_dir_depth);
+ if (tgt == ERR_PTR(-EAGAIN)) {
+ if (ltd_qos_is_balanced(&lmv->lmv_mdt_descs) &&
+ !lmv_op_default_rr_mkdir(op_data) &&
+ !lmv_op_user_qos_mkdir(op_data))
+ /* if not necessary, don't create remote directory. */
+ tgt = tmp;
+ else
+ tgt = lmv_locate_tgt_rr(lmv);
+ }
+
+ /*
+ * only update statfs after QoS mkdir, this means the cached statfs may
+ * be stale, and current mkdir may not follow QoS accurately, but it's
+ * not serious, and avoids periodic statfs when client doesn't mkdir by
+ * QoS.
+ */
+ if (!IS_ERR(tgt)) {
+ op_data->op_mds = tgt->ltd_index;
+ lmv_statfs_check_update(lmv2obd_dev(lmv), tgt);
+ }
+
+ return tgt;
+}
+
+int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
+ const void *data, size_t datalen, umode_t mode, uid_t uid,
+ gid_t gid, kernel_cap_t cap_effective, __u64 rdev,
+ struct ptlrpc_request **request)
+{
+ struct obd_device *obd = exp->exp_obd;
+ struct lmv_obd *lmv = &obd->u.lmv;
+ struct lmv_tgt_desc *tgt;
+ struct mdt_body *repbody;
+ int rc;
+
+ ENTRY;
+
+ if (!lmv->lmv_mdt_descs.ltd_lmv_desc.ld_active_tgt_count)
+ RETURN(-EIO);
+
+ if (lmv_dir_bad_hash(op_data->op_mea1))
+ RETURN(-EBADF);
+
+ if (lmv_dir_layout_changing(op_data->op_mea1)) {
+ /*
+ * if parent is migrating, create() needs to lookup existing
+ * name in both old and new layout, check old layout on client.
+ */
+ rc = lmv_old_layout_lookup(lmv, op_data);
+ if (rc != -ENOENT)
+ RETURN(rc);
+
+ op_data->op_new_layout = true;
+ }
+
+ tgt = lmv_locate_tgt(lmv, op_data);
+ if (IS_ERR(tgt))
+ RETURN(PTR_ERR(tgt));
+
+ /* the order to apply policy in mkdir:
+ * 1. is "lfs mkdir -i N"? mkdir on MDT N.
+ * 2. is "lfs mkdir -i -1"? mkdir by space usage.
+ * 3. is starting MDT specified in default LMV? mkdir on MDT N.
+ * 4. is default LMV space balanced? mkdir by space usage.
+ */
+ if (lmv_op_user_specific_mkdir(op_data)) {
+ struct lmv_user_md *lum = op_data->op_data;
+
+ op_data->op_mds = le32_to_cpu(lum->lum_stripe_offset);
+ tgt = lmv_tgt(lmv, op_data->op_mds);
+ if (!tgt)
+ RETURN(-ENODEV);
+ } else if (lmv_op_user_qos_mkdir(op_data)) {
+ tgt = lmv_locate_tgt_by_space(lmv, op_data, tgt);
+ if (IS_ERR(tgt))
+ RETURN(PTR_ERR(tgt));
+ } else if (lmv_op_default_specific_mkdir(op_data)) {
+ op_data->op_mds =
+ op_data->op_default_mea1->lsm_md_master_mdt_index;
+ tgt = lmv_tgt(lmv, op_data->op_mds);
+ if (!tgt)
+ RETURN(-ENODEV);
+ } else if (lmv_op_default_qos_mkdir(op_data)) {
+ tgt = lmv_locate_tgt_by_space(lmv, op_data, tgt);
+ if (IS_ERR(tgt))
+ RETURN(PTR_ERR(tgt));
+ }
+
+retry:
+ rc = lmv_fid_alloc(NULL, exp, &op_data->op_fid2, op_data);
+ if (rc)
+ RETURN(rc);
+
+ CDEBUG(D_INODE, "CREATE name '%.*s' "DFID" on "DFID" -> mds #%x\n",
+ (int)op_data->op_namelen, op_data->op_name,
+ PFID(&op_data->op_fid2), PFID(&op_data->op_fid1),
+ op_data->op_mds);