From 44a721b8c10631b52f9ee2fbac1eee8cb775d148 Mon Sep 17 00:00:00 2001 From: Mikhail Pershin Date: Fri, 28 Jun 2019 13:54:04 +0300 Subject: [PATCH] LU-11421 dom: manual OST-to-DOM migration via mirroring Allow DOM mirroring, update LOV/LOD code to check not just first component for DOM pattern but cycle through all mirrors if any. Sanity checks allows one DOM component in a mirror and it should be the first one. Multiple DOM components are allowed only with the same for now. Do OST file migration to MDT by using FLR. That can't be done by layout swapping, because MDT data will be tied to temporary volatile file but we want to keep data with the original file. The mirroring allows that with the following steps: - extent layout with new mirror on MDT, no data is copied but new mirror stays in 'stale' state. The reason is the same problem with volatile file. - resync mirrors, now new DOM layout is filled with data. - remove first mirror Signed-off-by: Mikhail Pershin Change-Id: I1d4213196a16d6aec70861c5530910cac062e34f Reviewed-on: https://review.whamcloud.com/35359 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Bobi Jam Reviewed-by: Oleg Drokin --- lustre/include/lustre/lustreapi.h | 1 + lustre/lod/lod_lov.c | 18 +++---- lustre/lod/lod_object.c | 12 +++++ lustre/lov/lov_object.c | 25 +++++++-- lustre/mdd/mdd_object.c | 14 ++++- lustre/mdt/mdt_internal.h | 12 +++-- lustre/tests/sanity.sh | 108 +++++++++++++++++++++++++++++++++++-- lustre/utils/lfs.c | 104 ++++++++++++++++++++++++++++++++++- lustre/utils/liblustreapi_layout.c | 46 +++++++++++++--- 9 files changed, 313 insertions(+), 27 deletions(-) diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index 4839fca..32e1ca1 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -1074,6 +1074,7 @@ int llapi_heat_get(int fd, struct lu_heat *heat); int llapi_heat_set(int fd, __u64 flags); int llapi_layout_sanity(struct llapi_layout *layout, bool incomplete, bool flr); void llapi_layout_sanity_perror(int error); +int llapi_layout_dom_size(struct llapi_layout *layout, uint64_t *size); /** @} llapi */ diff --git a/lustre/lod/lod_lov.c b/lustre/lod/lod_lov.c index c044bd1..8c3776e 100644 --- a/lustre/lod/lod_lov.c +++ b/lustre/lod/lod_lov.c @@ -1752,9 +1752,10 @@ struct lov_comp_md_entry_v1 *comp_entry_v1(struct lov_comp_md_v1 *comp, int i) le16_to_cpu(comp->lcm_entry_count) - 1); \ entry++) -int lod_erase_dom_stripe(struct lov_comp_md_v1 *comp_v1) +int lod_erase_dom_stripe(struct lov_comp_md_v1 *comp_v1, + struct lov_comp_md_entry_v1 *dom_ent) { - struct lov_comp_md_entry_v1 *ent, *dom_ent; + struct lov_comp_md_entry_v1 *ent; __u16 entries; __u32 dom_off, dom_size, comp_size; void *blob_src, *blob_dst; @@ -1766,7 +1767,6 @@ int lod_erase_dom_stripe(struct lov_comp_md_v1 *comp_v1) return -EFBIG; comp_size = le32_to_cpu(comp_v1->lcm_size); - dom_ent = &comp_v1->lcm_entries[0]; dom_off = le32_to_cpu(dom_ent->lcme_offset); dom_size = le32_to_cpu(dom_ent->lcme_size); @@ -1796,16 +1796,16 @@ int lod_erase_dom_stripe(struct lov_comp_md_v1 *comp_v1) return -ERESTART; } -int lod_fix_dom_stripe(struct lod_device *d, struct lov_comp_md_v1 *comp_v1) +int lod_fix_dom_stripe(struct lod_device *d, struct lov_comp_md_v1 *comp_v1, + struct lov_comp_md_entry_v1 *dom_ent) { - struct lov_comp_md_entry_v1 *ent, *dom_ent; + struct lov_comp_md_entry_v1 *ent; struct lu_extent *dom_ext, *ext; struct lov_user_md_v1 *lum; __u32 stripe_size; __u16 mid, dom_mid; int rc = 0; - dom_ent = &comp_v1->lcm_entries[0]; dom_ext = &dom_ent->lcme_extent; dom_mid = mirror_id_of(le32_to_cpu(dom_ent->lcme_id)); stripe_size = d->lod_dom_max_stripesize; @@ -1842,7 +1842,7 @@ int lod_fix_dom_stripe(struct lod_device *d, struct lov_comp_md_v1 *comp_v1) if (stripe_size == 0) { /* DoM component size is zero due to server setting, * remove it from the layout */ - rc = lod_erase_dom_stripe(comp_v1); + rc = lod_erase_dom_stripe(comp_v1, dom_ent); } else { /* Update DoM extent end finally */ dom_ext->e_end = cpu_to_le64(stripe_size); @@ -2015,7 +2015,7 @@ recheck: lum = tmp.lb_buf; if (lov_pattern(le32_to_cpu(lum->lmm_pattern)) == LOV_PATTERN_MDT) { - /* DoM component can be only the first stripe */ + /* DoM component must be the first in a mirror */ if (le64_to_cpu(ext->e_start) > 0) { CDEBUG(D_LAYOUT, "invalid DoM component " "with %llu extent start\n", @@ -2038,7 +2038,7 @@ recheck: "%u is bigger than MDT limit %u, check " "dom_max_stripesize parameter\n", stripe_size, d->lod_dom_max_stripesize); - rc = lod_fix_dom_stripe(d, comp_v1); + rc = lod_fix_dom_stripe(d, comp_v1, ent); if (rc == -ERESTART) { /* DoM entry was removed, re-check * new layout from start */ diff --git a/lustre/lod/lod_object.c b/lustre/lod/lod_object.c index 1fa0ffb..fb8ea42 100644 --- a/lustre/lod/lod_object.c +++ b/lustre/lod/lod_object.c @@ -3236,6 +3236,7 @@ static int lod_declare_layout_merge(const struct lu_env *env, struct lov_comp_md_v1 *cur_lcm; struct lov_comp_md_v1 *merge_lcm; struct lov_comp_md_entry_v1 *lcme; + struct lov_mds_md_v1 *lmm; size_t size = 0; size_t offset; __u16 cur_entry_count; @@ -3244,6 +3245,8 @@ static int lod_declare_layout_merge(const struct lu_env *env, __u16 mirror_id = 0; __u32 mirror_count; int rc, i; + bool merge_has_dom; + ENTRY; merge_lcm = mbuf->lb_buf; @@ -3331,6 +3334,13 @@ static int lod_declare_layout_merge(const struct lu_env *env, } mirror_id = mirror_id_of(id) + 1; + + /* check if first entry in new layout is DOM */ + lmm = (struct lov_mds_md_v1 *)((char *)merge_lcm + + merge_lcm->lcm_entries[0].lcme_offset); + merge_has_dom = lov_pattern(le32_to_cpu(lmm->lmm_pattern)) == + LOV_PATTERN_MDT; + for (i = 0; i < merge_entry_count; i++) { struct lov_comp_md_entry_v1 *merge_lcme; @@ -3339,6 +3349,8 @@ static int lod_declare_layout_merge(const struct lu_env *env, *lcme = *merge_lcme; lcme->lcme_offset = cpu_to_le32(offset); + if (merge_has_dom && i == 0) + lcme->lcme_flags |= cpu_to_le32(LCME_FL_STALE); id = pflr_id(mirror_id, i + 1); lcme->lcme_id = cpu_to_le32(id); diff --git a/lustre/lov/lov_object.c b/lustre/lov/lov_object.c index cc041c0..629f5e6 100644 --- a/lustre/lov/lov_object.c +++ b/lustre/lov/lov_object.c @@ -541,13 +541,18 @@ static int lov_init_dom(const struct lu_env *env, struct lov_device *dev, struct cl_device *mdcdev; struct lov_oinfo *loi = NULL; struct cl_object_conf *sconf = <i->lti_stripe_conf; - int rc; __u32 idx = 0; ENTRY; - LASSERT(index == 0); + /* DOM entry may be not zero index due to FLR but must start from 0 */ + if (unlikely(lle->lle_extent->e_start != 0)) { + CERROR("%s: DOM entry must be the first stripe in a mirror\n", + lov2obd(dev->ld_lov)->obd_name); + dump_lsm(D_ERROR, lov->lo_lsm); + RETURN(-EINVAL); + } /* find proper MDS device */ rc = lov_fld_lookup(dev, fid, &idx); @@ -640,6 +645,7 @@ static int lov_init_composite(const struct lu_env *env, struct lov_device *dev, int result = 0; unsigned int seq; int i, j; + bool dom_size = 0; ENTRY; @@ -683,6 +689,18 @@ static int lov_init_composite(const struct lu_env *env, struct lov_device *dev, lle->lle_comp_ops = &raid0_ops; break; case LOV_PATTERN_MDT: + /* Allowed to have several DOM stripes in different + * mirrors with the same DoM size. + */ + if (!dom_size) { + dom_size = lle->lle_lsme->lsme_extent.e_end; + } else if (dom_size != + lle->lle_lsme->lsme_extent.e_end) { + CERROR("%s: DOM entries with different sizes\n", + lov2obd(dev->ld_lov)->obd_name); + dump_lsm(D_ERROR, lsm); + RETURN(-EINVAL); + } lle->lle_comp_ops = &dom_ops; break; default: @@ -873,7 +891,8 @@ static void lov_fini_composite(const struct lu_env *env, struct lov_layout_entry *entry; lov_foreach_layout_entry(lov, entry) - entry->lle_comp_ops->lco_fini(env, entry); + if (entry->lle_comp_ops) + entry->lle_comp_ops->lco_fini(env, entry); OBD_FREE(comp->lo_entries, comp->lo_entry_count * sizeof(*comp->lo_entries)); diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index c993376..e4357ec 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -1712,6 +1712,9 @@ static int mdd_split_ea(struct lov_comp_md_v1 *comp_v1, __u16 mirror_id, return 0; } +static int mdd_dom_data_truncate(const struct lu_env *env, + struct mdd_device *mdd, struct mdd_object *mo); + static int mdd_xattr_split(const struct lu_env *env, struct md_object *md_obj, struct md_rejig_data *mrd) { @@ -1724,6 +1727,8 @@ static int mdd_xattr_split(const struct lu_env *env, struct md_object *md_obj, struct lov_comp_md_v1 *lcm; struct thandle *handle; int rc; + bool dom_stripe = false; + ENTRY; rc = lu_fid_cmp(mdo2fid(obj), mdo2fid(vic)); @@ -1762,6 +1767,8 @@ static int mdd_xattr_split(const struct lu_env *env, struct md_object *md_obj, if (rc < 0) GOTO(out, rc); + dom_stripe = mdd_lmm_dom_size(buf_vic->lb_buf) > 0; + rc = mdd_declare_xattr_set(env, mdd, obj, buf, XATTR_NAME_LOV, LU_XATTR_SPLIT, handle); if (rc) @@ -1805,7 +1812,12 @@ out_restore: mdd_obj_dev_name(obj), PFID(mdo2fid(obj)), rc2); } out: - mdd_trans_stop(env, mdd, rc, handle); + rc = mdd_trans_stop(env, mdd, rc, handle); + + /* Truncate local DOM data if all went well */ + if (!rc && dom_stripe) + mdd_dom_data_truncate(env, mdd, obj); + mdd_write_unlock(env, obj); mdd_write_unlock(env, vic); lu_buf_free(buf_save); diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index 79eaf99f..5a16cec 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -676,6 +676,7 @@ static inline int mdt_lmm_dom_entry(struct lov_mds_md *lmm) struct lov_comp_md_v1 *comp_v1; struct lov_mds_md *v1; __u32 off; + bool has_dom = true; int i; if (le32_to_cpu(lmm->lmm_magic) != LOV_MAGIC_COMP_V1) @@ -686,15 +687,20 @@ static inline int mdt_lmm_dom_entry(struct lov_mds_md *lmm) v1 = (struct lov_mds_md *)((char *)comp_v1 + off); /* DoM entry is the first entry always */ - if (lov_pattern(le32_to_cpu(v1->lmm_pattern)) != LOV_PATTERN_MDT) + if (lov_pattern(le32_to_cpu(v1->lmm_pattern)) != LOV_PATTERN_MDT && + le16_to_cpu(comp_v1->lcm_mirror_count) == 0) return LMM_NO_DOM; - for (i = 1; i < le16_to_cpu(comp_v1->lcm_entry_count); i++) { + for (i = 0; i < le16_to_cpu(comp_v1->lcm_entry_count); i++) { int j; off = le32_to_cpu(comp_v1->lcm_entries[i].lcme_offset); v1 = (struct lov_mds_md *)((char *)comp_v1 + off); + if (lov_pattern(le32_to_cpu(v1->lmm_pattern)) == + LOV_PATTERN_MDT) + has_dom = true; + for (j = 0; j < le16_to_cpu(v1->lmm_stripe_count); j++) { /* if there is any object on OST */ if (le32_to_cpu(v1->lmm_objects[j].l_ost_idx) != @@ -702,7 +708,7 @@ static inline int mdt_lmm_dom_entry(struct lov_mds_md *lmm) return LMM_DOM_OST; } } - return LMM_DOM_ONLY; + return has_dom ? LMM_DOM_ONLY : LMM_NO_DOM; } static inline bool mdt_lmm_is_flr(struct lov_mds_md *lmm) diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 2b02c2f..b1aad87 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -18385,12 +18385,12 @@ test_272b() { $LFS migrate -c2 $dom || error "failed to migrate to the new composite layout" - [ $($LFS getstripe -L $dom) == 'mdt' ] && + [ $($LFS getstripe -L $dom) != 'mdt' ] || error "MDT stripe was not removed" cancel_lru_locks mdc local new_md5=$(md5sum $dom) - [ "$old_md5" != "$new_md5" ] && + [ "$old_md5" == "$new_md5" ] || error "$old_md5 != $new_md5" # Skip free space checks with ZFS @@ -18430,7 +18430,7 @@ test_272c() { cancel_lru_locks mdc local new_md5=$(md5sum $dom) - [ "$old_md5" != "$new_md5" ] && + [ "$old_md5" == "$new_md5" ] || error "$old_md5 != $new_md5" # Skip free space checks with ZFS @@ -18444,6 +18444,108 @@ test_272c() { } run_test 272c "DoM migration: DOM file to the OST-striped file (composite)" +test_272d() { + [ $MDS1_VERSION -lt $(version_code 2.12.55) ] && + skip "Need MDS version at least 2.12.55" + + local dom=$DIR/$tdir/$tfile + mkdir -p $DIR/$tdir + $LFS setstripe -E 1M -L mdt -E -1 -c1 $dom + + local mdtidx=$($LFS getstripe -m $dom) + local mdtname=MDT$(printf %04x $mdtidx) + local facet=mds$((mdtidx + 1)) + + dd if=/dev/urandom of=$dom bs=2M count=1 oflag=direct || + error "failed to write data into $dom" + local old_md5=$(md5sum $dom) + cancel_lru_locks mdc + local mdtfree1=$(do_facet $facet \ + lctl get_param -n osd*.*$mdtname.kbytesfree) + + $LFS mirror extend -N -E 2M -c1 -E -1 -c2 $dom || + error "failed mirroring to the new composite layout" + $LFS mirror resync $dom || + error "failed mirror resync" + $LFS mirror split --mirror-id 1 -d $dom || + error "failed mirror split" + + [ $($LFS getstripe -L $dom) != 'mdt' ] || + error "MDT stripe was not removed" + + cancel_lru_locks mdc + local new_md5=$(md5sum $dom) + [ "$old_md5" == "$new_md5" ] || + error "$old_md5 != $new_md5" + + # Skip free space checks with ZFS + if [ "$(facet_fstype $facet)" != "zfs" ]; then + local mdtfree2=$(do_facet $facet \ + lctl get_param -n osd*.*$mdtname.kbytesfree) + [ $mdtfree2 -gt $mdtfree1 ] || + error "MDS space is not freed after DOM mirror deletion" + fi + return 0 +} +run_test 272d "DoM mirroring: OST-striped mirror to DOM file" + +test_272e() { + [ $MDS1_VERSION -lt $(version_code 2.12.55) ] && + skip "Need MDS version at least 2.12.55" + + local dom=$DIR/$tdir/$tfile + mkdir -p $DIR/$tdir + $LFS setstripe -c 2 $dom + + dd if=/dev/urandom of=$dom bs=512K count=1 oflag=direct || + error "failed to write data into $dom" + local old_md5=$(md5sum $dom) + cancel_lru_locks mdc + + $LFS mirror extend -N -E 1M -L mdt -E eof -c2 $dom || + error "failed mirroring to the DOM layout" + $LFS mirror resync $dom || + error "failed mirror resync" + $LFS mirror split --mirror-id 1 -d $dom || + error "failed mirror split" + + [ $($LFS getstripe -L $dom) != 'mdt' ] || + error "MDT stripe was not removed" + + cancel_lru_locks mdc + local new_md5=$(md5sum $dom) + [ "$old_md5" == "$new_md5" ] || + error "$old_md5 != $new_md5" + + return 0 +} +run_test 272e "DoM mirroring: DOM mirror to the OST-striped file" + +test_272f() { + [ $MDS1_VERSION -lt $(version_code 2.12.55) ] && + skip "Need MDS version at least 2.12.55" + + local dom=$DIR/$tdir/$tfile + mkdir -p $DIR/$tdir + $LFS setstripe -c 2 $dom + + dd if=/dev/urandom of=$dom bs=512K count=1 oflag=direct || + error "failed to write data into $dom" + local old_md5=$(md5sum $dom) + cancel_lru_locks mdc + + $LFS migrate -E 1M -L mdt -E eof -c2 -v $dom || + error "failed migrating to the DOM file" + + cancel_lru_locks mdc + local new_md5=$(md5sum $dom) + [ "$old_md5" != "$new_md5" ] && + error "$old_md5 != $new_md5" + + return 0 +} +run_test 272f "DoM migration: OST-striped file to DOM file" + test_273a() { [ $MDS1_VERSION -lt $(version_code 2.11.50) ] && skip "Need MDS version at least 2.11.50" diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index cf22944..e5ecd75 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -135,6 +135,10 @@ static int lfs_pcc_detach_fid(int argc, char **argv); static int lfs_pcc_state(int argc, char **argv); static int lfs_pcc(int argc, char **argv); static int lfs_pcc_list_commands(int argc, char **argv); +static int lfs_migrate_to_dom(int fd, int fdv, char *name, + __u64 migration_flags, + struct llapi_stripe_param *param, + struct llapi_layout *layout); enum setstripe_origin { SO_SETSTRIPE, @@ -1185,6 +1189,8 @@ static int lfs_migrate(char *name, __u64 migration_flags, struct llapi_stripe_param *param, struct llapi_layout *layout) { + struct llapi_layout *existing; + uint64_t dom_new, dom_cur; int fd = -1; int fdv = -1; int rc; @@ -1194,6 +1200,36 @@ static int lfs_migrate(char *name, __u64 migration_flags, if (rc < 0) goto out; + rc = llapi_layout_dom_size(layout, &dom_new); + if (rc) { + error_loc = "cannot get new layout DoM size"; + goto out; + } + /* special case for migration to DOM layout*/ + existing = llapi_layout_get_by_fd(fd, 0); + if (!existing) { + error_loc = "cannot get existing layout"; + goto out; + } + + rc = llapi_layout_dom_size(existing, &dom_cur); + if (rc) { + error_loc = "cannot get current layout DoM size"; + goto out; + } + + /* if file has DoM layout already then migration is possible to + * the new layout with the same DoM component via swap layout, + * if new layout used bigger DOM size, then mirroring is used + */ + if (dom_new > dom_cur) { + rc = lfs_migrate_to_dom(fd, fdv, name, migration_flags, param, + layout); + if (rc) + error_loc = "cannot migrate to DOM layout"; + goto out_closed; + } + if (!(migration_flags & MIGRATION_NONBLOCK)) { /* Blocking mode (forced if servers do not support file lease). * It is also the default mode, since we cannot distinguish @@ -1230,7 +1266,7 @@ out: if (fdv >= 0) close(fdv); - +out_closed: if (rc < 0) fprintf(stderr, "error: %s: %s: %s: %s\n", progname, name, error_loc, strerror(-rc)); @@ -1989,6 +2025,72 @@ free_layout: return rc; } +static inline +int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, + __u16 *mirror_ids, int ids_nr); + +static int lfs_migrate_to_dom(int fd, int fdv, char *name, + __u64 migration_flags, + struct llapi_stripe_param *param, + struct llapi_layout *layout) +{ + struct ll_ioc_lease *data = NULL; + int rc; + + rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK); + if (rc < 0) { + error_loc = "cannot get lease"; + goto out_close; + } + + /* Atomically put lease, merge layouts, resync and close. */ + data = calloc(1, offsetof(typeof(*data), lil_ids[1024])); + if (!data) { + error_loc = "memory allocation"; + goto out_close; + } + data->lil_mode = LL_LEASE_UNLCK; + data->lil_flags = LL_LEASE_LAYOUT_MERGE; + data->lil_count = 1; + data->lil_ids[0] = fdv; + rc = llapi_lease_set(fd, data); + if (rc < 0) { + error_loc = "cannot merge layout"; + goto out_close; + } else if (rc == 0) { + rc = -EBUSY; + error_loc = "lost lease lock"; + goto out_close; + } + close(fd); + close(fdv); + + rc = lfs_mirror_resync_file(name, data, NULL, 0); + if (rc) { + error_loc = "cannot resync file"; + goto out; + } + + /* delete first mirror now */ + rc = mirror_split(name, 1, NULL, MF_DESTROY, NULL); + if (rc < 0) + error_loc = "cannot delete old layout"; + goto out; + +out_close: + close(fd); + close(fdv); +out: + if (rc < 0) + fprintf(stderr, "error: %s: %s: %s: %s\n", + progname, name, error_loc, strerror(-rc)); + else if (migration_flags & MIGRATION_VERBOSE) + printf("%s\n", name); + if (data) + free(data); + return rc; +} + /** * Parse a string containing an target index list into an array of integers. * diff --git a/lustre/utils/liblustreapi_layout.c b/lustre/utils/liblustreapi_layout.c index fefb4f2..d88deb3 100644 --- a/lustre/utils/liblustreapi_layout.c +++ b/lustre/utils/liblustreapi_layout.c @@ -2987,7 +2987,7 @@ enum llapi_layout_comp_sanity_error { LSE_FLAGS, LSE_DOM_EXTENSION, LSE_DOM_EXTENSION_FOLLOWING, - LSE_DOM_FLR, + LSE_DOM_FIRST, LSE_SET_COMP_START, LSE_NOT_ZERO_LENGTH_EXTENDABLE, LSE_END_NOT_GREATER, @@ -3014,8 +3014,8 @@ const char *llapi_layout_strerror[] = "DoM components can't be extension space", [LSE_DOM_EXTENSION_FOLLOWING] = "DoM components cannot be followed by extension space", - [LSE_DOM_FLR] = - "FLR and DoM are not supported together", + [LSE_DOM_FIRST] = + "DoM component should be the first one in a file/mirror", [LSE_SET_COMP_START] = "Must set previous component extent before adding next", [LSE_NOT_ZERO_LENGTH_EXTENDABLE] = @@ -3127,10 +3127,10 @@ static int llapi_layout_sanity_cb(struct llapi_layout *layout, goto out_err; } - /* DoM and FLR are not supported together */ - if (args->lsa_flr && first_comp) { - args->lsa_rc = LSE_DOM_FLR; - errno = ENOTSUP; + /* DoM should be the first component in a mirror */ + if (!first_comp) { + args->lsa_rc = LSE_DOM_FIRST; + errno = EINVAL; goto out_err; } } @@ -3281,3 +3281,35 @@ int llapi_layout_sanity(struct llapi_layout *layout, bool incomplete, bool flr) return rc; } + +int llapi_layout_dom_size(struct llapi_layout *layout, uint64_t *size) +{ + uint64_t pattern, start; + int rc; + + if (!layout || !llapi_layout_is_composite(layout)) { + *size = 0; + return 0; + } + + rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST); + if (rc) + return -errno; + + rc = llapi_layout_pattern_get(layout, &pattern); + if (rc) + return -errno; + + if (pattern != LOV_PATTERN_MDT && pattern != LLAPI_LAYOUT_MDT) { + *size = 0; + return 0; + } + + rc = llapi_layout_comp_extent_get(layout, &start, size); + if (rc) + return -errno; + if (start) + return -ERANGE; + return 0; +} + -- 1.8.3.1