From 6e330ca0dc0364740de03748173209f9dfe727f2 Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Tue, 19 May 2026 16:55:19 +0000 Subject: [PATCH 1/2] DAOS-17321 vos: minor test and formatting fixes Fix resource leak in io_sgl_fetch(): move d_sgl_fini() before the error check so the SGL is freed regardless of vos_obj_update() return code. Fix missing newline in two D_PRINT() calls in vos_tests.c. Apply clang-format alignment to VOS_OF_* enum in vos_types.h to fix pre-existing clang-format non-conformance. Reformat io_test_init_csummer() in vts_io.c to match clang-format style. Signed-off-by: Cedric Koch-Hofer --- src/include/daos_srv/vos_types.h | 42 ++++++++++++++++---------------- src/vos/tests/vos_tests.c | 6 ++--- src/vos/tests/vts_io.c | 13 +++++----- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/include/daos_srv/vos_types.h b/src/include/daos_srv/vos_types.h index ee64bb92e1b..2864aefaf73 100644 --- a/src/include/daos_srv/vos_types.h +++ b/src/include/daos_srv/vos_types.h @@ -260,49 +260,49 @@ typedef enum { enum { /** Conditional Op: Punch key if it exists, fail otherwise */ - VOS_OF_COND_PUNCH = DAOS_COND_PUNCH, + VOS_OF_COND_PUNCH = DAOS_COND_PUNCH, /** Conditional Op: Insert dkey if it doesn't exist, fail otherwise */ - VOS_OF_COND_DKEY_INSERT = DAOS_COND_DKEY_INSERT, + VOS_OF_COND_DKEY_INSERT = DAOS_COND_DKEY_INSERT, /** Conditional Op: Update dkey if it exists, fail otherwise */ - VOS_OF_COND_DKEY_UPDATE = DAOS_COND_DKEY_UPDATE, + VOS_OF_COND_DKEY_UPDATE = DAOS_COND_DKEY_UPDATE, /** Conditional Op: Fetch dkey if it exists, fail otherwise */ - VOS_OF_COND_DKEY_FETCH = DAOS_COND_DKEY_FETCH, + VOS_OF_COND_DKEY_FETCH = DAOS_COND_DKEY_FETCH, /** Conditional Op: Insert akey if it doesn't exist, fail otherwise */ - VOS_OF_COND_AKEY_INSERT = DAOS_COND_AKEY_INSERT, + VOS_OF_COND_AKEY_INSERT = DAOS_COND_AKEY_INSERT, /** Conditional Op: Update akey if it exists, fail otherwise */ - VOS_OF_COND_AKEY_UPDATE = DAOS_COND_AKEY_UPDATE, + VOS_OF_COND_AKEY_UPDATE = DAOS_COND_AKEY_UPDATE, /** Conditional Op: Fetch akey if it exists, fail otherwise */ - VOS_OF_COND_AKEY_FETCH = DAOS_COND_AKEY_FETCH, + VOS_OF_COND_AKEY_FETCH = DAOS_COND_AKEY_FETCH, /** Indicates akey conditions are specified in iod_flags */ - VOS_OF_COND_PER_AKEY = DAOS_COND_PER_AKEY, + VOS_OF_COND_PER_AKEY = DAOS_COND_PER_AKEY, /* critical update - skip checks on SCM system/held space */ - VOS_OF_CRIT = (1 << 8), + VOS_OF_CRIT = (1 << 8), /** Instead of update or punch of extents, remove all extents * under the specified range. Intended for internal use only. */ - VOS_OF_REMOVE = (1 << 9), + VOS_OF_REMOVE = (1 << 9), /* only query iod_size */ - VOS_OF_FETCH_SIZE_ONLY = (1 << 10), + VOS_OF_FETCH_SIZE_ONLY = (1 << 10), /* query recx list */ - VOS_OF_FETCH_RECX_LIST = (1 << 11), + VOS_OF_FETCH_RECX_LIST = (1 << 11), /* only set read TS */ - VOS_OF_FETCH_SET_TS_ONLY = (1 << 12), + VOS_OF_FETCH_SET_TS_ONLY = (1 << 12), /* check the target (obj/dkey/akey) existence */ - VOS_OF_FETCH_CHECK_EXISTENCE = (1 << 13), + VOS_OF_FETCH_CHECK_EXISTENCE = (1 << 13), /** Set when propagating a punch that results in empty subtree */ - VOS_OF_PUNCH_PROPAGATE = (1 << 14), + VOS_OF_PUNCH_PROPAGATE = (1 << 14), /** replay punch (underwrite) */ - VOS_OF_REPLAY_PC = (1 << 15), + VOS_OF_REPLAY_PC = (1 << 15), /** Dedup update mode */ - VOS_OF_DEDUP = (1 << 16), + VOS_OF_DEDUP = (1 << 16), /** Dedup update with memcmp verify mode */ - VOS_OF_DEDUP_VERIFY = (1 << 17), + VOS_OF_DEDUP_VERIFY = (1 << 17), /** Ignore fetch only used by shadow fetch to ignore the evt fetch */ - VOS_OF_SKIP_FETCH = (1 << 18), + VOS_OF_SKIP_FETCH = (1 << 18), /** Operation on EC object (currently only applies to update) */ - VOS_OF_EC = (1 << 19), + VOS_OF_EC = (1 << 19), /** Update from rebuild */ - VOS_OF_REBUILD = (1 << 20), + VOS_OF_REBUILD = (1 << 20), }; enum { diff --git a/src/vos/tests/vos_tests.c b/src/vos/tests/vos_tests.c index 4fa1ac00c42..126327cc4c1 100644 --- a/src/vos/tests/vos_tests.c +++ b/src/vos/tests/vos_tests.c @@ -1,6 +1,6 @@ /** * (C) Copyright 2016-2023 Intel Corporation. - * (C) Copyright 2025 Hewlett Packard Enterprise Development LP. + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -166,7 +166,7 @@ main(int argc, char **argv) #if CMOCKA_FILTER_SUPPORTED == 1 /** requires cmocka 1.1.5 */ cmocka_set_skip_filter(optarg); #else - D_PRINT("filter not enabled"); + D_PRINT("filter not enabled\n"); #endif break; @@ -181,7 +181,7 @@ main(int argc, char **argv) printf("Test filter: %s\n", filter); } #else - D_PRINT("filter not enabled"); + D_PRINT("filter not enabled\n"); #endif break; case FORCE_CSUM: diff --git a/src/vos/tests/vts_io.c b/src/vos/tests/vts_io.c index fdad31e03bb..d64c475f6d0 100644 --- a/src/vos/tests/vts_io.c +++ b/src/vos/tests/vts_io.c @@ -1,6 +1,6 @@ /** * (C) Copyright 2016-2024 Intel Corporation. - * (C) Copyright 2025 Hewlett Packard Enterprise Development LP + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -553,12 +553,11 @@ io_obj_iter_test(struct io_test_args *arg, daos_epoch_range_t *epr, static struct daos_csummer * io_test_init_csummer() { - enum DAOS_HASH_TYPE type = HASH_TYPE_CRC16; - size_t chunk_size = 1 << 12; - struct daos_csummer *csummer = NULL; + enum DAOS_HASH_TYPE type = HASH_TYPE_CRC16; + size_t chunk_size = 1 << 12; + struct daos_csummer *csummer = NULL; - assert_success(daos_csummer_init_with_type(&csummer, type, - chunk_size, 0)); + assert_success(daos_csummer_init_with_type(&csummer, type, chunk_size, 0)); return csummer; @@ -2315,9 +2314,9 @@ io_sgl_fetch(void **state) /* Write/Update */ rc = vos_obj_update(arg->ctx.tc_co_hdl, arg->oid, 1, 0, 0, &dkey, 1, &iod, NULL, &sgl); + d_sgl_fini(&sgl, false); if (rc) goto exit; - d_sgl_fini(&sgl, false); inc_cntr(arg->ta_flags); /* Allocate memory for the scatter-gather list */ From 2a922ea31f7d7b3fc9dd7b3a6b3594f3d4d96826 Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Tue, 19 May 2026 16:56:21 +0000 Subject: [PATCH 2/2] DAOS-17321 vos: add VOS_OF_FETCH_CSUM flag for checksum-only fetch Add VOS_OF_FETCH_CSUM (1 << 21) flag to vos_fetch_begin() allowing callers to retrieve per-extent checksum metadata without fetching the actual data. This is intended for the ddb (DAOS Debugger) tool which needs to inspect and manage checksums stored in VOS. When VOS_OF_FETCH_CSUM is set: - SGL/bio-buffer allocation is skipped (like VOS_OF_FETCH_SIZE_ONLY). - For single-value records: save_csum() is called, then the data fetch is skipped. iod_size is not updated. - For array records: save_csum() is called as normal, and the full stored extent bounds (en_ext) plus epoch are saved via save_recx() so that callers get the raw per-version extent list paired with their checksums via vos_ioh2recx_list() and vos_ioh2ci(). VOS_OF_FETCH_CSUM and VOS_OF_FETCH_RECX_LIST are mutually exclusive since both write ic_recx_lists with incompatible semantics. An explicit -DER_INVAL check is added in vos_ioc_create() (in addition to the existing D_ASSERT in the hot path). Add unit tests for the new flag: - VOS400.1: Fetch checksum of a single-value record (CRC64). - VOS401.1: Fetch checksums of overlapping array extents (CRC16). Features: recovery Signed-off-by: Cedric Koch-Hofer --- src/include/daos_srv/vos.h | 6 +- src/include/daos_srv/vos_types.h | 2 + src/vos/tests/vts_io.c | 249 +++++++++++++++++++++++++++++++ src/vos/vos_io.c | 43 +++++- 4 files changed, 289 insertions(+), 11 deletions(-) diff --git a/src/include/daos_srv/vos.h b/src/include/daos_srv/vos.h index 730c2e88742..72234757e64 100644 --- a/src/include/daos_srv/vos.h +++ b/src/include/daos_srv/vos.h @@ -1,6 +1,6 @@ /** * (C) Copyright 2015-2024 Intel Corporation. - * (C) Copyright 2025 Hewlett Packard Enterprise Development LP. + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -913,8 +913,8 @@ vos_obj_mark_corruption(daos_handle_t coh, daos_epoch_t epoch, uint32_t pm_ver, * \param[in] nr Number of I/O descriptors in \a ios. * \param[in,out] iods Array of I/O descriptors. The returned record sizes are also restored in * this parameter. - * \param[in] vos_flags VOS fetch flags, VOS cond flags, VOS_OF_FETCH_SIZE_ONLY or - * VOS_OF_FETCH_RECX_LIST. + * \param[in] vos_flags VOS fetch flags, VOS cond flags, VOS_OF_FETCH_SIZE_ONLY, + * VOS_OF_FETCH_RECX_LIST or VOS_OF_FETCH_CSUM. * \param[in] shadows Optional shadow recx/epoch lists, one for each iod. * data of extents covered by these should not be returned * by fetch function. Only used for EC obj degraded fetch. diff --git a/src/include/daos_srv/vos_types.h b/src/include/daos_srv/vos_types.h index 2864aefaf73..696cf7f3945 100644 --- a/src/include/daos_srv/vos_types.h +++ b/src/include/daos_srv/vos_types.h @@ -303,6 +303,8 @@ enum { VOS_OF_EC = (1 << 19), /** Update from rebuild */ VOS_OF_REBUILD = (1 << 20), + /* only query for checksums */ + VOS_OF_FETCH_CSUM = (1 << 21), }; enum { diff --git a/src/vos/tests/vts_io.c b/src/vos/tests/vts_io.c index d64c475f6d0..2414213e2bc 100644 --- a/src/vos/tests/vts_io.c +++ b/src/vos/tests/vts_io.c @@ -3044,6 +3044,253 @@ gang_sv_test(void **state) D_FREE(fetch_buf); } +static void +io_csum_fetch_single(void **state) +{ + const enum DAOS_HASH_TYPE csum_type = HASH_TYPE_CRC64; + const size_t csum_chunk_size = 1u << 12; + + struct io_test_args *arg; + daos_key_t dkey; + daos_key_t akey; + daos_iod_t iod; + d_sg_list_t sgl; + struct daos_recx_ep_list *rel; + struct dcs_ci_list *cil; + struct dcs_csum_info *ci; + struct daos_csummer *csummer; + struct dcs_iod_csums *ic; + struct hash_ft *hf; + char dkey_name[UPDATE_DKEY_SIZE]; + char akey_name[UPDATE_AKEY_SIZE]; + char *update_buf; + const size_t update_buf_size = 2 * csum_chunk_size; + daos_handle_t ioh; + int rc; + + arg = *state; + + /* Allocate update buffer */ + D_ALLOC(update_buf, update_buf_size); + assert_non_null(update_buf); + + /* Set up unique dkey and akey */ + vts_key_gen(&dkey_name[0], arg->dkey_size, true, arg); + set_iov(&dkey, &dkey_name[0], is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64)); + vts_key_gen(&akey_name[0], arg->akey_size, false, arg); + set_iov(&akey, &akey_name[0], is_daos_obj_type_set(arg->otype, DAOS_OT_AKEY_UINT64)); + + iod.iod_type = DAOS_IOD_SINGLE; + iod.iod_size = update_buf_size; + iod.iod_name = akey; + iod.iod_recxs = NULL; + iod.iod_nr = 1; + + /* Fill the buffer with random letters */ + dts_buf_render(&update_buf[0], update_buf_size); + rc = d_sgl_init(&sgl, 1); + if (rc) + goto out; + d_iov_set(sgl.sg_iovs, &update_buf[0], update_buf_size); + + /* Compute update buffer checksum */ + rc = daos_csummer_init_with_type(&csummer, csum_type, csum_chunk_size, 0); + if (rc != 0) + goto out_sgl; + rc = daos_csummer_calc_iods(csummer, &sgl, &iod, NULL, 1, false, NULL, 0, &ic); + if (rc) + goto out_csummer; + + /* Write/Update and update mocking counters */ + rc = vos_obj_update(arg->ctx.tc_co_hdl, arg->oid, 1, 0, 0, &dkey, 1, &iod, ic, &sgl); + if (rc) + goto out_ic; + inc_cntr(arg->ta_flags); + + /* Fetch checksum info */ + iod.iod_size = 0; + rc = vos_fetch_begin(arg->ctx.tc_co_hdl, arg->oid, DAOS_EPOCH_MAX, &dkey, 1, &iod, + VOS_OF_FETCH_CSUM, NULL, &ioh, NULL); + assert_rc_equal(rc, 0); + + /* Check fetched csum info */ + rel = vos_ioh2recx_list(ioh); + assert_null(rel); + cil = vos_ioh2ci(ioh); + assert_non_null(cil); + assert_int_equal(cil->dcl_csum_infos_nr, 1); + ci = dcs_csum_info_get(cil, 0); + assert_true(ci_is_valid(ci)); + assert_int_equal(ci->cs_nr, 1); + hf = daos_mhash_type2algo(ci->cs_type); + assert_int_equal(hf->cf_type, csum_type); + assert_true(daos_csummer_compare_csum_info(csummer, ic->ic_data, ci)); + + /* Cleanup */ + rc = vos_fetch_end(ioh, NULL, rc); + assert_rc_equal(rc, 0); + +out_ic: + daos_csummer_free_ic(csummer, &ic); +out_csummer: + daos_csummer_destroy(&csummer); +out_sgl: + d_sgl_fini(&sgl, false); +out: + D_FREE(update_buf); + assert_rc_equal(rc, 0); +} + +static int +io_csum_update_recx(struct io_test_args *arg, daos_epoch_t epoch, daos_key_t *dkey, + daos_key_t *akey, uint64_t recx_idx, size_t recx_size, + struct daos_csummer *csummer, struct dcs_iod_csums **p_ic) +{ + char *buf; + daos_iod_t iod; + daos_recx_t recx; + d_sg_list_t sgl; + int rc; + + D_ALLOC(buf, recx_size); + if (buf == NULL) { + rc = -DER_NOMEM; + goto out; + } + + recx.rx_idx = recx_idx; + recx.rx_nr = recx_size; + + iod.iod_type = DAOS_IOD_ARRAY; + iod.iod_name = *akey; + iod.iod_recxs = &recx; + iod.iod_size = 1; + iod.iod_nr = 1; + + /* Fill the buffer with random letters */ + dts_buf_render(&buf[0], recx_size); + rc = d_sgl_init(&sgl, 1); + if (rc) + goto out_buf; + d_iov_set(sgl.sg_iovs, &buf[0], recx_size); + + /* Compute update buffer checksum */ + rc = daos_csummer_calc_iods(csummer, &sgl, &iod, NULL, 1, false, NULL, 0, p_ic); + if (rc) + goto out_sgl; + + /* Write/Update and update mocking counters */ + rc = vos_obj_update(arg->ctx.tc_co_hdl, arg->oid, epoch, 0, 0, dkey, 1, &iod, *p_ic, &sgl); + if (rc) + goto out_sgl; + inc_cntr(arg->ta_flags); + +out_sgl: + d_sgl_fini(&sgl, false); +out_buf: + D_FREE(buf); +out: + return rc; +} + +static void +io_csum_fetch_recx(void **state) +{ + const enum DAOS_HASH_TYPE csum_type = HASH_TYPE_CRC16; + const size_t csum_chunk_size = 1u << 6; + + struct io_test_args *arg; + daos_key_t dkey; + daos_key_t akey; + daos_recx_t recx; + daos_iod_t iod; + struct daos_csummer *csummer; + struct dcs_iod_csums *ic[2] = {NULL, NULL}; + struct daos_recx_ep_list *rel; + struct dcs_ci_list *cil; + struct dcs_csum_info *ci; + struct hash_ft *hf; + char dkey_name[UPDATE_DKEY_SIZE]; + char akey_name[UPDATE_AKEY_SIZE]; + daos_handle_t ioh; + int i; + int rc; + + arg = *state; + + /* Set up dkey and akey */ + vts_key_gen(&dkey_name[0], arg->dkey_size, true, arg); + set_iov(&dkey, &dkey_name[0], is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64)); + vts_key_gen(&akey_name[0], arg->akey_size, false, arg); + set_iov(&akey, &akey_name[0], is_daos_obj_type_set(arg->otype, DAOS_OT_AKEY_UINT64)); + + /* Create csumer */ + rc = daos_csummer_init_with_type(&csummer, csum_type, csum_chunk_size, 0); + if (rc != 0) + goto out; + + for (i = 0; i < 2; i++) { + rc = io_csum_update_recx(arg, i + 1, &dkey, &akey, i * csum_chunk_size / 2, + 2 * csum_chunk_size, csummer, &ic[i]); + if (rc) + goto out_csums; + } + + /* Fetch recx and checksums info */ + recx.rx_idx = 0; + recx.rx_nr = 2 * csum_chunk_size; + iod.iod_type = DAOS_IOD_ARRAY; + iod.iod_name = akey; + iod.iod_recxs = &recx; + iod.iod_size = 1; + iod.iod_nr = 1; + rc = vos_fetch_begin(arg->ctx.tc_co_hdl, arg->oid, DAOS_EPOCH_MAX, &dkey, 1, &iod, + VOS_OF_FETCH_CSUM, NULL, &ioh, NULL); + assert_rc_equal(rc, 0); + + /* Check fetched recx info */ + rel = vos_ioh2recx_list(ioh); + assert_non_null(rel); + assert_int_equal(rel->re_nr, 2); + assert_int_equal(rel->re_items[0].re_recx.rx_idx, 0); + assert_int_equal(rel->re_items[0].re_recx.rx_nr, 2 * csum_chunk_size); + assert_int_equal(rel->re_items[0].re_ep, 1); + assert_int_equal(rel->re_items[1].re_recx.rx_idx, csum_chunk_size / 2); + assert_int_equal(rel->re_items[1].re_recx.rx_nr, 2 * csum_chunk_size); + assert_int_equal(rel->re_items[1].re_ep, 2); + + /* Check fetched csum info */ + cil = vos_ioh2ci(ioh); + assert_non_null(cil); + assert_int_equal(cil->dcl_csum_infos_nr, 2); + ci = dcs_csum_info_get(cil, 0); + assert_true(ci_is_valid(ci)); + assert_int_equal(ci->cs_nr, 2); + hf = daos_mhash_type2algo(ci->cs_type); + assert_int_equal(hf->cf_type, csum_type); + assert_true(daos_csummer_compare_csum_info(csummer, ic[0]->ic_data, ci)); + ci = dcs_csum_info_get(cil, 1); + assert_true(ci_is_valid(ci)); + assert_int_equal(ci->cs_nr, 3); + hf = daos_mhash_type2algo(ci->cs_type); + assert_int_equal(hf->cf_type, csum_type); + assert_true(daos_csummer_compare_csum_info(csummer, ic[1]->ic_data, ci)); + + /* Cleanup */ + daos_recx_ep_list_free(rel, iod.iod_nr); + rc = vos_fetch_end(ioh, NULL, rc); + assert_rc_equal(rc, 0); + +out_csums: + for (i = 0; i < 2; i++) { + if (ic[i] != NULL) + daos_csummer_free_ic(csummer, &ic[i]); + } + daos_csummer_destroy(&csummer); +out: + assert_rc_equal(rc, 0); +} + static const struct CMUnitTest iterator_tests[] = { {"VOS220: 100K update/fetch/verify test", io_multiple_dkey, NULL, NULL}, {"VOS240.0: KV Iter tests (for dkey)", io_iter_test, NULL, NULL}, @@ -3080,6 +3327,7 @@ static const struct CMUnitTest io_tests[] = { {"VOS282.2: Accessing pool, container with same UUID", pool_cont_same_uuid, NULL, NULL}, {"VOS299: Space overflow negative error test", io_pool_overflow_test, NULL, io_pool_overflow_teardown}, + {"VOS401.1: Fetch checksum of array value objects", io_csum_fetch_recx, NULL, NULL}, }; static const struct CMUnitTest int_tests[] = { @@ -3090,6 +3338,7 @@ static const struct CMUnitTest int_tests[] = { {"VOS300.2: Key query test", io_query_key, NULL, NULL}, {"VOS300.3: Key query negative test", io_query_key_negative, NULL, NULL}, {"VOS300.4: Gang SV update/fetch test", gang_sv_test, NULL, NULL}, + {"VOS400.1: Fetch checksum of a single value object", io_csum_fetch_single, NULL, NULL}, }; static int diff --git a/src/vos/vos_io.c b/src/vos/vos_io.c index e2bcad16dc3..01f540d59d6 100644 --- a/src/vos/vos_io.c +++ b/src/vos/vos_io.c @@ -79,7 +79,7 @@ struct vos_io_context { ic_dedup : 1, /** candidate for dedup */ ic_dedup_verify : 1, ic_read_ts_only : 1, ic_check_existence : 1, ic_remove : 1, ic_skip_fetch : 1, ic_agg_needed : 1, ic_skip_akey_support : 1, ic_rebuild : 1, - ic_ec : 1; /**< see VOS_OF_EC */ + ic_csum_fetch : 1, ic_ec : 1; /**< see VOS_OF_EC */ /** * Input shadow recx lists, one for each iod. Now only used for degraded * mode EC obj fetch handling. @@ -712,6 +712,15 @@ vos_ioc_create(daos_handle_t coh, daos_unit_oid_t oid, bool read_only, ioc->ic_remove = ((vos_flags & VOS_OF_REMOVE) != 0); ioc->ic_ec = ((vos_flags & VOS_OF_EC) != 0); ioc->ic_rebuild = ((vos_flags & VOS_OF_REBUILD) != 0); + ioc->ic_csum_fetch = ((vos_flags & VOS_OF_FETCH_CSUM) != 0); + /* VOS_OF_FETCH_CSUM and VOS_OF_FETCH_RECX_LIST both write ic_recx_lists + * with incompatible semantics (full stored extent vs. selected range) and + * must not be combined. + */ + if (ioc->ic_csum_fetch && ioc->ic_save_recx) { + D_ERROR("VOS_OF_FETCH_CSUM and VOS_OF_FETCH_RECX_LIST are mutually exclusive\n"); + D_GOTO(error, rc = -DER_INVAL); + } ioc->ic_umoffs_cnt = 0; ioc->ic_iod_csums = iod_csums; vos_ilog_fetch_init(&ioc->ic_dkey_info); @@ -791,7 +800,7 @@ vos_ioc_create(daos_handle_t coh, daos_unit_oid_t oid, bool read_only, } /* Don't bother to initialize SGLs for size fetch */ - if (ioc->ic_size_fetch) + if (ioc->ic_size_fetch || ioc->ic_csum_fetch) continue; bsgl = bio_iod_sgl(ioc->ic_biod, i); @@ -814,7 +823,7 @@ iod_fetch(struct vos_io_context *ioc, struct bio_iov *biov) struct bio_sglist *bsgl; int iov_nr, iov_at; - if (ioc->ic_size_fetch) + if (ioc->ic_size_fetch || ioc->ic_csum_fetch) return 0; bsgl = bio_iod_sgl(ioc->ic_biod, ioc->ic_sgl_at); @@ -868,7 +877,7 @@ iod_gang_fetch(struct vos_io_context *ioc, struct bio_iov *biov) uint32_t data_len; int i, rc = 0; - if (ioc->ic_size_fetch) + if (ioc->ic_size_fetch || ioc->ic_csum_fetch) return 0; if (biov->bi_addr.ba_gang_nr < 2) { @@ -957,6 +966,8 @@ akey_fetch_single(daos_handle_t toh, const daos_epoch_range_t *epr, if (ci_is_valid(&csum_info)) save_csum(ioc, &csum_info, NULL, 0); + if (ioc->ic_csum_fetch) + goto out; /* iod_size not updated on csum-only fetch; caller must not rely on it */ if (BIO_ADDR_IS_CORRUPTED(&rbund.rb_biov->bi_addr)) { D_DEBUG(DB_CSUM, "Found corrupted record\n"); @@ -1159,6 +1170,7 @@ akey_fetch_recx(daos_handle_t toh, const daos_epoch_range_t *epr, D_ASSERT(rsize == inob); if (ioc->ic_save_recx) { + D_ASSERT(!ioc->ic_csum_fetch); rc = save_recx(ioc, lo, nr, ent->en_epoch, inob, DRT_NORMAL); if (rc != 0) @@ -1179,9 +1191,24 @@ akey_fetch_recx(daos_handle_t toh, const daos_epoch_range_t *epr, "but not all\n"); } - rc = iod_fetch(ioc, &biov); - if (rc != 0) - goto failed; + if (ioc->ic_csum_fetch && csum_enabled) { + daos_off_t ex_lo; + daos_size_t ex_nr; + + D_ASSERT(!ioc->ic_save_recx); + D_ASSERT(!with_shadow); + D_ASSERT(ioc->ic_iod_nr == 1); + + ex_lo = ent->en_ext.ex_lo; + ex_nr = ent->en_ext.ex_hi - ex_lo + 1; + rc = save_recx(ioc, ex_lo, ex_nr, ent->en_epoch, inob, DRT_NORMAL); + if (rc != 0) + goto failed; + } else { + rc = iod_fetch(ioc, &biov); + if (rc != 0) + goto failed; + } index = lo + nr; } @@ -1218,7 +1245,7 @@ ioc_trim_tail_holes(struct vos_io_context *ioc) struct bio_iov *biov; int i; - if (ioc->ic_size_fetch) + if (ioc->ic_size_fetch || ioc->ic_csum_fetch) return; bsgl = bio_iod_sgl(ioc->ic_biod, ioc->ic_sgl_at);