+static int lod_verify_md_striping(struct lod_device *lod,
+ const struct lmv_user_md_v1 *lum)
+{
+ int rc = 0;
+ ENTRY;
+
+ if (unlikely(le32_to_cpu(lum->lum_magic) != LMV_USER_MAGIC))
+ GOTO(out, rc = -EINVAL);
+
+ if (unlikely(le32_to_cpu(lum->lum_stripe_count) == 0))
+ GOTO(out, rc = -EINVAL);
+out:
+ if (rc != 0)
+ CERROR("%s: invalid lmv_user_md: magic = %x, "
+ "stripe_offset = %d, stripe_count = %u: rc = %d\n",
+ lod2obd(lod)->obd_name, le32_to_cpu(lum->lum_magic),
+ (int)le32_to_cpu(lum->lum_stripe_offset),
+ le32_to_cpu(lum->lum_stripe_count), rc);
+ return rc;
+}
+
+/**
+ * Master LMVEA will be same as slave LMVEA, except
+ * 1. different magic
+ * 2. No lmv_stripe_fids on slave
+ * 3. lmv_master_mdt_index on slave LMV EA will be stripe_index.
+ */
+static void lod_prep_slave_lmv_md(struct lmv_mds_md_v1 *slave_lmv,
+ const struct lmv_mds_md_v1 *master_lmv)
+{
+ *slave_lmv = *master_lmv;
+ slave_lmv->lmv_magic = cpu_to_le32(LMV_MAGIC_STRIPE);
+}
+
+int lod_prep_lmv_md(const struct lu_env *env, struct dt_object *dt,
+ struct lu_buf *lmv_buf)
+{
+ struct lod_thread_info *info = lod_env_info(env);
+ struct lod_device *lod = lu2lod_dev(dt->do_lu.lo_dev);
+ struct lod_object *lo = lod_dt_obj(dt);
+ struct lmv_mds_md_v1 *lmm1;
+ int stripe_count;
+ int lmm_size;
+ int type = LU_SEQ_RANGE_ANY;
+ int i;
+ int rc;
+ __u32 mdtidx;
+ ENTRY;
+
+ LASSERT(lo->ldo_dir_striped != 0);
+ LASSERT(lo->ldo_stripenr > 0);
+ stripe_count = lo->ldo_stripenr;
+ lmm_size = lmv_mds_md_size(stripe_count, LMV_MAGIC);
+ if (info->lti_ea_store_size < lmm_size) {
+ rc = lod_ea_store_resize(info, lmm_size);
+ if (rc != 0)
+ RETURN(rc);
+ }
+
+ lmm1 = (struct lmv_mds_md_v1 *)info->lti_ea_store;
+ lmm1->lmv_magic = cpu_to_le32(LMV_MAGIC);
+ lmm1->lmv_stripe_count = cpu_to_le32(stripe_count);
+ lmm1->lmv_hash_type = cpu_to_le32(lo->ldo_dir_hash_type);
+ rc = lod_fld_lookup(env, lod, lu_object_fid(&dt->do_lu),
+ &mdtidx, &type);
+ if (rc != 0)
+ RETURN(rc);
+
+ lmm1->lmv_master_mdt_index = cpu_to_le32(mdtidx);
+ fid_cpu_to_le(&lmm1->lmv_master_fid, lu_object_fid(&dt->do_lu));
+ for (i = 0; i < lo->ldo_stripenr; i++) {
+ struct dt_object *dto;
+
+ dto = lo->ldo_stripe[i];
+ LASSERT(dto != NULL);
+ fid_cpu_to_le(&lmm1->lmv_stripe_fids[i],
+ lu_object_fid(&dto->do_lu));
+ }
+
+ lmv_buf->lb_buf = info->lti_ea_store;
+ lmv_buf->lb_len = lmm_size;
+ lo->ldo_dir_striping_cached = 1;
+
+ RETURN(rc);
+}
+
+int lod_parse_dir_striping(const struct lu_env *env, struct lod_object *lo,
+ const struct lu_buf *buf)
+{
+ struct lod_thread_info *info = lod_env_info(env);
+ struct lod_device *lod = lu2lod_dev(lo->ldo_obj.do_lu.lo_dev);
+ struct lod_tgt_descs *ltd = &lod->lod_mdt_descs;
+ struct dt_object **stripe;
+ union lmv_mds_md *lmm = buf->lb_buf;
+ struct lmv_mds_md_v1 *lmv1 = &lmm->lmv_md_v1;
+ struct lu_fid *fid = &info->lti_fid;
+ int i;
+ int rc = 0;
+ ENTRY;
+
+ if (le32_to_cpu(lmv1->lmv_hash_type) & LMV_HASH_FLAG_MIGRATION)
+ RETURN(0);
+
+ if (le32_to_cpu(lmv1->lmv_magic) == LMV_MAGIC_STRIPE) {
+ lo->ldo_dir_slave_stripe = 1;
+ RETURN(0);
+ }
+
+ if (le32_to_cpu(lmv1->lmv_magic) != LMV_MAGIC_V1)
+ RETURN(-EINVAL);
+
+ if (le32_to_cpu(lmv1->lmv_stripe_count) <= 1)
+ RETURN(0);
+
+ LASSERT(lo->ldo_stripe == NULL);
+ OBD_ALLOC(stripe, sizeof(stripe[0]) *
+ (le32_to_cpu(lmv1->lmv_stripe_count)));
+ if (stripe == NULL)
+ RETURN(-ENOMEM);
+
+ for (i = 0; i < le32_to_cpu(lmv1->lmv_stripe_count); i++) {
+ struct dt_device *tgt_dt;
+ struct dt_object *dto;
+ int type = LU_SEQ_RANGE_ANY;
+ __u32 idx;
+
+ fid_le_to_cpu(fid, &lmv1->lmv_stripe_fids[i]);
+ if (!fid_is_sane(fid))
+ GOTO(out, rc = -ESTALE);
+
+ rc = lod_fld_lookup(env, lod, fid, &idx, &type);
+ if (rc != 0)
+ GOTO(out, rc);
+
+ if (idx == lod2lu_dev(lod)->ld_site->ld_seq_site->ss_node_id) {
+ tgt_dt = lod->lod_child;
+ } else {
+ struct lod_tgt_desc *tgt;
+
+ tgt = LTD_TGT(ltd, idx);
+ if (tgt == NULL)
+ GOTO(out, rc = -ESTALE);
+ tgt_dt = tgt->ltd_tgt;
+ }
+
+ dto = dt_locate_at(env, tgt_dt, fid,
+ lo->ldo_obj.do_lu.lo_dev->ld_site->ls_top_dev,
+ NULL);
+ if (IS_ERR(dto))
+ GOTO(out, rc = PTR_ERR(dto));
+
+ stripe[i] = dto;
+ }
+out:
+ lo->ldo_stripe = stripe;
+ lo->ldo_stripenr = le32_to_cpu(lmv1->lmv_stripe_count);
+ lo->ldo_stripes_allocated = le32_to_cpu(lmv1->lmv_stripe_count);
+ if (rc != 0)
+ lod_object_free_striping(env, lo);
+
+ RETURN(rc);
+}
+
+static int lod_prep_md_striped_create(const struct lu_env *env,
+ struct dt_object *dt,
+ struct lu_attr *attr,
+ const struct lmv_user_md_v1 *lum,
+ struct dt_object_format *dof,
+ struct thandle *th)
+{
+ struct lod_device *lod = lu2lod_dev(dt->do_lu.lo_dev);
+ struct lod_tgt_descs *ltd = &lod->lod_mdt_descs;
+ struct lod_object *lo = lod_dt_obj(dt);
+ struct lod_thread_info *info = lod_env_info(env);
+ struct dt_object **stripe;
+ struct lu_buf lmv_buf;
+ struct lu_buf slave_lmv_buf;
+ struct lmv_mds_md_v1 *lmm;
+ struct lmv_mds_md_v1 *slave_lmm = NULL;
+ int stripe_count;
+ int *idx_array;
+ int rc = 0;
+ int i;
+ int j;
+ ENTRY;
+
+ /* The lum has been verifed in lod_verify_md_striping */
+ LASSERT(le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC);
+ LASSERT(le32_to_cpu(lum->lum_stripe_count) > 0);
+
+ stripe_count = le32_to_cpu(lum->lum_stripe_count);
+
+ /* shrink the stripe_count to the avaible MDT count */
+ if (stripe_count > lod->lod_remote_mdt_count + 1)
+ stripe_count = lod->lod_remote_mdt_count + 1;
+
+ OBD_ALLOC(stripe, sizeof(stripe[0]) * stripe_count);
+ if (stripe == NULL)
+ RETURN(-ENOMEM);
+
+ OBD_ALLOC(idx_array, sizeof(idx_array[0]) * stripe_count);
+ if (idx_array == NULL)
+ GOTO(out_free, rc = -ENOMEM);
+
+ for (i = 0; i < stripe_count; i++) {
+ struct lod_tgt_desc *tgt = NULL;
+ struct dt_object *dto;
+ struct lu_fid fid = { 0 };
+ int idx;
+ struct lu_object_conf conf = { 0 };
+ struct dt_device *tgt_dt = NULL;
+
+ if (i == 0) {
+ /* Right now, master stripe and master object are
+ * on the same MDT */
+ idx = le32_to_cpu(lum->lum_stripe_offset);
+ rc = obd_fid_alloc(env, lod->lod_child_exp, &fid,
+ NULL);
+ if (rc < 0)
+ GOTO(out_put, rc);
+ tgt_dt = lod->lod_child;
+ goto next;
+ }
+
+ idx = (idx_array[i - 1] + 1) % (lod->lod_remote_mdt_count + 1);
+
+ for (j = 0; j < lod->lod_remote_mdt_count;
+ j++, idx = (idx + 1) % (lod->lod_remote_mdt_count + 1)) {
+ bool already_allocated = false;
+ int k;
+
+ CDEBUG(D_INFO, "try idx %d, mdt cnt %d,"
+ " allocated %d, last allocated %d\n", idx,
+ lod->lod_remote_mdt_count, i, idx_array[i - 1]);
+
+ /* Find next available target */
+ if (!cfs_bitmap_check(ltd->ltd_tgt_bitmap, idx))
+ continue;
+
+ /* check whether the idx already exists
+ * in current allocated array */
+ for (k = 0; k < i; k++) {
+ if (idx_array[k] == idx) {
+ already_allocated = true;
+ break;
+ }
+ }
+
+ if (already_allocated)
+ continue;
+
+ /* check the status of the OSP */
+ tgt = LTD_TGT(ltd, idx);
+ if (tgt == NULL)
+ continue;
+
+ tgt_dt = tgt->ltd_tgt;
+ rc = dt_statfs(env, tgt_dt, NULL);
+ if (rc) {
+ /* this OSP doesn't feel well */
+ rc = 0;
+ continue;
+ }
+
+ rc = obd_fid_alloc(env, tgt->ltd_exp, &fid, NULL);
+ if (rc < 0) {
+ rc = 0;
+ continue;
+ }
+
+ break;
+ }
+
+ /* Can not allocate more stripes */
+ if (j == lod->lod_remote_mdt_count) {
+ CDEBUG(D_INFO, "%s: require stripes %d only get %d\n",
+ lod2obd(lod)->obd_name, stripe_count, i - 1);
+ break;
+ }
+
+ CDEBUG(D_INFO, "idx %d, mdt cnt %d,"
+ " allocated %d, last allocated %d\n", idx,
+ lod->lod_remote_mdt_count, i, idx_array[i - 1]);
+
+next:
+ /* tgt_dt and fid must be ready after search avaible OSP
+ * in the above loop */
+ LASSERT(tgt_dt != NULL);
+ LASSERT(fid_is_sane(&fid));
+ conf.loc_flags = LOC_F_NEW;
+ dto = dt_locate_at(env, tgt_dt, &fid,
+ dt->do_lu.lo_dev->ld_site->ls_top_dev,
+ &conf);
+ if (IS_ERR(dto))
+ GOTO(out_put, rc = PTR_ERR(dto));
+ stripe[i] = dto;
+ idx_array[i] = idx;
+ }
+
+ lo->ldo_dir_striped = 1;
+ lo->ldo_stripe = stripe;
+ lo->ldo_stripenr = i;
+ lo->ldo_stripes_allocated = stripe_count;
+
+ if (lo->ldo_stripenr == 0)
+ GOTO(out_put, rc = -ENOSPC);
+
+ rc = lod_prep_lmv_md(env, dt, &lmv_buf);
+ if (rc != 0)
+ GOTO(out_put, rc);
+ lmm = lmv_buf.lb_buf;
+
+ OBD_ALLOC_PTR(slave_lmm);
+ if (slave_lmm == NULL)
+ GOTO(out_put, rc = -ENOMEM);
+
+ lod_prep_slave_lmv_md(slave_lmm, lmm);
+ slave_lmv_buf.lb_buf = slave_lmm;
+ slave_lmv_buf.lb_len = sizeof(*slave_lmm);
+
+ if (!dt_try_as_dir(env, dt_object_child(dt)))
+ GOTO(out_put, rc = -EINVAL);
+
+ for (i = 0; i < lo->ldo_stripenr; i++) {
+ struct dt_object *dto = stripe[i];
+ char *stripe_name = info->lti_key;
+
+ rc = dt_declare_create(env, dto, attr, NULL, dof, th);
+ if (rc != 0)
+ GOTO(out_put, rc);
+
+ if (!dt_try_as_dir(env, dto))
+ GOTO(out_put, rc = -EINVAL);
+
+ rc = dt_declare_insert(env, dto,
+ (const struct dt_rec *)lu_object_fid(&dto->do_lu),
+ (const struct dt_key *)dot, th);
+ if (rc != 0)
+ GOTO(out_put, rc);
+
+ /* master stripe FID will be put to .. */
+ rc = dt_declare_insert(env, dto,
+ (const struct dt_rec *)lu_object_fid(&dt->do_lu),
+ (const struct dt_key *)dotdot, th);
+ if (rc != 0)
+ GOTO(out_put, rc);
+
+ /* probably nothing to inherite */
+ if (lo->ldo_striping_cached &&
+ !LOVEA_DELETE_VALUES(lo->ldo_def_stripe_size,
+ lo->ldo_def_stripenr,
+ lo->ldo_def_stripe_offset)) {
+ struct lov_user_md_v3 *v3;
+
+ /* sigh, lti_ea_store has been used for lmv_buf,
+ * so we have to allocate buffer for default
+ * stripe EA */
+ OBD_ALLOC_PTR(v3);
+ if (v3 == NULL)
+ GOTO(out_put, rc = -ENOMEM);
+
+ memset(v3, 0, sizeof(*v3));
+ v3->lmm_magic = cpu_to_le32(LOV_USER_MAGIC_V3);
+ v3->lmm_stripe_count =
+ cpu_to_le16(lo->ldo_def_stripenr);
+ v3->lmm_stripe_offset =
+ cpu_to_le16(lo->ldo_def_stripe_offset);
+ v3->lmm_stripe_size =
+ cpu_to_le32(lo->ldo_def_stripe_size);
+ if (lo->ldo_pool)
+ strncpy(v3->lmm_pool_name, lo->ldo_pool,
+ LOV_MAXPOOLNAME);
+
+ info->lti_buf.lb_buf = v3;
+ info->lti_buf.lb_len = sizeof(*v3);
+ rc = dt_declare_xattr_set(env, dto,
+ &info->lti_buf,
+ XATTR_NAME_LOV,
+ 0, th);
+ OBD_FREE_PTR(v3);
+ if (rc != 0)
+ GOTO(out_put, rc);
+ }
+
+ slave_lmm->lmv_master_mdt_index = cpu_to_le32(i);
+ rc = dt_declare_xattr_set(env, dto, &slave_lmv_buf,
+ XATTR_NAME_LMV, 0, th);
+ if (rc != 0)
+ GOTO(out_put, rc);
+
+ snprintf(stripe_name, sizeof(info->lti_key), DFID":%d",
+ PFID(lu_object_fid(&dto->do_lu)), i);
+ rc = dt_declare_insert(env, dt_object_child(dt),
+ (const struct dt_rec *)lu_object_fid(&dto->do_lu),
+ (const struct dt_key *)stripe_name, th);
+ if (rc != 0)
+ GOTO(out_put, rc);
+
+ rc = dt_declare_ref_add(env, dt_object_child(dt), th);
+ if (rc != 0)
+ GOTO(out_put, rc);
+ }
+
+ rc = dt_declare_xattr_set(env, dt_object_child(dt), &lmv_buf,
+ XATTR_NAME_LMV, 0, th);
+ if (rc != 0)
+ GOTO(out_put, rc);
+
+out_put:
+ if (rc < 0) {
+ for (i = 0; i < stripe_count; i++)
+ if (stripe[i] != NULL)
+ lu_object_put(env, &stripe[i]->do_lu);
+ OBD_FREE(stripe, sizeof(stripe[0]) * stripe_count);
+ lo->ldo_stripenr = 0;
+ lo->ldo_stripes_allocated = 0;
+ lo->ldo_stripe = NULL;
+ }
+
+out_free:
+ if (idx_array != NULL)
+ OBD_FREE(idx_array, sizeof(idx_array[0]) * stripe_count);
+ if (slave_lmm != NULL)
+ OBD_FREE_PTR(slave_lmm);
+
+ RETURN(rc);
+}
+
+/**
+ * Declare create striped md object.
+ */
+static int lod_declare_xattr_set_lmv(const struct lu_env *env,
+ struct dt_object *dt,
+ struct lu_attr *attr,
+ const struct lu_buf *lum_buf,
+ struct dt_object_format *dof,
+ struct thandle *th)
+{
+ struct lod_object *lo = lod_dt_obj(dt);
+ struct lod_device *lod = lu2lod_dev(dt->do_lu.lo_dev);
+ struct lmv_user_md_v1 *lum;
+ int rc;
+ ENTRY;
+
+ lum = lum_buf->lb_buf;
+ LASSERT(lum != NULL);
+
+ CDEBUG(D_INFO, "lum magic = %x count = %u offset = %d\n",
+ le32_to_cpu(lum->lum_magic), le32_to_cpu(lum->lum_stripe_count),
+ (int)le32_to_cpu(lum->lum_stripe_offset));
+
+ if (le32_to_cpu(lum->lum_stripe_count) == 0)
+ GOTO(out, rc = 0);
+
+ rc = lod_verify_md_striping(lod, lum);
+ if (rc != 0)
+ GOTO(out, rc);
+
+ /* prepare dir striped objects */
+ rc = lod_prep_md_striped_create(env, dt, attr, lum, dof, th);
+ if (rc != 0) {
+ /* failed to create striping, let's reset
+ * config so that others don't get confused */
+ lod_object_free_striping(env, lo);
+ GOTO(out, rc);
+ }
+out:
+ RETURN(rc);
+}
+
+static int lod_dir_declare_xattr_set(const struct lu_env *env,
+ struct dt_object *dt,
+ const struct lu_buf *buf,
+ const char *name, int fl,
+ struct thandle *th)
+{
+ struct dt_object *next = dt_object_child(dt);
+ struct lod_device *d = lu2lod_dev(dt->do_lu.lo_dev);
+ struct lod_object *lo = lod_dt_obj(dt);
+ int i;
+ int rc;
+ ENTRY;
+
+ if (strcmp(name, XATTR_NAME_DEFAULT_LMV) == 0) {
+ struct lmv_user_md_v1 *lum;
+
+ LASSERT(buf != NULL && buf->lb_buf != NULL);
+ lum = buf->lb_buf;
+ rc = lod_verify_md_striping(d, lum);
+ if (rc != 0)
+ RETURN(rc);
+ }
+
+ rc = dt_declare_xattr_set(env, next, buf, name, fl, th);
+ if (rc != 0)
+ RETURN(rc);
+
+ /* set xattr to each stripes, if needed */
+ rc = lod_load_striping(env, lo);
+ if (rc != 0)
+ RETURN(rc);
+
+ if (lo->ldo_stripenr == 0)
+ RETURN(rc);
+
+ for (i = 0; i < lo->ldo_stripenr; i++) {
+ LASSERT(lo->ldo_stripe[i]);
+ rc = dt_declare_xattr_set(env, lo->ldo_stripe[i], buf,
+ name, fl, th);
+ if (rc != 0)
+ break;
+ }
+
+ RETURN(rc);
+}
+