From 824e7f7170027255f8002a5d8d0d0f5ba5753a47 Mon Sep 17 00:00:00 2001 From: Phil Henderson Date: Fri, 19 Sep 2025 15:09:39 -0400 Subject: [PATCH 01/12] DASO-17577 test: Skip certain functional test stages by default (#16872) Avoid utilizing excessive CI resources usage while manually starting CI jobs by disabling functional test stages that are normally skipped when running PRs. Signed-off-by: Phil Henderson --- Jenkinsfile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index d75c00fb12d..5a14017c50d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -289,10 +289,10 @@ pipeline { defaultValue: true, description: 'Run the Functional on EL 8 test stage') booleanParam(name: 'CI_FUNCTIONAL_el9_TEST', - defaultValue: true, + defaultValue: false, description: 'Run the Functional on EL 9 test stage') booleanParam(name: 'CI_FUNCTIONAL_leap15_TEST', - defaultValue: true, + defaultValue: false, description: 'Run the Functional on Leap 15 test stage' + ' Requires CI_MORE_FUNCTIONAL_PR_TESTS') booleanParam(name: 'CI_FUNCTIONAL_ubuntu20_TEST', @@ -306,25 +306,25 @@ pipeline { defaultValue: true, description: 'Run the Functional Hardware Medium test stage') booleanParam(name: 'CI_medium_md_on_ssd_TEST', - defaultValue: true, + defaultValue: false, description: 'Run the Functional Hardware Medium MD on SSD test stage') booleanParam(name: 'CI_medium_vmd_TEST', - defaultValue: true, + defaultValue: false, description: 'Run the Functional Hardware Medium VMD test stage') booleanParam(name: 'CI_medium_verbs_provider_TEST', defaultValue: true, description: 'Run the Functional Hardware Medium Verbs Provider test stage') booleanParam(name: 'CI_medium_verbs_provider_md_on_ssd_TEST', - defaultValue: true, + defaultValue: false, description: 'Run the Functional Hardware Medium Verbs Provider MD on SSD test stage') booleanParam(name: 'CI_medium_ucx_provider_TEST', - defaultValue: true, + defaultValue: false, description: 'Run the Functional Hardware Medium UCX Provider test stage') booleanParam(name: 'CI_large_TEST', defaultValue: true, description: 'Run the Functional Hardware Large test stage') booleanParam(name: 'CI_large_md_on_ssd_TEST', - defaultValue: true, + defaultValue: false, description: 'Run the Functional Hardware Large MD on SSD test stage') string(name: 'CI_UNIT_VM1_LABEL', defaultValue: 'ci_vm1', From c4c431926cf8b3a61a00b9d2879e67f1640aece5 Mon Sep 17 00:00:00 2001 From: Mohamad Chaarawi Date: Tue, 23 Sep 2025 09:41:30 -0500 Subject: [PATCH 02/12] DAOS-17325 object: use EC_xP3 for auto oclass selection (#16800) (#16865) Since we support EC for RF3 now, we should utilize the object class in the auto selection for files / objects. Signed-off-by: Mohamad Chaarawi --- src/object/obj_class.c | 19 ++++++++++-- src/tests/suite/dfs_unit_test.c | 52 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/object/obj_class.c b/src/object/obj_class.c index f37ff1e6ee7..654a316efe0 100644 --- a/src/object/obj_class.c +++ b/src/object/obj_class.c @@ -812,9 +812,22 @@ dc_set_oclass(uint32_t rf, int domain_nr, int target_nr, enum daos_otype_t otype } break; case DAOS_PROP_CO_REDUN_RF3: - /** EC not supported here */ - *ord = OR_RP_4; - grp_size = 4; + if ((rdd == DAOS_OCH_RDD_EC || (rdd == 0 && daos_is_array_type(otype))) && + domain_nr >= 10) { + if (domain_nr >= 22) { + *ord = OR_RS_16P3; + grp_size = 19; + } else if (domain_nr >= 14) { + *ord = OR_RS_8P3; + grp_size = 11; + } else { + *ord = OR_RS_4P3; + grp_size = 7; + } + } else { + *ord = OR_RP_4; + grp_size = 4; + } break; case DAOS_PROP_CO_REDUN_RF4: /** EC not supported here */ diff --git a/src/tests/suite/dfs_unit_test.c b/src/tests/suite/dfs_unit_test.c index 84c77453e88..cb2ad322f89 100644 --- a/src/tests/suite/dfs_unit_test.c +++ b/src/tests/suite/dfs_unit_test.c @@ -2475,6 +2475,58 @@ dfs_test_oclass_hints(void **state) rc = daos_cont_destroy(arg->pool.poh, "oc_cont2", 0, NULL); assert_success(rc); + /** create container with RF = 3 */ + print_message("DFS object class hints with container RF3:\n"); + prop->dpp_entries[0].dpe_type = DAOS_PROP_CO_REDUN_FAC; + prop->dpp_entries[0].dpe_val = DAOS_PROP_CO_REDUN_RF3; + rc = dfs_cont_create_with_label(arg->pool.poh, "oc_cont3", &dattr, NULL, &coh, &dfs_l); + assert_int_equal(rc, 0); + + /** set the expect EC object class ID based on domain nr */ + if (attr.pa_domain_nr >= 22) + ecidx = OC_EC_16P3GX; + else if (attr.pa_domain_nr >= 14) + ecidx = OC_EC_8P3GX; + else if (attr.pa_domain_nr >= 10) + ecidx = OC_EC_4P3GX; + else + ecidx = OC_RP_4GX; + + rc = dfs_suggest_oclass(dfs_l, "file:single", &cid); + assert_int_equal(rc, 0); + daos_oclass_id2name(cid, oclass_name); + print_message("oclass suggested for \"file:single\" = %s\n", oclass_name); + rc = compare_oclass(coh, cid, OC_RP_4G1); + assert_rc_equal(rc, 0); + + rc = dfs_suggest_oclass(dfs_l, "File:max", &cid); + assert_int_equal(rc, 0); + daos_oclass_id2name(cid, oclass_name); + print_message("oclass suggested for \"File:max\" = %s\n", oclass_name); + rc = compare_oclass(coh, cid, ecidx); + assert_rc_equal(rc, 0); + + rc = dfs_suggest_oclass(dfs_l, "dir:single", &cid); + assert_int_equal(rc, 0); + daos_oclass_id2name(cid, oclass_name); + print_message("oclass suggested for \"dir:single\" = %s\n", oclass_name); + rc = compare_oclass(coh, cid, OC_RP_4G1); + assert_rc_equal(rc, 0); + + rc = dfs_suggest_oclass(dfs_l, "Directory:max", &cid); + assert_int_equal(rc, 0); + daos_oclass_id2name(cid, oclass_name); + print_message("oclass suggested for \"Directory:max\" = %s\n", oclass_name); + rc = compare_oclass(coh, cid, OC_RP_4GX); + assert_rc_equal(rc, 0); + + rc = dfs_umount(dfs_l); + assert_int_equal(rc, 0); + rc = daos_cont_close(coh, NULL); + assert_success(rc); + rc = daos_cont_destroy(arg->pool.poh, "oc_cont3", 0, NULL); + assert_success(rc); + daos_prop_free(prop); } From a61eb70a330adfe220408395e3caa6e5dd36e3e5 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Wed, 24 Sep 2025 11:18:03 +0800 Subject: [PATCH 03/12] DAOS-17948 object: fix bugs for sgl duplicate logic (#16796) * DAOS-17948 object: fix bugs for sgl duplicate logic 1. When IO retries occur, a use-after-free scenario may arise during scatter-gather list (sgl) merging. This happens because retried I/O's sgl references dup_sgls, which could be prematurely freed in obj_reasb_io_fini(). To fix above issue, processed_sgls must not be freed during retry operations and should be called only once per I/O operation. 2. If both short reads and duplicated SGLs occur, the iov_len of the original SGLs must be updated properly to ensure the correct number of read data bytes is returned. 3. Since only fetched data bytes are copied back, it is unnecessary to copy the original buffer to the merged buffer before fetching. 4. A test case has been added to verify that short reads function as expected during SGL merging. Signed-off-by: Wang Shilong --- src/object/cli_obj.c | 36 +++++++-------- src/tests/suite/daos_obj_array.c | 78 ++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 18 deletions(-) diff --git a/src/object/cli_obj.c b/src/object/cli_obj.c index 3f0f2f196e5..2a4d6e89313 100644 --- a/src/object/cli_obj.c +++ b/src/object/cli_obj.c @@ -4907,49 +4907,48 @@ obj_dup_sgls_free(struct obj_auxi_args *obj_auxi) d_sg_list_t *sg_orig = &ctx->sgls_orig[i]; uint32_t dup_sg_idx = 0; uint32_t dup_buf_size = 0; - uint32_t sg_nr_out = 0; + uint32_t dup_data_len = 0; char *dup_buf; if (!ctx->alloc_bitmaps || !ctx->alloc_bitmaps[i]) continue; D_ASSERT(ctx->merged_bitmaps[i] != NULL); - for (j = 0; j < sg_orig->sg_nr && dup_sg_idx < sg_dup->sg_nr_out;) { + for (j = 0; j < sg_orig->sg_nr && dup_sg_idx < sg_dup->sg_nr_out; j++) { iov = &sg_orig->sg_iovs[j]; iov_dup = &sg_dup->sg_iovs[dup_sg_idx]; - if (skip_sgl_iov(false, iov)) { - j++; + if (skip_sgl_iov(false, iov)) continue; - } /* Direct copy if entry wasn't modified */ if (!isset_range((uint8_t *)ctx->merged_bitmaps[i], j, j)) { *iov = *iov_dup; - D_ASSERT(dup_buf_size == 0); - j++; - sg_nr_out++; + D_ASSERT(dup_data_len == 0); dup_sg_idx++; continue; } - if (dup_buf_size == 0) { + if (dup_data_len == 0) { + dup_data_len = iov_dup->iov_len; dup_buf_size = iov_dup->iov_buf_len; dup_buf = (char *)iov_dup->iov_buf; } + /* Update iov_len for short read */ + if (dup_data_len < iov->iov_len) + iov->iov_len = dup_data_len; /* Copy data from duplicate buffer to original buffer */ - D_ASSERT(dup_buf_size >= iov->iov_buf_len); - memcpy((char *)iov->iov_buf, dup_buf, iov->iov_buf_len); - dup_buf_size -= iov->iov_buf_len; - dup_buf += iov->iov_buf_len; - sg_nr_out++; - j++; + D_ASSERT(dup_buf_size >= iov->iov_len); + memcpy((char *)iov->iov_buf, dup_buf, iov->iov_len); + dup_data_len -= iov->iov_len; + dup_buf += iov->iov_len; + dup_buf_size -= iov->iov_len; /* When current duplicate buffer is exhausted, get next entry */ - if (dup_buf_size == 0) + if (dup_data_len == 0) dup_sg_idx++; } - sg_orig->sg_nr_out = sg_nr_out; + sg_orig->sg_nr_out = j; } } @@ -4974,7 +4973,8 @@ obj_reasb_io_fini(struct obj_auxi_args *obj_auxi, bool retry) } obj_bulk_fini(obj_auxi); obj_auxi_free_failed_tgt_list(obj_auxi); - obj_dup_sgls_free(obj_auxi); + if (!retry) + obj_dup_sgls_free(obj_auxi); obj_reasb_req_fini(&obj_auxi->reasb_req, obj_auxi->iod_nr); obj_auxi->req_reasbed = false; diff --git a/src/tests/suite/daos_obj_array.c b/src/tests/suite/daos_obj_array.c index 00742f54991..858b70e6ff2 100644 --- a/src/tests/suite/daos_obj_array.c +++ b/src/tests/suite/daos_obj_array.c @@ -1729,6 +1729,83 @@ array_recx_write_mixed_iov_read_single(void **state) daos_obj_close(oh, NULL); } +#define ONE_KB (1024) +#define TWO_MB (2 * 1024 * 1024) + +void +test_sgl_merge_short_read(void **state) +{ + test_arg_t *arg = *state; + daos_obj_id_t oid; + daos_handle_t oh; + d_iov_t dkey; + d_sg_list_t sgl; + daos_iod_t iod; + daos_recx_t recx; + char *wbuf, *rbuf; + d_iov_t *sg_iovs = NULL; + int total_iovs = TWO_MB / ONE_KB; + int data_offset = 0; + int rc, i; + + oid = daos_test_oid_gen(arg->coh, OC_SX, 0, 0, arg->myrank); + rc = daos_obj_open(arg->coh, oid, DAOS_OO_RW, &oh, NULL); + assert_rc_equal(rc, 0); + + /* Buffer allocation with guard pages */ + wbuf = malloc(ONE_MB); + assert_true(wbuf != NULL); + dts_buf_render(wbuf, ONE_MB); + + /* Allocate 2MB read buffer with guard pages */ + rbuf = calloc(1, TWO_MB + FOUR_KB); + assert_true(rbuf != NULL); + + /* Build scatter-gather list for 1KB chunks */ + sg_iovs = calloc(total_iovs, sizeof(d_iov_t)); + assert_true(sg_iovs != NULL); + + /* 1MB data read in 1KB chunks */ + for (i = 0; i < total_iovs; i++) { + d_iov_set(&sg_iovs[data_offset], rbuf + i * ONE_KB, ONE_KB); + data_offset++; + } + + /* Configure scatter-gather list */ + sgl = (d_sg_list_t){.sg_nr = total_iovs, .sg_nr_out = 0, .sg_iovs = sg_iovs}; + + /* Prepare I/O descriptor */ + d_iov_set(&dkey, "short_key", 9); + d_iov_set(&iod.iod_name, "big_akey", 8); + iod.iod_nr = 1; + iod.iod_size = 1; + iod.iod_type = DAOS_IOD_ARRAY; + iod.iod_recxs = &recx; + recx.rx_idx = 0; + recx.rx_nr = ONE_MB - 4; + + /* Write initial data with single IOV */ + d_sg_list_t write_sgl = { + .sg_nr = 1, + .sg_iovs = &(d_iov_t){.iov_buf = wbuf, .iov_len = ONE_MB - 4, .iov_buf_len = ONE_MB}}; + rc = daos_obj_update(oh, DAOS_TX_NONE, 0, &dkey, 1, &iod, &write_sgl, NULL); + assert_rc_equal(rc, 0); + + /* Read back using 1KB chunks */ + rc = daos_obj_fetch(oh, DAOS_TX_NONE, 0, &dkey, 1, &iod, &sgl, NULL, NULL); + assert_rc_equal(rc, 0); + assert_rc_equal(sgl.sg_nr_out, 1024); + assert_rc_equal(sg_iovs[1023].iov_len, 1020); + + /* Verify only 1MB - 4 was read successfully */ + assert_memory_equal(wbuf, rbuf, ONE_MB - 4); + + free(wbuf); + free(rbuf); + free(sg_iovs); + daos_obj_close(oh, NULL); +} + static const struct CMUnitTest array_tests[] = { {"ARRAY0: small_sgl", small_sgl, NULL, test_case_teardown}, {"ARRAY1: byte array with buffer on stack", byte_array_simple_stack, NULL, test_case_teardown}, @@ -1759,6 +1836,7 @@ static const struct CMUnitTest array_tests[] = { {"ARRAY20: recx read mixed iov", array_recx_read_mixed_iov, NULL, test_case_teardown}, {"ARRAY21: recx write mixed iov", array_recx_write_mixed_iov_read_single, NULL, test_case_teardown}, + {"ARRAY22: recx short read", test_sgl_merge_short_read, NULL, test_case_teardown}, }; static int From d2babd1e00ac1ad760af26bc0860b30694d06d88 Mon Sep 17 00:00:00 2001 From: Nasf-Fan Date: Thu, 25 Sep 2025 11:44:55 +0800 Subject: [PATCH 04/12] DAOS-17979 object: fixes for EC object consistency verification - b26 (#16851) Mainly include the following: 1. The old implementation sets dc_obj_verify_args::current_shard as the shard in the first EC redundancy group. It causes that we always verify the first EC redundancy group without others. That is wrong. We need to combine it with the group index. 2. New DIOF_EC_NO_DEGRADE flag for dc_obj_fetch task to guarantee reading data from the specified data shard. Otherwise, related read request maybe automatically converted as degraded reading from parity shard. 3. Replace DAOS_OBJ_FORCE_DEGRADE fail_loc as OBJ fetch API flag DIOF_FOR_FORCE_DEGRADE for EC verification logic. Then if the degraded fetch RPC is retried for some reason, the retry task will also be degraded fetch. That will avoid self-comparing. 4. Cleanup d_sg_list_t::sg_nr_out parameter for OBJ fetch task in object consistency verification logic. 5. For rebuild related test cases, if need to verify parity shard, then set fail_loc as DAOS_OBJ_FORCE_DEGRADE | DAOS_FAIL_ALWAYS, That will handle RPC retry cases properly. Signed-off-by: Fan Yong --- src/include/daos/object.h | 2 ++ src/object/cli_obj.c | 6 ++++ src/object/obj_verify.c | 50 ++++++++++++++------------- src/tests/suite/daos_rebuild_common.c | 22 ++++++++---- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/src/include/daos/object.h b/src/include/daos/object.h index feb59d24d0c..bdd7abb2cc7 100644 --- a/src/include/daos/object.h +++ b/src/include/daos/object.h @@ -653,6 +653,8 @@ enum daos_io_flags { DIOF_RECX_REVERSE = 0x800, /* Use for rebuild fetch epoch selection */ DIOF_FETCH_EPOCH_EC_AGG_BOUNDARY = 0x1000, + /* Do not degrade enumeration/fetch if data shard failed */ + DIOF_EC_NO_DEGRADE = 0x2000, }; /** diff --git a/src/object/cli_obj.c b/src/object/cli_obj.c index 2a4d6e89313..75089cb1ae1 100644 --- a/src/object/cli_obj.c +++ b/src/object/cli_obj.c @@ -5743,6 +5743,12 @@ obj_ec_fetch_shards_get(struct dc_object *obj, daos_obj_fetch_t *args, unsigned if (likely(ec_deg_tgt == tgt_idx)) continue; + if (args->extra_flags & DIOF_EC_NO_DEGRADE) { + D_WARN(DF_OID "have to degraded fetch for %u => %u, but sponsor forbid.\n", + DP_OID(obj->cob_md.omd_id), tgt_idx, ec_deg_tgt); + D_GOTO(out, rc = -DER_IO); + } + if (obj_auxi->ec_in_recov) { D_DEBUG(DB_IO, DF_OID " shard %d failed recovery.\n", DP_OID(obj->cob_md.omd_id), grp_start + tgt_idx); diff --git a/src/object/obj_verify.c b/src/object/obj_verify.c index beffd5744ab..46df0b6c93d 100644 --- a/src/object/obj_verify.c +++ b/src/object/obj_verify.c @@ -1,5 +1,6 @@ /** * (C) Copyright 2019-2023 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -31,9 +32,9 @@ dc_obj_verify_list(struct dc_obj_verify_args *dova) memset(dova->kds, 0, sizeof(daos_key_desc_t) * DOVA_NUM); memset(dova->list_buf, 0, dova->list_buf_len); - dova->list_sgl.sg_nr = 1; - dova->list_sgl.sg_nr_out = 1; - dova->list_sgl.sg_iovs = &dova->list_iov; + dova->list_sgl.sg_nr = 1; + dova->list_sgl.sg_nr_out = 0; + dova->list_sgl.sg_iovs = &dova->list_iov; dova->size = 0; dova->num = DOVA_NUM; @@ -113,9 +114,9 @@ dc_obj_verify_fetch(struct dc_obj_verify_args *dova) dova->fetch_iov.iov_buf = dova->fetch_buf; dova->fetch_iov.iov_buf_len = dova->fetch_buf_len; - dova->fetch_sgl.sg_nr = 1; - dova->fetch_sgl.sg_nr_out = 1; - dova->fetch_sgl.sg_iovs = &dova->fetch_iov; + dova->fetch_sgl.sg_nr = 1; + dova->fetch_sgl.sg_nr_out = 0; + dova->fetch_sgl.sg_iovs = &dova->fetch_iov; shard = dc_obj_anchor2shard(&dova->dkey_anchor); rc = dc_obj_fetch_task_create(dova->oh, dova->th, 0, &cursor->dkey, 1, @@ -677,18 +678,18 @@ dc_obj_verify_ec_cb(struct dc_obj_enum_unpack_io *io, void *arg) D_GOTO(out, rc = -DER_NOMEM); d_iov_set(&iovs[idx], data, size); - sgls[idx].sg_nr = 1; - sgls[idx].sg_nr_out = 1; - sgls[idx].sg_iovs = &iovs[idx]; + sgls[idx].sg_nr = 1; + sgls[idx].sg_nr_out = 0; + sgls[idx].sg_iovs = &iovs[idx]; D_ALLOC(data_verify, size); if (data_verify == NULL) D_GOTO(out, rc = -DER_NOMEM); d_iov_set(&iovs_verify[idx], data_verify, size); - sgls_verify[idx].sg_nr = 1; - sgls_verify[idx].sg_nr_out = 1; - sgls_verify[idx].sg_iovs = &iovs_verify[idx]; + sgls_verify[idx].sg_nr = 1; + sgls_verify[idx].sg_nr_out = 0; + sgls_verify[idx].sg_iovs = &iovs_verify[idx]; if (iod->iod_type == DAOS_IOD_ARRAY) { rc = obj_recx_ec2_daos(obj_get_oca(obj), tgt_off, &iod->iod_recxs, NULL, &iod->iod_nr, true); @@ -705,10 +706,13 @@ dc_obj_verify_ec_cb(struct dc_obj_enum_unpack_io *io, void *arg) return 0; } - /* Fetch by specific shard */ - rc = dc_obj_fetch_task_create(dova->oh, dova->th, 0, &io->ui_dkey, idx, - 0, iods, sgls, NULL, &shard, NULL, NULL, NULL, - &task); + /* + * NOTE: Fetch data from data shard (including current one). The EC fetch task may touch + * multiple data shards. That is no matter as long as it does not trigger degraded + * fetch. Using DIOF_EC_NO_DEGRADE flag for such purpose. + */ + rc = dc_obj_fetch_task_create(dova->oh, dova->th, 0, &io->ui_dkey, idx, DIOF_EC_NO_DEGRADE, + iods, sgls, NULL, &shard, NULL, NULL, NULL, &task); if (rc != 0) { D_ERROR(DF_OID" sgl num %u shard "DF_U64"\n", DP_OID(obj->cob_md.omd_id), idx, shard); @@ -731,10 +735,9 @@ dc_obj_verify_ec_cb(struct dc_obj_enum_unpack_io *io, void *arg) D_GOTO(out, rc); } - daos_fail_loc_set(DAOS_OBJ_FORCE_DEGRADE | DAOS_FAIL_ONCE); rc = dc_obj_fetch_task_create(dova->oh, dova->th, 0, &io->ui_dkey, idx, - 0, iods, sgls_verify, NULL, &shard, NULL, NULL, - NULL, &verify_task); + DIOF_FOR_FORCE_DEGRADE, iods, sgls_verify, NULL, &shard, NULL, + NULL, NULL, &verify_task); if (rc != 0) { D_ERROR(DF_OID" sgl num %u shard "DF_U64"\n", DP_OID(obj->cob_md.omd_id), idx, shard); @@ -756,7 +759,6 @@ dc_obj_verify_ec_cb(struct dc_obj_enum_unpack_io *io, void *arg) io->ui_iods[i].iod_size, DP_RC(rc)); D_GOTO(out, rc); } - daos_fail_loc_set(0); for (i = 0; i < idx; i++) { if (sgls[i].sg_iovs[0].iov_len != sgls_verify[i].sg_iovs[0].iov_len || @@ -810,10 +812,10 @@ dc_obj_verify_ec_rdg(struct dc_object *obj, struct dc_obj_verify_args *dova, dc_obj_shard2anchor(&dova->dkey_anchor, start + i); daos_anchor_set_flags(&dova->dkey_anchor, DIOF_TO_SPEC_SHARD | DIOF_WITH_SPEC_EPOCH); - dova->th = th; - dova->eof = 0; - dova->non_exist = 0; - dova->current_shard = i; + dova->th = th; + dova->eof = 0; + dova->non_exist = 0; + dova->current_shard = start + i; memset(cursor, 0, sizeof(*cursor)); cursor->iod.iod_nr = 1; cursor->iod.iod_recxs = &cursor->recx; diff --git a/src/tests/suite/daos_rebuild_common.c b/src/tests/suite/daos_rebuild_common.c index 799b52fede8..18017191280 100644 --- a/src/tests/suite/daos_rebuild_common.c +++ b/src/tests/suite/daos_rebuild_common.c @@ -1,5 +1,6 @@ /** * (C) Copyright 2016-2023 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -624,19 +625,24 @@ void make_buffer(char *buffer, char start, int total) static void write_ec(struct ioreq *req, int index, char *data, daos_off_t off, int size) { - char key[32]; - daos_recx_t recx; - int i; - char single_data[LARGE_SINGLE_VALUE_SIZE]; + char key[32]; + daos_recx_t recx; + int small_size = 5; + int i; + char *single_data; + + assert_true(small_size <= size); + + D_ALLOC(single_data, LARGE_SINGLE_VALUE_SIZE); + assert_non_null(single_data); for (i = 0; i < KEY_NR; i++) { req->iod_type = DAOS_IOD_ARRAY; sprintf(key, "dkey_small_%d", index); - recx.rx_nr = 5; + recx.rx_nr = small_size; recx.rx_idx = off + i * 10485760; - insert_recxs(key, "a_key", 1, DAOS_TX_NONE, &recx, 1, - data, size, req); + insert_recxs(key, "a_key", 1, DAOS_TX_NONE, &recx, 1, data, small_size, req); sprintf(key, "dkey_%d", index); recx.rx_nr = size; @@ -658,6 +664,8 @@ write_ec(struct ioreq *req, int index, char *data, daos_off_t off, int size) insert_single(key, "a_key", 0, single_data, LARGE_SINGLE_VALUE_SIZE, DAOS_TX_NONE, req); } + + D_FREE(single_data); } static void From ee13dff34c7c2e7ff7617809fe560440ec8a1dec Mon Sep 17 00:00:00 2001 From: Liang Zhen Date: Thu, 25 Sep 2025 12:10:03 +0800 Subject: [PATCH 05/12] DAOS-17843 placement: correct the way JCH placement calls CRC (#16695) * DAOS-17843 placement: correct the way JCH placement calls CRC The Jump Consistent Hash (JCH) placement algorithm in DAOS calls the CRC functions incorrectly, which may lead to excessive hash collisions and imbalanced data distribution. This patch corrects how the JCH placement algorithm invokes the CRC functions. Signed-off-by: Zhen Liang Signed-off-by: Wang Shilong --- src/container/cli.c | 12 +- src/container/srv_container.c | 28 ++- src/include/daos/pool.h | 11 ++ src/include/daos_cont.h | 10 +- src/include/daos_srv/pool.h | 6 - src/pipeline/cli_pipeline.c | 11 +- src/placement/jump_map.c | 37 ++-- src/placement/jump_map.h | 19 ++ src/placement/jump_map_versions.c | 242 +++++++++++++++++++++-- src/placement/tests/jump_map_place_obj.c | 12 +- src/placement/tests/place_obj_common.h | 3 +- src/pool/srv_layout.c | 3 +- src/pool/srv_pool.c | 11 +- 13 files changed, 345 insertions(+), 60 deletions(-) diff --git a/src/container/cli.c b/src/container/cli.c index a0dc96fec00..18b6a75a590 100644 --- a/src/container/cli.c +++ b/src/container/cli.c @@ -190,6 +190,7 @@ dup_cont_create_props(daos_handle_t poh, daos_prop_t **prop_out, int rc = 0; uid_t uid = geteuid(); gid_t gid = getegid(); + uint32_t co_ver = 0; entries = (prop_in == NULL) ? 0 : prop_in->dpp_nr; @@ -224,6 +225,10 @@ dup_cont_create_props(daos_handle_t poh, daos_prop_t **prop_out, entries++; } + if (!daos_prop_has_entry(prop_in, DAOS_PROP_CO_OBJ_VERSION)) { + co_ver = DAOS_POOL_OBJ_VERSION_2; + entries++; + } if (!daos_prop_has_entry(prop_in, DAOS_PROP_CO_ROOTS)) { uint64_t rf; @@ -294,6 +299,11 @@ dup_cont_create_props(daos_handle_t poh, daos_prop_t **prop_out, roots = NULL; /* prop is responsible for it now */ idx++; } + if (co_ver != 0) { + final_prop->dpp_entries[idx].dpe_type = DAOS_PROP_CO_OBJ_VERSION; + final_prop->dpp_entries[idx].dpe_val = co_ver; + idx++; + } } *prop_out = final_prop; @@ -999,7 +1009,7 @@ dc_cont_open(tse_task_t *task) if (tpriv->cont == NULL) D_GOTO(err_pool, rc = -DER_NOMEM); uuid_generate(tpriv->cont->dc_cont_hdl); - tpriv->cont->dc_capas = args->flags; + tpriv->cont->dc_capas = args->flags | DAOS_COO_NEW_LAYOUT; } D_DEBUG(DB_MD, DF_UUID ":%s: opening: hdl=" DF_UUIDF " flags=%x\n", DP_UUID(pool->dp_pool), diff --git a/src/container/srv_container.c b/src/container/srv_container.c index 5dc44e2758d..7f15a275b5d 100644 --- a/src/container/srv_container.c +++ b/src/container/srv_container.c @@ -702,10 +702,12 @@ cont_create_prop_prepare(struct ds_pool_hdl *pool_hdl, } break; case DAOS_PROP_CO_GLOBAL_VERSION: - case DAOS_PROP_CO_OBJ_VERSION: - D_ERROR("container global/obj %u version could be not set\n", - entry->dpe_type); + D_ERROR("container global %u version could be not set\n", entry->dpe_type); return -DER_INVAL; + case DAOS_PROP_CO_OBJ_VERSION: + /* this is a walkaround for 2.6 only */ + entry_def->dpe_val = entry->dpe_val; + break; default: D_ASSERTF(0, "bad dpt_type %d.\n", entry->dpe_type); break; @@ -760,8 +762,9 @@ cont_create_prop_prepare(struct ds_pool_hdl *pool_hdl, /* inherit object version from pool*/ entry_def = daos_prop_entry_get(prop_def, DAOS_PROP_CO_OBJ_VERSION); - if (entry_def) + if (entry_def && entry_def->dpe_val == 0) entry_def->dpe_val = pool_hdl->sph_obj_ver; + /* for new container set HEALTHY status with current pm ver */ entry_def = daos_prop_entry_get(prop_def, DAOS_PROP_CO_STATUS); D_ASSERT(entry_def != NULL); @@ -2272,6 +2275,17 @@ cont_open(struct rdb_tx *tx, struct ds_pool_hdl *pool_hdl, struct cont *cont, cr D_GOTO(out, rc); D_ASSERT(prop != NULL); D_ASSERT(prop->dpp_nr <= CONT_PROP_NUM); + if (!(flags & DAOS_COO_NEW_LAYOUT)) { + struct daos_prop_entry *entry; + + entry = daos_prop_entry_get(prop, DAOS_PROP_CO_OBJ_VERSION); + if (entry && entry->dpe_val >= DAOS_POOL_OBJ_VERSION_2) { + D_ERROR(DF_CONT ": refusing attempt to open with new layout: " DF_X64 "\n", + DP_CONT(cont->c_svc->cs_pool_uuid, cont->c_uuid), entry->dpe_val); + rc = -DER_NOTSUPPORTED; + D_GOTO(out, rc); + } + } get_cont_prop_access_info(prop, &owner, &acl); @@ -4612,7 +4626,7 @@ upgrade_cont_cb(daos_handle_t ih, d_iov_t *key, d_iov_t *val, void *varg) } if (DAOS_FAIL_CHECK(DAOS_FORCE_OBJ_UPGRADE)) { - obj_ver = DS_POOL_OBJ_VERSION; + obj_ver = DAOS_POOL_OBJ_VERSION; d_iov_set(&value, &obj_ver, sizeof(obj_ver)); rc = rdb_tx_update(ap->tx, &cont->c_prop, &ds_cont_prop_cont_obj_version, &value); @@ -4707,9 +4721,9 @@ upgrade_cont_cb(daos_handle_t ih, d_iov_t *key, d_iov_t *val, void *varg) entry = daos_prop_entry_get(prop, DAOS_PROP_CO_OBJ_VERSION); D_ASSERT(entry != NULL); - entry->dpe_val = DS_POOL_OBJ_VERSION; + entry->dpe_val = DAOS_POOL_OBJ_VERSION; entry->dpe_flags &= ~DAOS_PROP_ENTRY_NOT_SET; - obj_ver = DS_POOL_OBJ_VERSION; + obj_ver = DAOS_POOL_OBJ_VERSION; d_iov_set(&value, &obj_ver, sizeof(obj_ver)); rc = rdb_tx_update(ap->tx, &cont->c_prop, &ds_cont_prop_cont_obj_version, &value); if (rc) { diff --git a/src/include/daos/pool.h b/src/include/daos/pool.h index e51758e16b1..2747b8c3432 100644 --- a/src/include/daos/pool.h +++ b/src/include/daos/pool.h @@ -1,5 +1,6 @@ /* * (C) Copyright 2016-2024 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -85,6 +86,16 @@ */ #define DAOS_POOL_GLOBAL_VERSION 3 +/** + * Each individual object layout format, like oid layout, dkey to group, + * dkey to EC group start. + */ +enum { + DAOS_POOL_OBJ_VERSION_1 = 1, + DAOS_POOL_OBJ_VERSION_2 = 2, + DAOS_POOL_OBJ_VERSION = DAOS_POOL_OBJ_VERSION_2, +}; + int dc_pool_init(void); void dc_pool_fini(void); diff --git a/src/include/daos_cont.h b/src/include/daos_cont.h index 632eafe8130..6e6e5b98adc 100644 --- a/src/include/daos_cont.h +++ b/src/include/daos_cont.h @@ -1,5 +1,6 @@ /* * (C) Copyright 2020-2024 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -73,8 +74,15 @@ extern "C" { */ #define DAOS_COO_EVICT_ALL (1U << 6) +/** + * When clients attempt to open a container using the new hash layout, + * the server will reject the request if this flag is not set, + * even if the container is already in the new layout format. + */ +#define DAOS_COO_NEW_LAYOUT (1U << 7) + /** Number of bits in the container open mode flag, DAOS_COO_ bits */ -#define DAOS_COO_NBITS (7) +#define DAOS_COO_NBITS (8) /** Mask for all of the bits in the container open mode flag, DAOS_COO_ bits */ #define DAOS_COO_MASK ((1U << DAOS_COO_NBITS) - 1) diff --git a/src/include/daos_srv/pool.h b/src/include/daos_srv/pool.h index 1b5fcc902c9..7cf244e3cb0 100644 --- a/src/include/daos_srv/pool.h +++ b/src/include/daos_srv/pool.h @@ -30,12 +30,6 @@ /* Pool service (opaque) */ struct ds_pool_svc; -/** - * Each individual object layout format, like oid layout, dkey to group, - * dkey to EC group start. - */ -#define DS_POOL_OBJ_VERSION 1 - /* age of an entry in svc_ops KVS before it may be evicted */ #define DEFAULT_SVC_OPS_ENTRY_AGE_SEC_MAX 300ULL diff --git a/src/pipeline/cli_pipeline.c b/src/pipeline/cli_pipeline.c index b30d8366b79..9d76456f331 100644 --- a/src/pipeline/cli_pipeline.c +++ b/src/pipeline/cli_pipeline.c @@ -1,5 +1,6 @@ /** * (C) Copyright 2021-2023 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -544,7 +545,7 @@ shard_task_sched(tse_task_t *task, void *arg) static int pipeline_create_layout(daos_handle_t coh, struct dc_pool *pool, struct daos_obj_md *obj_md, - struct pl_obj_layout **layout) + struct pl_obj_layout **layout, uint16_t layout_gl_version) { int rc = 0; struct pl_map *map; @@ -555,7 +556,7 @@ pipeline_create_layout(daos_handle_t coh, struct dc_pool *pool, struct daos_obj_ D_GOTO(out, rc = -DER_INVAL); } - rc = pl_obj_place(map, 0, obj_md, 0, NULL, layout); + rc = pl_obj_place(map, layout_gl_version, obj_md, 0, NULL, layout); pl_map_decref(map); if (rc != 0) { D_DEBUG(DB_PL, "Failed to generate object layout\n"); @@ -609,6 +610,7 @@ dc_pipeline_run(tse_task_t *api_task) int total_replicas; int shard; struct pipeline_comp_cb_args comp_cb_args; + uint16_t layout_gl_ver; coh = dc_obj_hdl2cont_hdl(api_args->oh); rc = dc_obj_hdl2obj_md(api_args->oh, &obj_md); @@ -629,7 +631,8 @@ dc_pipeline_run(tse_task_t *api_task) /** get layout */ - rc = pipeline_create_layout(coh, pool, &obj_md, &layout); + layout_gl_ver = dc_obj_hdl2layout_ver(api_args->oh); + rc = pipeline_create_layout(coh, pool, &obj_md, &layout, layout_gl_ver); dc_pool_put(pool); if (rc != 0) D_GOTO(out, rc); @@ -687,7 +690,7 @@ dc_pipeline_run(tse_task_t *api_task) /** object id */ oid.id_pub = obj_md.omd_id; oid.id_shard = shard; - oid.id_layout_ver = dc_obj_hdl2layout_ver(api_args->oh); + oid.id_layout_ver = layout_gl_ver; oid.id_padding = 0; /** queue shard task */ diff --git a/src/placement/jump_map.c b/src/placement/jump_map.c index 179a3788ea5..70057d8e7d8 100644 --- a/src/placement/jump_map.c +++ b/src/placement/jump_map.c @@ -1,6 +1,7 @@ /** * * (C) Copyright 2016-2024 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -46,7 +47,7 @@ jm_obj_placement_fini(struct jm_obj_placement *jmop) #define LOCAL_PD_ARRAY_SIZE (4) static int jm_obj_pd_init(struct pl_jump_map *jmap, struct daos_obj_md *md, struct pool_domain *root, - struct jm_obj_placement *jmop) + struct jm_obj_placement *jmop, uint32_t layout_ver) { struct pool_domain *pds, *pd; uint8_t *pd_used = NULL; @@ -114,9 +115,9 @@ jm_obj_pd_init(struct pl_jump_map *jmap, struct daos_obj_md *md, struct pool_dom } oid = md->omd_id; - key = oid.hi ^ oid.lo; + key = jm_oid_hash(layout_ver, oid); for (i = 0; i < jmop->jmop_pd_nr; i++) { - key = crc(key, i); + key = (layout_ver <= 1) ? crc(key, i) : jm_crc(key, i, 0xcafebabe); selected_pd = d_hash_jump(key, jmap->jmp_pd_nr); do { selected_pd = selected_pd % jmap->jmp_pd_nr; @@ -242,8 +243,8 @@ layout_find_diff(struct pl_jump_map *jmap, struct pl_obj_layout *original, */ static int jm_obj_placement_init(struct pl_jump_map *jmap, struct daos_obj_md *md, - struct daos_obj_shard_md *shard_md, - struct jm_obj_placement *jmop) + struct daos_obj_shard_md *shard_md, struct jm_obj_placement *jmop, + uint32_t layout_ver) { struct daos_oclass_attr *oc_attr; struct pool_domain *root; @@ -305,7 +306,7 @@ jm_obj_placement_init(struct pl_jump_map *jmap, struct daos_obj_md *md, D_ASSERT(jmop->jmop_grp_nr > 0); D_ASSERT(jmop->jmop_grp_size > 0); - rc = jm_obj_pd_init(jmap, md, root, jmop); + rc = jm_obj_pd_init(jmap, md, root, jmop, layout_ver); if (rc == 0) D_DEBUG(DB_PL, "obj="DF_OID"/ grp_size=%u grp_nr=%d, pd_nr=%u pd_grp_size=%u\n", DP_OID(oid), jmop->jmop_grp_size, jmop->jmop_grp_nr, @@ -404,7 +405,7 @@ obj_remap_shards(struct pl_jump_map *jmap, uint32_t layout_ver, struct daos_obj_ current = remap_list->next; spare_tgt = NULL; oid = md->omd_id; - key = oid.hi ^ oid.lo; + key = jm_oid_hash(layout_ver, oid); spares_left = count_available_spares(jmap, layout, failed_in_layout); rc = pool_map_find_domain(jmap->jmp_map.pl_poolmap, PO_COMP_TP_ROOT, @@ -435,13 +436,16 @@ obj_remap_shards(struct pl_jump_map *jmap, uint32_t layout_ver, struct daos_obj_ dgu = f_shard->fs_data; D_ASSERT(dgu != NULL); - rebuild_key = crc(key, f_shard->fs_shard_idx); + if (layout_ver <= 1) + rebuild_key = crc(key, crc(key, f_shard->fs_shard_idx)); + else /* hash OID differently so we don't land to the same target */ + rebuild_key = jm_crc(oid.lo, oid.hi, 0xDead2Bad); + curr_pd = jm_obj_shard_pd(jmop, shard_id); - get_target(root, curr_pd, layout_ver, &spare_tgt, &spare_dom, - crc(key, rebuild_key), dom_used, dom_full, - dgu->dgu_used, dgu->dgu_real, tgts_used, - shard_id, allow_version, gen_mode, fdom_lvl, - jmop->jmop_grp_size, &spares_left, &spare_avail); + get_target(root, curr_pd, layout_ver, &spare_tgt, &spare_dom, rebuild_key, + dom_used, dom_full, dgu->dgu_used, dgu->dgu_real, tgts_used, + shard_id, allow_version, gen_mode, fdom_lvl, jmop->jmop_grp_size, + &spares_left, &spare_avail); if (layout_ver > 0) { /* * After 2.4 (layout_ver > 0), it will always assign each shard @@ -644,7 +648,8 @@ get_object_layout(struct pl_jump_map *jmap, uint32_t layout_ver, struct pl_obj_l D_GOTO(out, rc = -DER_NOMEM); oid = md->omd_id; - key = oid.hi ^ oid.lo; + key = jm_oid_hash(layout_ver, oid); + if (daos_obj_is_srank(oid)) spec_oid = true; @@ -1012,7 +1017,7 @@ jump_map_obj_place(struct pl_map *map, uint32_t layout_version, struct daos_obj_ D_DEBUG(DB_PL, "Determining location for object: "DF_OID", ver: %d, pda %u\n", DP_OID(oid), md->omd_ver, md->omd_pda); - rc = jm_obj_placement_init(jmap, md, shard_md, &jmop); + rc = jm_obj_placement_init(jmap, md, shard_md, &jmop, layout_version); if (rc) { D_ERROR("jm_obj_placement_init failed, rc "DF_RC"\n", DP_RC(rc)); return rc; @@ -1115,7 +1120,7 @@ jump_map_obj_find_diff(struct pl_map *map, uint32_t layout_ver, struct daos_obj_ } jmap = pl_map2jmap(map); - rc = jm_obj_placement_init(jmap, md, shard_md, &jop); + rc = jm_obj_placement_init(jmap, md, shard_md, &jop, layout_ver); if (rc) { D_ERROR("jm_obj_placement_init failed, rc %d.\n", rc); return rc; diff --git a/src/placement/jump_map.h b/src/placement/jump_map.h index 1fd39d3ce58..330872d842f 100644 --- a/src/placement/jump_map.h +++ b/src/placement/jump_map.h @@ -1,5 +1,6 @@ /** * (C) Copyright 2022-2023 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -61,4 +62,22 @@ get_target(struct pool_domain *root, struct pool_domain *curr_pd, uint32_t layou uint8_t *dom_full, uint8_t *dom_cur_grp_used, uint8_t *dom_cur_grp_real, uint8_t *tgts_used, int shard_num, uint32_t allow_version, enum layout_gen_mode gen_mode, pool_comp_type_t fdom_lvl, uint32_t grp_size, uint32_t *spare_left, bool *spare_avail); + +static inline uint64_t +jm_crc(uint64_t val0, uint64_t val1, uint64_t val2) +{ + uint64_t data[3]; + + data[0] = val0; + data[1] = val1; + data[2] = val2; + return crc64_ecma_refl(0xbabecafe, (uint8_t *)data, 24); +} + +static inline uint64_t +jm_oid_hash(uint32_t layout_ver, daos_obj_id_t oid) +{ + return layout_ver <= 1 ? (oid.hi ^ oid.lo) : jm_crc(oid.hi, oid.lo, 0xbabeface); +} + #endif /* __JUMP_MAP_H__ */ diff --git a/src/placement/jump_map_versions.c b/src/placement/jump_map_versions.c index b943949ad6a..f817ed96b04 100644 --- a/src/placement/jump_map_versions.c +++ b/src/placement/jump_map_versions.c @@ -1,6 +1,7 @@ /** * * (C) Copyright 2016-2024 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -414,6 +415,216 @@ __get_target_v1(struct pool_domain *root_pos, struct pool_domain *curr_pd, } while (!found_target); } +/** + * This function is identical to __get_target_v1, except how they call CRC functions, + * the V1 function may cause a large number of hash collisions in certain cases. + * + * Search for jm_crc() and crc() to see how they differ. + */ +static void +__get_target_v2(struct pool_domain *root_pos, struct pool_domain *curr_pd, + struct pool_target **target, struct pool_domain **dom, uint64_t obj_key, + uint8_t *dom_used, uint8_t *dom_full, uint8_t *dom_cur_grp_used, uint8_t *tgts_used, + int shard_num, uint32_t allow_version, enum layout_gen_mode gen_mode, + pool_comp_type_t fdom_lvl, uint32_t grp_size, bool *pd_ignored) +{ + int range_set; + uint8_t found_target = 0; + struct pool_domain *curr_dom; + struct pool_domain *dom_stack[MAX_STACK] = {0}; + int top = -1; + + curr_dom = curr_pd; + do { + uint32_t avail_doms; + uint64_t key; + + /* Retrieve number of nodes in this domain */ + avail_doms = get_num_domains(curr_dom, allow_version, gen_mode, fdom_lvl); + + /* If choosing target (lowest fault domain level) */ + if (curr_dom->do_comp.co_type == fdom_lvl) { + uint32_t fail_num = 0; + uint32_t tgt_idx; + uint32_t start_tgt; + uint32_t end_tgt; + uint32_t selected_tgt; + + start_tgt = curr_dom->do_targets - root_pos->do_targets; + end_tgt = start_tgt + (curr_dom->do_target_nr - 1); + + range_set = tgt_isset_range(root_pos->do_targets, tgts_used, start_tgt, + end_tgt, allow_version, gen_mode); + if (range_set) { + /* Used up all targets in this domain */ + D_ASSERT(top != -1); + curr_dom = dom_stack[top--]; /* try parent */ + continue; + } + + /* + * Must crc key because jump consistent hash + * requires an even distribution or it will + * not work + */ + key = jm_crc(obj_key, shard_num, fail_num++); + /* Get target for shard */ + selected_tgt = d_hash_jump(key, avail_doms); + do { + selected_tgt = selected_tgt % avail_doms; + /* Retrieve actual target using index */ + *target = + _get_target(curr_dom, selected_tgt, allow_version, gen_mode); + /* Get target id to check if target used */ + tgt_idx = *target - root_pos->do_targets; + selected_tgt++; + } while (isset(tgts_used, tgt_idx)); + + setbit(tgts_used, tgt_idx); + D_DEBUG(DB_PL, "selected tgt %d\n", tgt_idx); + D_ASSERTF(isclr(dom_full, (uint32_t)(curr_dom - root_pos)), + "selected_tgt %u\n", (uint32_t)(curr_dom - root_pos)); + range_set = tgt_isset_range(root_pos->do_targets, tgts_used, start_tgt, + end_tgt, allow_version, gen_mode); + if (range_set) { + /* Used up all targets in this domain */ + setbit(dom_full, curr_dom - root_pos); + D_DEBUG(DB_PL, "dom %d used up\n", (int)(curr_dom - root_pos)); + /* Check and set if all of its parent are full */ + while (top != -1) { + if (is_dom_full(dom_stack[top], root_pos, dom_full, + allow_version, gen_mode)) { + uint32_t off = dom_stack[top] - root_pos; + + D_DEBUG(DB_PL, "dom %u used up\n", off); + setbit(dom_full, off); + } + --top; + } + } + *dom = curr_dom; + /* Found target (which may be available or not) */ + found_target = 1; + } else { + uint32_t selected_dom; + uint32_t fail_num = 0; + uint32_t start_dom; + uint32_t end_dom; + + start_dom = (curr_dom->do_children) - root_pos; + end_dom = start_dom + (curr_dom->do_child_nr - 1); + + D_DEBUG(DB_TRACE, "start_dom %u end_dom %u\n", start_dom, end_dom); + /* Check if all targets under the domain range has been + * used up (occupied), go back to its parent if it does. + */ + range_set = + is_dom_full(curr_dom, root_pos, dom_full, allow_version, gen_mode); + if (range_set) { + if (top == -1) { + if (curr_pd != root_pos) { + /* all domains within the PD are full, ignore the + * PD restrict. + */ + D_DEBUG(DB_PL, + "PD[%d] all doms are full, weak the " + "PD restrict\n", + (int)(curr_dom - root_pos)); + curr_pd = root_pos; + curr_dom = curr_pd; + *pd_ignored = true; + continue; + } + /* shard nr > target nr, no extra target for the shard */ + *target = NULL; + return; + } + setbit(dom_full, curr_dom - root_pos); + D_DEBUG(DB_PL, "used up dom %d\n", (int)(curr_dom - root_pos)); + setbit(dom_cur_grp_used, curr_dom - root_pos); + curr_dom = dom_stack[top--]; + continue; + } + + /* Check if all children has been used for the current group or full */ + range_set = dom_isset_2ranges(root_pos, dom_full, dom_cur_grp_used, + start_dom, end_dom, allow_version, gen_mode); + if (range_set) { + if (top == -1) { + if (curr_pd != root_pos && grp_size > 1) { + /* All domains within the PD are full, ignore the + * PD restrict. For non-replica (grp_size 1) case, + * keep the PD restrict until all targets under the + * domain range has been used up (see above check + * for dom_full bitmap). + */ + D_DEBUG(DB_PL, + "PD[%d] all doms are full, weak the " + "PD restrict\n", + (int)(curr_dom - root_pos)); + curr_pd = root_pos; + curr_dom = curr_pd; + *pd_ignored = true; + continue; + } + *target = NULL; + return; + } + setbit(dom_cur_grp_used, curr_dom - root_pos); + D_DEBUG(DB_PL, "set grp_used %d\n", (int)(curr_dom - root_pos)); + curr_dom = dom_stack[top--]; + continue; + } + + /* Check if all children has been used for the current group or the + * object. + */ + range_set = dom_isset_2ranges(root_pos, dom_used, dom_cur_grp_used, + start_dom, end_dom, allow_version, gen_mode); + if (range_set) { + int idx; + + for (idx = start_dom; idx <= end_dom; ++idx) + if (!isset(dom_full, idx)) { + clrbit(dom_used, idx); + D_DEBUG(DB_PL, "clrbit dom_used %d\n", idx); + } + if (top == -1) + curr_dom = curr_pd; + else + curr_dom = dom_stack[top--]; + continue; + } + + /* Keep choosing the new domain until the one has not been used. */ + do { + struct pool_domain *_dom; + + key = jm_crc(obj_key, shard_num, fail_num++); + selected_dom = d_hash_jump(key, avail_doms); + _dom = _get_dom(curr_dom, selected_dom, allow_version, gen_mode); + if (_dom != NULL) + selected_dom = _dom - curr_dom->do_children; + } while (isset(dom_used, start_dom + selected_dom) || + isset(dom_cur_grp_used, start_dom + selected_dom)); + + D_ASSERTF(isclr(dom_full, start_dom + selected_dom), "selected_dom %u\n", + selected_dom); + /* Mark this domain as used */ + if (curr_dom == curr_pd && curr_pd != root_pos) + setbit(dom_used, (int)(curr_dom - root_pos)); + D_DEBUG(DB_PL, "selected dom %d\n", start_dom + selected_dom); + setbit(dom_used, start_dom + selected_dom); + setbit(dom_cur_grp_used, start_dom + selected_dom); + D_ASSERT(top < MAX_STACK - 1); + top++; + dom_stack[top] = curr_dom; + curr_dom = &curr_dom->do_children[selected_dom]; + obj_key = jm_crc(obj_key, curr_dom->do_comp.co_id, 0xbabecafe); + } + } while (!found_target); +} + /* Only reset all used dom/tgts bits if all domain has been used. */ static void dom_reset_bit(struct pool_domain *dom, uint8_t *dom_bits, struct pool_domain *root, @@ -604,11 +815,11 @@ reset_dom_cur_grp_v1(struct pool_domain *root, struct pool_domain *curr_pd, } static void -get_target_v1(struct pool_domain *root, struct pool_domain *curr_pd, struct pool_target **target, - struct pool_domain **dom, uint64_t key, uint8_t *dom_used, uint8_t *dom_full, - uint8_t *dom_cur_grp_used, uint8_t *dom_cur_grp_real, uint8_t *tgts_used, - int shard_num, uint32_t allow_version, enum layout_gen_mode gen_mode, - pool_comp_type_t fdom_lvl, uint32_t grp_size) +get_target_new(struct pool_domain *root, struct pool_domain *curr_pd, uint32_t layout_ver, + struct pool_target **target, struct pool_domain **dom, uint64_t key, + uint8_t *dom_used, uint8_t *dom_full, uint8_t *dom_cur_grp_used, + uint8_t *dom_cur_grp_real, uint8_t *tgts_used, int shard_num, uint32_t allow_version, + enum layout_gen_mode gen_mode, pool_comp_type_t fdom_lvl, uint32_t grp_size) { struct pool_target *found = NULL; bool pd_ignored; @@ -622,9 +833,17 @@ get_target_v1(struct pool_domain *root, struct pool_domain *curr_pd, struct pool */ while (found == NULL) { pd_ignored = false; - __get_target_v1(root, curr_pd, &found, dom, key, dom_used, dom_full, - dom_cur_grp_used, tgts_used, shard_num, allow_version, gen_mode, - fdom_lvl, grp_size, &pd_ignored); + if (layout_ver == 1) { + __get_target_v1(root, curr_pd, &found, dom, key, dom_used, dom_full, + dom_cur_grp_used, tgts_used, shard_num, allow_version, + gen_mode, fdom_lvl, grp_size, &pd_ignored); + } else { /* Fix CRC calls */ + D_ASSERT(layout_ver == 2); + __get_target_v2(root, curr_pd, &found, dom, key, dom_used, dom_full, + dom_cur_grp_used, tgts_used, shard_num, allow_version, + gen_mode, fdom_lvl, grp_size, &pd_ignored); + } + if (found == NULL) { if (pd_ignored) reset_dom_cur_grp_v1(root, root, dom_cur_grp_used, dom_cur_grp_real, @@ -901,14 +1120,15 @@ get_target(struct pool_domain *root, struct pool_domain *curr_pd, uint32_t layou } break; case 1: + case 2: /** * New layout(>= 1) will always try to assign target to the shard due to the high * overhead of the EC degraded fetch, so it might put multiple shards in the * same target, i.e. it will never check the spare target here. */ - get_target_v1(root, curr_pd, target, dom, key, dom_used, dom_full, dom_cur_grp_used, - dom_cur_grp_real, tgts_used, shard_num, allow_version, gen_mode, - fdom_lvl, grp_size); + get_target_new(root, curr_pd, layout_ver, target, dom, key, dom_used, dom_full, + dom_cur_grp_used, dom_cur_grp_real, tgts_used, shard_num, + allow_version, gen_mode, fdom_lvl, grp_size); if (spare_avail) *spare_avail = true; break; diff --git a/src/placement/tests/jump_map_place_obj.c b/src/placement/tests/jump_map_place_obj.c index 8e257aad82f..b2e5e1d21e7 100644 --- a/src/placement/tests/jump_map_place_obj.c +++ b/src/placement/tests/jump_map_place_obj.c @@ -1196,10 +1196,10 @@ down_back_to_up_in_same_order(void **state) * healthy targets because of the retry/collision mechanism of the jump * map algorithm. * Due to layout colocation, if the oid has been changed, then it could - * be 2 or even 3 as well, with current oid setting, this is 1. + * be 2 or even 3 as well, with current oid setting, this is 2. */ - assert_int_equal(1, ctx.reint.out_nr); - jtc_assert_rebuild_reint_new(ctx, 1, 0, 1, 1); + assert_int_equal(2, ctx.reint.out_nr); + jtc_assert_rebuild_reint_new(ctx, 2, 0, 2, 2); /* Take second downed target up */ jtc_set_status_on_target(&ctx, UP, orig_shard_targets[1]); @@ -1674,14 +1674,14 @@ placement_handles_multiple_states_with_addition(void **state) rebuilding = jtc_get_layout_rebuild_count(&ctx); /* 1 each for down, up, new ... maybe? */ - assert_true(rebuilding == 2 || rebuilding == 3); + assert_true(rebuilding == 2 || rebuilding == 3 || rebuilding == 4); /* Both DOWN and UP target will be remapped during remap */ - assert_int_equal(ctx.rebuild.out_nr, 2); + assert_int_equal(ctx.rebuild.out_nr, 3); /* Adding new targets might make original shard to be remapped * to new location. */ - assert_true(ctx.reint.out_nr == 1 || ctx.reint.out_nr == 2); + assert_true(ctx.reint.out_nr == 1 || ctx.reint.out_nr == 2 || ctx.reint.out_nr == 3); /* JCH might cause multiple shards remap to the new target */ assert_true(ctx.new.out_nr >= 1); diff --git a/src/placement/tests/place_obj_common.h b/src/placement/tests/place_obj_common.h index 537c02a8de7..537fbe963a2 100644 --- a/src/placement/tests/place_obj_common.h +++ b/src/placement/tests/place_obj_common.h @@ -1,5 +1,6 @@ /** * (C) Copyright 2016-2023 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -28,7 +29,7 @@ extern bool g_verbose; #define is_true assert_true #define is_false assert_false -#define PLT_LAYOUT_VERSION 1 +#define PLT_LAYOUT_VERSION 2 extern bool fail_domain_node; void print_layout(struct pl_obj_layout *layout); diff --git a/src/pool/srv_layout.c b/src/pool/srv_layout.c index dbddb92ef6f..1456cbeaf46 100644 --- a/src/pool/srv_layout.c +++ b/src/pool/srv_layout.c @@ -1,5 +1,6 @@ /* * (C) Copyright 2017-2023 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -133,7 +134,7 @@ struct daos_prop_entry pool_prop_entries_default[DAOS_PROP_PO_NUM] = { }, { .dpe_type = DAOS_PROP_PO_OBJ_VERSION, - .dpe_val = DS_POOL_OBJ_VERSION, + .dpe_val = DAOS_POOL_OBJ_VERSION, }, { .dpe_type = DAOS_PROP_PO_PERF_DOMAIN, diff --git a/src/pool/srv_pool.c b/src/pool/srv_pool.c index d207f4876c9..339a236e281 100644 --- a/src/pool/srv_pool.c +++ b/src/pool/srv_pool.c @@ -665,7 +665,7 @@ pool_prop_write(struct rdb_tx *tx, const rdb_path_t *kvs, daos_prop_t *prop) rc = rdb_tx_update(tx, kvs, &ds_pool_prop_svc_redun_fac, &value); break; case DAOS_PROP_PO_OBJ_VERSION: - if (entry->dpe_val > DS_POOL_OBJ_VERSION) { + if (entry->dpe_val > DAOS_POOL_OBJ_VERSION) { rc = -DER_INVAL; break; } @@ -6030,7 +6030,7 @@ __ds_pool_mark_upgrade_completed(uuid_t pool_uuid, struct pool_svc *svc, int rc) obj_version = (uint32_t)fail_val; } else { - obj_version = DS_POOL_OBJ_VERSION; + obj_version = DAOS_POOL_OBJ_VERSION; } d_iov_set(&value, &obj_version, sizeof(obj_version)); @@ -6091,10 +6091,9 @@ pool_check_upgrade_object_layout(struct rdb_tx *tx, struct pool_svc *svc, else if (rc == -DER_NONEXIST) current_layout_ver = 0; - if (current_layout_ver < DS_POOL_OBJ_VERSION) { - rc = ds_rebuild_schedule(svc->ps_pool, svc->ps_pool->sp_map_version, - upgrade_eph, DS_POOL_OBJ_VERSION, NULL, - RB_OP_UPGRADE, 0); + if (current_layout_ver < DAOS_POOL_OBJ_VERSION) { + rc = ds_rebuild_schedule(svc->ps_pool, svc->ps_pool->sp_map_version, upgrade_eph, + DAOS_POOL_OBJ_VERSION, NULL, RB_OP_UPGRADE, 0); if (rc == 0) *scheduled_layout_upgrade = true; } From 1683541c601af3eea9562227e5640f52caa212d4 Mon Sep 17 00:00:00 2001 From: Niu Yawei Date: Tue, 30 Sep 2025 02:23:11 +0800 Subject: [PATCH 06/12] DAOS-17759 test: bump restart_duration (#16834) (#16914) Slightly bump restart_duration from 120 to 140 seconds. Signed-off-by: Niu Yawei --- src/tests/ftest/pool/create_capacity.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/ftest/pool/create_capacity.yaml b/src/tests/ftest/pool/create_capacity.yaml index 9ba2c5652fe..1eee1e71e6a 100644 --- a/src/tests/ftest/pool/create_capacity.yaml +++ b/src/tests/ftest/pool/create_capacity.yaml @@ -9,7 +9,7 @@ timeouts: server_config: name: daos_server engines_per_host: 2 - restart_duration: 120 + restart_duration: 140 engines: 0: pinned_numa_node: 0 From 2416e0c8d4909fbbdec9df3d5b0fb708a895e600 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 07:41:19 -0700 Subject: [PATCH 07/12] DAOS-18022 cq: Bump github/codeql-action from 3.30.3 to 3.30.5 (#16921) (#16920) Updates `github/codeql-action` from 3.30.3 to 3.30.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/192325c86100d080feab897ff886c34abd4c83a3...3599b3baa15b485a2e49ef411a7a4bb2452e7f93) Signed-off-by: dependabot[bot] --- .github/workflows/ossf-scorecard.yml | 2 +- .github/workflows/trivy.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index c0cf1c5257b..fa39d27eb83 100644 --- a/.github/workflows/ossf-scorecard.yml +++ b/.github/workflows/ossf-scorecard.yml @@ -71,6 +71,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 with: sarif_file: results.sarif diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index dd8b3c3db7c..1f0c07c9c3e 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -58,7 +58,7 @@ jobs: trivy-config: 'utils/trivy/trivy.yaml' - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 with: sarif_file: 'trivy-results.sarif' From caf473b70338ccf3c17ecfb0832b77ec7c0fa6f3 Mon Sep 17 00:00:00 2001 From: Mohamad Chaarawi Date: Wed, 8 Oct 2025 09:05:49 -0500 Subject: [PATCH 08/12] DAOS-18015 dfuse: add options for dfuse to dump handles (#16910) (#16933) Add 2 new options for dfuse to --dump-handles and --read-handles to a file. dump will serialize the pool, container, and dfs handles to that file, and read will read that file for those handles and use the g2l to connect to the pool, container and DFS. If using MPI to launch dfuse, we should not force running in the foreground as that introduces several limitations. MPI like clush should be able to launch and daemonize dfuse. Signed-off-by: Mohamad Chaarawi --- src/client/dfuse/dfuse.h | 7 ++ src/client/dfuse/dfuse_core.c | 58 ++++++---- src/client/dfuse/dfuse_main.c | 202 +++++++++++++++++++++++++++++++++- utils/node_local_test.py | 29 ++++- 4 files changed, 268 insertions(+), 28 deletions(-) diff --git a/src/client/dfuse/dfuse.h b/src/client/dfuse/dfuse.h index 58847287391..7244875029e 100644 --- a/src/client/dfuse/dfuse.h +++ b/src/client/dfuse/dfuse.h @@ -1,5 +1,6 @@ /** * (C) Copyright 2016-2024 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -27,6 +28,12 @@ struct dfuse_info { struct fuse_session *di_session; char *di_group; char *di_mountpoint; + char *di_handles_file; + bool di_dump_handles; + bool di_read_handles; + daos_handle_t di_poh; + daos_handle_t di_coh; + dfs_t *di_dfs; int32_t di_thread_count; uint32_t di_eq_count; bool di_threaded; diff --git a/src/client/dfuse/dfuse_core.c b/src/client/dfuse/dfuse_core.c index 5ca85d27588..be485c95168 100644 --- a/src/client/dfuse/dfuse_core.c +++ b/src/client/dfuse/dfuse_core.c @@ -499,14 +499,24 @@ dfuse_pool_connect(struct dfuse_info *dfuse_info, const char *label, struct dfus if (label) { daos_pool_info_t p_info = {}; - rc = daos_pool_connect(label, dfuse_info->di_group, DAOS_PC_RO, &dfp->dfp_poh, - &p_info, NULL); - if (rc) { - if (rc == -DER_NO_PERM || rc == -DER_NONEXIST) - DHL_INFO(dfp, rc, "daos_pool_connect() failed"); - else - DHL_ERROR(dfp, rc, "daos_pool_connect() failed"); - D_GOTO(err_free, rc = daos_der2errno(rc)); + /** if we read the pool handle, query for the info */ + if (dfuse_info->di_read_handles) { + dfp->dfp_poh = dfuse_info->di_poh; + rc = daos_pool_query(dfp->dfp_poh, NULL, &p_info, NULL, NULL); + if (rc) { + DHL_ERROR(dfp, rc, "daos_pool_query() failed"); + D_GOTO(err_free, rc = daos_der2errno(rc)); + } + } else { + rc = daos_pool_connect(label, dfuse_info->di_group, DAOS_PC_RO, + &dfp->dfp_poh, &p_info, NULL); + if (rc) { + if (rc == -DER_NO_PERM || rc == -DER_NONEXIST) + DHL_INFO(dfp, rc, "daos_pool_connect() failed"); + else + DHL_ERROR(dfp, rc, "daos_pool_connect() failed"); + D_GOTO(err_free, rc = daos_der2errno(rc)); + } } uuid_copy(dfp->dfp_uuid, p_info.pi_uuid); @@ -847,17 +857,23 @@ dfuse_cont_open(struct dfuse_info *dfuse_info, struct dfuse_pool *dfp, const cha int dfs_flags = O_RDWR; dfc->dfs_ops = &dfuse_dfs_ops; - if (dfuse_info->di_read_only) { - dfs_flags = O_RDONLY; - rc = daos_cont_open(dfp->dfp_poh, label, DAOS_COO_RO, &dfc->dfs_coh, - &c_info, NULL); + + if (dfuse_info->di_read_handles) { + dfc->dfs_coh = dfuse_info->di_coh; + rc = daos_cont_query(dfc->dfs_coh, &c_info, NULL, NULL); } else { - rc = daos_cont_open(dfp->dfp_poh, label, DAOS_COO_RW, &dfc->dfs_coh, - &c_info, NULL); - if (rc == -DER_NO_PERM) { + if (dfuse_info->di_read_only) { dfs_flags = O_RDONLY; rc = daos_cont_open(dfp->dfp_poh, label, DAOS_COO_RO, &dfc->dfs_coh, &c_info, NULL); + } else { + rc = daos_cont_open(dfp->dfp_poh, label, DAOS_COO_RW, &dfc->dfs_coh, + &c_info, NULL); + if (rc == -DER_NO_PERM) { + dfs_flags = O_RDONLY; + rc = daos_cont_open(dfp->dfp_poh, label, DAOS_COO_RO, + &dfc->dfs_coh, &c_info, NULL); + } } } if (rc != -DER_SUCCESS) { @@ -868,10 +884,14 @@ dfuse_cont_open(struct dfuse_info *dfuse_info, struct dfuse_pool *dfp, const cha D_GOTO(err_free, rc = daos_der2errno(rc)); } - rc = dfs_mount(dfp->dfp_poh, dfc->dfs_coh, dfs_flags, &dfc->dfs_ns); - if (rc) { - DHS_ERROR(dfc, rc, "dfs mount() failed"); - D_GOTO(err_close, rc); + if (dfuse_info->di_read_handles) + dfc->dfs_ns = dfuse_info->di_dfs; + else { + rc = dfs_mount(dfp->dfp_poh, dfc->dfs_coh, dfs_flags, &dfc->dfs_ns); + if (rc) { + DHS_ERROR(dfc, rc, "dfs mount() failed"); + D_GOTO(err_close, rc); + } } uuid_copy(dfc->dfc_uuid, c_info.ci_uuid); diff --git a/src/client/dfuse/dfuse_main.c b/src/client/dfuse/dfuse_main.c index bcb9632c6ee..8bd975530b2 100644 --- a/src/client/dfuse/dfuse_main.c +++ b/src/client/dfuse/dfuse_main.c @@ -293,6 +293,10 @@ show_help(char *name) "\n" " --multi-user Run dfuse in multi user mode\n" " --read-only Mount dfuse read-only\n" + " --dump-handles=file Serialize and dump the pool, container, and dfs handles" + " to file using the local2global DAOS functionality\n" + " --read-handles=file Read the deserialize the pool, cont, and dfs handles," + " and use them instead of connecting to the server\n" "\n" " -h --help Show this help\n" " -v --version Show version\n" @@ -369,6 +373,11 @@ show_help(char *name) " The default is --enable-wb-cache.\n" "* If --disable-caching and --enable-wb-cache are both specified,\n" " the --enable-wb-cache option is ignored and no caching is performed.\n" + "* If --dump-handles is used from one dfuse mount and --read-handles is used for\n" + " starting other dfuse mounts, the dfuse mount that dumps the handles cannot be\n" + " umounted before the others, otherwise the other mounts will become inaccessible\n" + " since the g2l & l2g method for sharing DAOS handles requires the main process\n" + " that establishes the pool and container connections to keep those alive.\n" "\n" "Version: %s\n", name, DAOS_VERSION); @@ -433,6 +442,8 @@ main(int argc, char **argv) {"enable-wb-cache", no_argument, 0, 'F'}, {"disable-caching", no_argument, 0, 'A'}, {"disable-wb-cache", no_argument, 0, 'B'}, + {"dump-handles", required_argument, 0, 'D'}, + {"read-handles", required_argument, 0, 'R'}, {"read-only", no_argument, 0, 'r'}, {"options", required_argument, 0, 'o'}, {"version", no_argument, 0, 'v'}, @@ -453,6 +464,8 @@ main(int argc, char **argv) dfuse_info->di_caching = true; dfuse_info->di_wb_cache = true; dfuse_info->di_eq_count = 1; + dfuse_info->di_dump_handles = false; + dfuse_info->di_read_handles = false; while (1) { c = getopt_long(argc, argv, "Mm:St:o:fhe:v", long_options, NULL); @@ -487,6 +500,14 @@ main(int argc, char **argv) case 'm': dfuse_info->di_mountpoint = optarg; break; + case 'D': + dfuse_info->di_handles_file = optarg; + dfuse_info->di_dump_handles = true; + break; + case 'R': + dfuse_info->di_handles_file = optarg; + dfuse_info->di_read_handles = true; + break; case 'M': dfuse_info->di_multi_user = true; break; @@ -550,17 +571,16 @@ main(int argc, char **argv) } } - if (!dfuse_info->di_foreground && d_isenv_def("PMIX_RANK")) { - DFUSE_TRA_WARNING(dfuse_info, - "Not running in background under orterun"); - dfuse_info->di_foreground = true; - } - if (!dfuse_info->di_mountpoint) { printf("Mountpoint is required\n"); show_help(argv[0]); D_GOTO(out_debug, rc = -DER_INVAL); } + if (dfuse_info->di_dump_handles && dfuse_info->di_read_handles) { + printf("Cannot dump and read handles file at the same time\n"); + show_help(argv[0]); + D_GOTO(out_debug, rc = -DER_INVAL); + } /* If the number of threads has been specified on the command line then use that, otherwise * check CPU binding. If bound to a number of cores then launch that number of threads, @@ -708,6 +728,91 @@ main(int argc, char **argv) D_GOTO(out_daos, rc = daos_errno2der(rc)); } + /** if user passes a handle file, read it and store the serialized handles */ + if (dfuse_info->di_read_handles && dfuse_info->di_handles_file) { + d_iov_t pool_hdl = {NULL, 0, 0}; + d_iov_t cont_hdl = {NULL, 0, 0}; + d_iov_t dfs_hdl = {NULL, 0, 0}; + char *buf = NULL; + daos_size_t buf_size; + size_t sizes[3]; + FILE *fp; + int dfs_flags = O_RDWR; + + fp = fopen(dfuse_info->di_handles_file, "rb"); + if (!fp) { + rc = errno; + DHL_ERROR(dfuse_info, daos_errno2der(rc), "Failed to open file %s", + dfuse_info->di_handles_file); + D_GOTO(out_daos, rc = daos_errno2der(rc)); + } + + /** read the 3 size_t values for the 3 handles */ + if (fread(sizes, sizeof(size_t), 3, fp) != 3) { + rc = errno; + DHL_ERROR(dfuse_info, daos_errno2der(rc), "Failed to read file %s", + dfuse_info->di_handles_file); + fclose(fp); + D_GOTO(out_daos, rc = daos_errno2der(rc)); + } + pool_hdl.iov_buf_len = pool_hdl.iov_len = sizes[0]; + cont_hdl.iov_buf_len = cont_hdl.iov_len = sizes[1]; + dfs_hdl.iov_buf_len = dfs_hdl.iov_len = sizes[2]; + + buf_size = sizes[0] + sizes[1] + sizes[2]; + D_ALLOC(buf, buf_size); + if (buf == NULL) { + fclose(fp); + D_GOTO(out_daos, rc = -DER_NOMEM); + } + + if (fread(buf, 1, buf_size, fp) != buf_size) { + rc = errno; + DHL_ERROR(dfuse_info, daos_errno2der(rc), "Failed to read file %s", + dfuse_info->di_handles_file); + fclose(fp); + D_FREE(buf); + D_GOTO(out_daos, rc = daos_errno2der(rc)); + } + + pool_hdl.iov_buf = buf; + cont_hdl.iov_buf = buf + pool_hdl.iov_buf_len; + dfs_hdl.iov_buf = buf + pool_hdl.iov_buf_len + cont_hdl.iov_buf_len; + + rc = daos_pool_global2local(pool_hdl, &dfuse_info->di_poh); + if (rc) { + fclose(fp); + D_FREE(buf); + DHL_ERROR(dfuse_info, rc, "daos_pool_global2local() failed"); + D_GOTO(out_daos, rc); + } + + rc = daos_cont_global2local(dfuse_info->di_poh, cont_hdl, &dfuse_info->di_coh); + if (rc) { + fclose(fp); + D_FREE(buf); + daos_pool_disconnect(dfuse_info->di_poh, NULL); + DHL_ERROR(dfuse_info, rc, "daos_cont_global2local() failed"); + D_GOTO(out_daos, rc); + } + + if (dfuse_info->di_read_only) + dfs_flags = O_RDONLY; + rc = dfs_global2local(dfuse_info->di_poh, dfuse_info->di_coh, dfs_flags, dfs_hdl, + &dfuse_info->di_dfs); + if (rc) { + fclose(fp); + D_FREE(buf); + daos_cont_close(dfuse_info->di_coh, NULL); + daos_pool_disconnect(dfuse_info->di_poh, NULL); + DHL_ERROR(dfuse_info, rc, "dfs_global2local() failed"); + D_GOTO(out_daos, rc); + } + + fclose(fp); + D_FREE(buf); + } + /* Connect to a pool */ rc = dfuse_pool_connect(dfuse_info, pool_name[0] ? pool_name : NULL, &dfp); if (rc != 0) { @@ -721,6 +826,91 @@ main(int argc, char **argv) D_GOTO(out_pool, rc = daos_errno2der(rc)); } + /** if user asked to dump the handles, serialize them and write them to the file */ + if (dfuse_info->di_dump_handles && dfuse_info->di_handles_file) { + d_iov_t pool_hdl = {NULL, 0, 0}; + d_iov_t cont_hdl = {NULL, 0, 0}; + d_iov_t dfs_hdl = {NULL, 0, 0}; + char *buf = NULL; + daos_size_t buf_size; + FILE *fp; + + rc = daos_pool_local2global(dfp->dfp_poh, &pool_hdl); + if (rc) { + DHL_ERROR(dfuse_info, rc, "daos_pool_local2global() failed"); + goto out_cont; + } + rc = daos_cont_local2global(dfs->dfs_coh, &cont_hdl); + if (rc) { + DHL_ERROR(dfuse_info, rc, "daos_cont_local2global() failed"); + goto out_cont; + } + rc = dfs_local2global(dfs->dfs_ns, &dfs_hdl); + if (rc) { + DHL_ERROR(dfuse_info, rc, "dfs_local2global() failed"); + goto out_cont; + } + + buf_size = pool_hdl.iov_buf_len + cont_hdl.iov_buf_len + dfs_hdl.iov_buf_len; + D_ALLOC(buf, buf_size); + if (buf == NULL) + D_GOTO(out_cont, rc = -DER_NOMEM); + + pool_hdl.iov_buf = buf; + cont_hdl.iov_buf = buf + pool_hdl.iov_buf_len; + dfs_hdl.iov_buf = buf + pool_hdl.iov_buf_len + cont_hdl.iov_buf_len; + + rc = daos_pool_local2global(dfp->dfp_poh, &pool_hdl); + if (rc) { + DHL_ERROR(dfuse_info, rc, "daos_pool_local2global() failed"); + D_FREE(buf); + goto out_cont; + } + rc = daos_cont_local2global(dfs->dfs_coh, &cont_hdl); + if (rc) { + DHL_ERROR(dfuse_info, rc, "daos_cont_local2global() failed"); + D_FREE(buf); + goto out_cont; + } + rc = dfs_local2global(dfs->dfs_ns, &dfs_hdl); + if (rc) { + DHL_ERROR(dfuse_info, rc, "dfs_local2global() failed"); + D_FREE(buf); + goto out_cont; + } + + fp = fopen(dfuse_info->di_handles_file, "wb+"); + if (!fp) { + rc = errno; + DHL_ERROR(dfuse_info, daos_errno2der(rc), "Failed to open file %s", + dfuse_info->di_handles_file); + D_FREE(buf); + D_GOTO(out_cont, rc = daos_errno2der(rc)); + } + + size_t sizes[3] = {pool_hdl.iov_buf_len, cont_hdl.iov_buf_len, dfs_hdl.iov_buf_len}; + + if (fwrite(sizes, sizeof(size_t), 3, fp) != 3) { + rc = errno; + fclose(fp); + D_FREE(buf); + DHL_ERROR(dfuse_info, daos_errno2der(rc), "Failed to write file %s", + dfuse_info->di_handles_file); + D_GOTO(out_cont, rc = daos_errno2der(rc)); + } + + if (fwrite(buf, 1, buf_size, fp) != buf_size) { + rc = errno; + fclose(fp); + D_FREE(buf); + DHL_ERROR(dfuse_info, daos_errno2der(rc), "Failed to write file %s", + dfuse_info->di_handles_file); + D_GOTO(out_cont, rc = daos_errno2der(rc)); + } + fclose(fp); + D_FREE(buf); + } + rc = dfuse_fs_start(dfuse_info, dfs); if (rc != -DER_SUCCESS) D_GOTO(out_cont, rc); diff --git a/utils/node_local_test.py b/utils/node_local_test.py index a1d5703ae3d..7e86aac13d0 100755 --- a/utils/node_local_test.py +++ b/utils/node_local_test.py @@ -1295,7 +1295,8 @@ class DFuse(): # pylint: disable-next=too-many-arguments def __init__(self, daos, conf, pool=None, container=None, mount_path=None, uns_path=None, - caching=True, wbcache=True, multi_user=False, ro=False): + caching=True, wbcache=True, multi_user=False, ro=False, dump_h=False, + read_h=False, file_h=None): if mount_path: self.dir = mount_path else: @@ -1320,6 +1321,9 @@ def __init__(self, daos, conf, pool=None, container=None, mount_path=None, uns_p self.log_mask = None self.log_file = None self._ro = ro + self.dump_h = dump_h + self.read_h = read_h + self.file_h = file_h self.valgrind = None if not os.path.exists(self.dir): @@ -1394,6 +1398,11 @@ def start(self, v_hint=None, single_threaded=False, use_oopt=False): if not self.wbcache: cmd.append('--disable-wb-cache') + if self.dump_h: + cmd.extend(['--dump-handles', self.file_h]) + if self.read_h: + cmd.extend(['--read-handles', self.file_h]) + if self._ro: cmd.append('--read-only') @@ -2310,15 +2319,29 @@ def test_pre_read(self): def test_two_mounts(self): """Create two mounts, and check that a file created in one can be read from the other""" + + try: + fd, tmpfile = tempfile.mkstemp(prefix="my_temp_file_", dir="/tmp") + print(f"Created temp file: {tmpfile}") + os.close(fd) + + except OSError as e: + print(f"mkstemp failed: {e}", file=sys.stderr) + sys.exit(1) + dfuse0 = DFuse(self.server, self.conf, caching=False, + dump_h=True, + file_h=tmpfile, container=self.container) dfuse0.start(v_hint='two_0') dfuse1 = DFuse(self.server, self.conf, caching=True, + read_h=True, + file_h=tmpfile, container=self.container) dfuse1.start(v_hint='two_1') @@ -2334,10 +2357,10 @@ def test_two_mounts(self): with open(file0, 'w') as fd: fd.write('test') - if dfuse0.stop(): - self.fatal_errors = True if dfuse1.stop(): self.fatal_errors = True + if dfuse0.stop(): + self.fatal_errors = True def test_cache_expire(self): """Check that data and readdir cache expire correctly From 03a3635505498ff555caa181f4a1fe7a8be4c543 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 9 Oct 2025 16:24:50 +0200 Subject: [PATCH 09/12] DAOS-17997 cq: Update hadoop from 3.4.0 to 3.4.2 (#16887) (#16888) Hadoop 3.4.2 eliminates the following vulnerabilities: CVE-2023-39410,HIGH,7.5,"apache-avro: Apache Avro Java SDK: Memory when deserializing untrusted data in Avro Java SDK","org.apache.avro:avro","1.7.7","1.11.3", https://avd.aquasec.com/nvd/cve-2023-39410 CVE-2024-47561,CRITICAL,,"apache-avro: Schema parsing may trigger Remote Code Execution (RCE)", "org.apache.avro:avro","1.9.2","1.11.4",https://avd.aquasec.com/nvd/cve-2024-47561 CVE-2025-24970,HIGH,,"io.netty:netty-handler: SslHandler doesn't correctly validate packets which can lead to native crash when using native SSLEngine","io.netty:netty-handler", "4.1.100.Final","4.1.118.Final",https://avd.aquasec.com/nvd/cve-2025-24970 CVE-2025-49128,MEDIUM,,"com.fasterxml.jackson.core/jackson-core: Jackson-core Memory Disclosure via Source Snippet in JsonLocation","com.fasterxml.jackson.core:jackson-core", "2.10.2","2.13.0",https://avd.aquasec.com/nvd/cve-2025-49128 CVE-2025-48734,HIGH,,"commons-beanutils: Apache Commons BeanUtils: PropertyUtilsBean does not suppresses an enum's declaredClass property by default", "commons-beanutils:commons-beanutils","1.9.4","1.11.0", https://avd.aquasec.com/nvd/cve-2025-48734 CVE-2025-25193,MEDIUM,,"Netty, an asynchronous, event-driven network application framework, ha ...","io.netty:netty-common","4.1.115.Final","",https://avd.aquasec.com/nvd/cve-2025-25193 This PR also updates io.netty.netty-buffer from 4.1.115 to 4.1.125 to eliminate the following vulnerability: CVE-2025-58057,MEDIUM,7.5,"netty-codec: netty-codec-compression: Netty's BrotliDecoder is vulnerable to DoS via zip bomb style attack","io.netty:netty-codec","4.1.100.Final", "4.1.125.Final",https://avd.aquasec.com/nvd/cve-2025-58057 NOTICE: Hadoop 3.4.2 introduces new vulnerability: CVE-2025-58057,MEDIUM,7.5,"netty-codec: netty-codec-compression: Netty's BrotliDecoder is vulnerable to DoS via zip bomb style attack","io.netty:netty-codec","4.1.100.Final", "4.1.125.Final",https://avd.aquasec.com/nvd/cve-2025-58057 Backport of #16887 Signed-off-by: Tomasz Gromadzki --- .gitignore | 1 + src/client/java/daos-java/pom.xml | 2 +- src/client/java/hadoop-daos/pom.xml | 2 +- utils/trivy/.trivyignore | 42 +++++++---------------------- utils/trivy/trivy.yaml | 3 ++- 5 files changed, 15 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 0960ff64e30..cdef98717dc 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,4 @@ utils/githooks/*.d/*-user-* .vscode src/include/daos_version.h utils/rpms/mock.cfg +trivy-report-daos.txt diff --git a/src/client/java/daos-java/pom.xml b/src/client/java/daos-java/pom.xml index 6b26378ac6f..b6d6b6996f3 100644 --- a/src/client/java/daos-java/pom.xml +++ b/src/client/java/daos-java/pom.xml @@ -41,7 +41,7 @@ io.netty netty-buffer - 4.1.115.Final + 4.1.125.Final com.google.code.findbugs diff --git a/src/client/java/hadoop-daos/pom.xml b/src/client/java/hadoop-daos/pom.xml index 1bba3428580..28576e3ec63 100644 --- a/src/client/java/hadoop-daos/pom.xml +++ b/src/client/java/hadoop-daos/pom.xml @@ -15,7 +15,7 @@ jar - 3.4.0 + 3.4.2 ${project.basedir}/build ${project.basedir}/install diff --git a/utils/trivy/.trivyignore b/utils/trivy/.trivyignore index 2a44fd66369..c3452b8f4fa 100644 --- a/utils/trivy/.trivyignore +++ b/utils/trivy/.trivyignore @@ -1,34 +1,12 @@ -## Ignored hadoop 3.3.6 related CVE -## CVE-2023-52428,MEDIUM,,"Denial of Service in Connect2id Nimbus JOSE+JWT","com.nimbusds:nimbus-jose-jwt","9.8.1","9.37.2",https://avd.aquasec.com/nvd/cve-2023-52428 -CVE-2023-52428 -## CVE-2023-39410,HIGH,7.5,"apache-avro: Apache Avro Java SDK: Memory when deserializing untrusted data in Avro Java SDK","org.apache.avro:avro","1.7.7","1.11.3",https://avd.aquasec.com/nvd/cve-2023-39410 -CVE-2023-39410 -## CVE-2024-25710,HIGH,5.5,"commons-compress: Denial of service caused by an infinite loop for a corrupted DUMP file","org.apache.commons:commons-compress","1.21","1.26.0",https://avd.aquasec.com/nvd/cve-2024-25710 -CVE-2024-25710 -## CVE-2024-26308,HIGH,5.5,"commons-compress: OutOfMemoryError unpacking broken Pack200 file","org.apache.commons:commons-compress","1.21","1.26.0",https://avd.aquasec.com/nvd/cve-2024-26308 -CVE-2024-26308 -## CVE-2024-29131,MEDIUM,,"commons-configuration: StackOverflowError adding property in AbstractListDelimiterHandler.flattenIterator()","org.apache.commons:commons-configuration2","2.8.0","2.10.1",https://avd.aquasec.com/nvd/cve-2024-29131 -CVE-2024-29131 -## CVE-2024-29133,MEDIUM,,"commons-configuration: StackOverflowError calling ListDelimiterHandler.flatten(Object, int) with a cyclical object tree","org.apache.commons:commons-configuration2","2.8.0","2.10.1",https://avd.aquasec.com/nvd/cve-2024-29133 -CVE-2024-29133 -## CVE-2024-25638,HIGH,,"dnsjava: Improper response validation allowing DNSSEC bypass","dnsjava:dnsjava","2.1.7","3.6.0",https://avd.aquasec.com/nvd/cve-2024-25638 -CVE-2024-25638 +### Ignored hadoop 3.4.2 related CVEs +## CVE-2025-52999,HIGH,,"com.fasterxml.jackson.core/jackson-core: jackson-core Potential StackoverflowError","com.fasterxml.jackson.core:jackson-core","2.10.2","2.15.0",https://avd.aquasec.com/nvd/cve-2025-52999 +CVE-2025-52999 -## Ignored hadoop 3.4.0 related CVE -## CVE-2024-47561,CRITICAL,,"apache-avro: Schema parsing may trigger Remote Code Execution (RCE)","org.apache.avro:avro","1.9.2","1.11.4",https://avd.aquasec.com/nvd/cve-2024-47561 -CVE-2024-47561 -## CVE-2023-33201,MEDIUM,5.3,"bouncycastle: potential blind LDAP injection attack using a self-signed certificate","org.bouncycastle:bcprov-jdk15on","1.70","",https://avd.aquasec.com/nvd/cve-2023-33201 -CVE-2023-33201 -## CVE-2024-29857,MEDIUM,,"org.bouncycastle: Importing an EC certificate with crafted F2m parameters may lead to Denial of Service","org.bouncycastle:bcprov-jdk15on","1.70","1.78",https://avd.aquasec.com/nvd/cve-2024-29857 -CVE-2024-29857 -## CVE-2024-30171,MEDIUM,,"bc-java: BouncyCastle vulnerable to a timing variant of Bleichenbacher (Marvin Attack)","org.bouncycastle:bcprov-jdk15on","1.70","1.78",https://avd.aquasec.com/nvd/cve-2024-30171 -CVE-2024-30171 -## CVE-2024-30172,MEDIUM,,"org.bouncycastle:bcprov-jdk18on: Infinite loop in ED25519 verification in the ScalarUtil class","org.bouncycastle:bcprov-jdk15on","1.70","1.78",https://avd.aquasec.com/nvd/cve-2024-30172 -CVE-2024-30172 +## CVE-2025-53864,MEDIUM,,"com.nimbusds/nimbus-jose-jwt: Uncontrolled recursion in Connect2id Nimbus JOSE + JWT","com.nimbusds:nimbus-jose-jwt","9.37.2","10.0.2",https://avd.aquasec.com/nvd/cve-2025-53864 +CVE-2025-53864 -## Ignored io.netty:netty-buffer:4.1.115.Final and hadoop-common:3.4.0 CVE -## CVE-2025-25193,MEDIUM,,"Netty, an asynchronous, event-driven network application framework, ha ...","io.netty:netty-common","4.1.115.Final","",https://avd.aquasec.com/nvd/cve-2025-25193 -CVE-2025-25193 -## Ignored hadoop 3.4.0 related CVE -## CVE-2025-24970,HIGH,,"io.netty:netty-handler: SslHandler doesn't correctly validate packets which can lead to native crash when using native SSLEngine","io.netty:netty-handler","4.1.100.Final","4.1.118.Final",https://avd.aquasec.com/nvd/cve-2025-24970 -CVE-2025-24970 +## CVE-2025-48924,MEDIUM,,"commons-lang/commons-lang: org.apache.commons/commons-lang3: Uncontrolled Recursion vulnerability in Apache Commons Lang","org.apache.commons:commons-lang3","3.12.0","3.18.0",https://avd.aquasec.com/nvd/cve-2025-48924 +CVE-2025-48924 + +## CVE-2025-58057,MEDIUM,7.5,"netty-codec: netty-codec-compression: Netty's BrotliDecoder is vulnerable to DoS via zip bomb style attack","io.netty:netty-codec","4.1.100.Final","4.1.125.Final",https://avd.aquasec.com/nvd/cve-2025-58057 +CVE-2025-58057 diff --git a/utils/trivy/trivy.yaml b/utils/trivy/trivy.yaml index c6d9974456d..5ac0b5a86c7 100644 --- a/utils/trivy/trivy.yaml +++ b/utils/trivy/trivy.yaml @@ -19,7 +19,7 @@ db: no-progress: false repository: ghcr.io/aquasecurity/trivy-db skip-update: false -debug: true +debug: false dependency-tree: true exit-code: 0 generate-default-config: false @@ -228,6 +228,7 @@ scan: # ignore all hadoop dependencies skip-dirs: ./src/client/java/hadoop-daos + ./build skip-files: [] show-suppressed: true secret: From 9a3a35579d9f4c9b1e3a9c5aebbda0d806581969 Mon Sep 17 00:00:00 2001 From: Liu Xuezhao Date: Fri, 10 Oct 2025 16:13:39 +0800 Subject: [PATCH 10/12] DAOS-17772 rebuild: refine some rebuild/EC agg/EC deg fetch process (#16928) * DAOS-17772 rebuild: refine EC agg epoch boundary process 1. add container RDB KV ds_cont_prop_ec_agg_eph for EC aggregation epoch boundary, store it when bump and load it after restart. 2. synchronize the ec agg boundary before rebuild 3. wait discard's completion in ds_pool_tgt_discard_handler() 4. fix a crt IV bug that ignored IV sync's GRP_VER err case Signed-off-by: Xuezhao Liu Signed-off-by: Wang Shilong --- src/cart/crt_iv.c | 53 ++--- src/cart/crt_rpc.h | 4 +- src/common/misc.c | 8 +- src/common/tests_lib.c | 3 +- src/container/container_iv.c | 44 +++- src/container/srv_container.c | 340 +++++++++++++++++++++++-------- src/container/srv_internal.h | 6 +- src/container/srv_layout.c | 2 + src/container/srv_layout.h | 2 + src/include/daos/common.h | 5 +- src/include/daos_srv/container.h | 6 +- src/include/daos_srv/rebuild.h | 3 +- src/object/cli_ec.c | 11 +- src/object/cli_shard.c | 10 +- src/object/srv_ec_aggregate.c | 11 +- src/object/srv_obj.c | 45 ++++ src/object/srv_obj_migrate.c | 2 +- src/pool/srv_pool.c | 4 +- src/pool/srv_target.c | 10 +- src/rebuild/srv.c | 21 +- src/vos/vos_io.c | 37 +++- 21 files changed, 478 insertions(+), 149 deletions(-) diff --git a/src/cart/crt_iv.c b/src/cart/crt_iv.c index c1d9c9e85cb..9913686e5f1 100644 --- a/src/cart/crt_iv.c +++ b/src/cart/crt_iv.c @@ -1843,11 +1843,10 @@ crt_hdlr_iv_sync_aux(void *arg) grp_ver = ivns_internal->cii_grp_priv->gp_membs_ver; D_RWLOCK_UNLOCK(&ivns_internal->cii_grp_priv->gp_rwlock); if (grp_ver != input->ivs_grp_ver) { - D_DEBUG(DB_ALL, - "Group (%s) version mismatch. Local: %d Remote :%d\n", - ivns_id.ii_group_name, grp_ver, - input->ivs_grp_ver); - D_GOTO(exit, rc = -DER_GRPVER); + rc = -DER_GRPVER; + DL_INFO(rc, "Group (%s) version mismatch. Local: %d Remote :%d", + ivns_id.ii_group_name, grp_ver, input->ivs_grp_ver); + goto exit; } iv_ops = crt_iv_ops_get(ivns_internal, input->ivs_class_id); @@ -1922,7 +1921,7 @@ crt_hdlr_iv_sync_aux(void *arg) if (need_put && iv_ops) iv_ops->ivo_on_put(ivns_internal, NULL, user_priv); - output->rc = rc; + output->ivs_rc = rc; crt_reply_send(rpc_req); /* ADDREF done in lookup above */ @@ -2002,7 +2001,7 @@ crt_hdlr_iv_sync(crt_rpc_t *rpc_req) IVNS_DECREF(ivns_internal); return; exit: - output->rc = rc; + output->ivs_rc = rc; crt_reply_send(rpc_req); if (ivns_internal) { @@ -2022,9 +2021,9 @@ crt_iv_sync_corpc_aggregate(crt_rpc_t *source, crt_rpc_t *result, void *arg) output_result = crt_reply_get(result); /* Only set new rc if so far rc is 0 */ - if (output_result->rc == 0) { - if (output_source->rc != 0) - output_result->rc = output_source->rc; + if (output_result->ivs_rc == 0) { + if (output_source->ivs_rc != 0) + output_result->ivs_rc = output_source->ivs_rc; } return 0; @@ -2163,14 +2162,16 @@ handle_ivsync_response(const struct crt_cb_info *cb_info) { struct iv_sync_cb_info *iv_sync = cb_info->cci_arg; struct crt_iv_ops *iv_ops; + crt_rpc_t *rpc = cb_info->cci_rpc; + struct crt_iv_sync_out *output = crt_reply_get(rpc); if (iv_sync->isc_bulk_hdl != CRT_BULK_NULL) crt_bulk_free(iv_sync->isc_bulk_hdl); /* do_callback is set based on sync value specified */ if (iv_sync->isc_do_callback) { - if (cb_info->cci_rc != 0) - iv_sync->isc_update_rc = cb_info->cci_rc; + if (cb_info->cci_rc || output->ivs_rc) + iv_sync->isc_update_rc = cb_info->cci_rc ? cb_info->cci_rc : output->ivs_rc; iv_sync->isc_update_comp_cb(iv_sync->isc_ivns_internal, iv_sync->isc_class_id, @@ -2412,7 +2413,7 @@ finalize_transfer_back(struct update_cb_info *cb_info, int rc) struct crt_iv_update_out *child_output; child_output = crt_reply_get(cb_info->uci_child_rpc); - child_output->rc = rc; + child_output->ivo_rc = rc; ivns = cb_info->uci_ivns_internal; crt_reply_send(cb_info->uci_child_rpc); @@ -2528,15 +2529,15 @@ handle_ivupdate_response(const struct crt_cb_info *cb_info) if (iv_info->uci_bulk_hdl == CRT_BULK_NULL) d_sgl_buf_copy(&iv_info->uci_iv_value, &output->ivo_iv_sgl); iv_ops->ivo_on_refresh(iv_info->uci_ivns_internal, &input->ivu_key, 0, - &iv_info->uci_iv_value, false, cb_info->cci_rc ?: output->rc, - iv_info->uci_user_priv); + &iv_info->uci_iv_value, false, + cb_info->cci_rc ?: output->ivo_rc, iv_info->uci_user_priv); if (input->ivu_iv_value_bulk == CRT_BULK_NULL && iv_info->uci_child_rpc != NULL) { child_output = crt_reply_get(iv_info->uci_child_rpc); child_output->ivo_iv_sgl = iv_info->uci_iv_value; } - transfer_back_to_child(&input->ivu_key, iv_info, cb_info->cci_rc ?: output->rc); + transfer_back_to_child(&input->ivu_key, iv_info, cb_info->cci_rc ?: output->ivo_rc); D_GOTO(exit, 0); } @@ -2549,10 +2550,10 @@ handle_ivupdate_response(const struct crt_cb_info *cb_info) iv_ops->ivo_on_put(iv_info->uci_ivns_internal, &iv_info->uci_iv_value, iv_info->uci_user_priv); - child_output->rc = output->rc; + child_output->ivo_rc = output->ivo_rc; if (cb_info->cci_rc != 0) - child_output->rc = cb_info->cci_rc; + child_output->ivo_rc = cb_info->cci_rc; /* Respond back to child; might fail if child is not alive */ if (crt_reply_send(iv_info->uci_child_rpc) != DER_SUCCESS) @@ -2568,7 +2569,7 @@ handle_ivupdate_response(const struct crt_cb_info *cb_info) else tmp_iv_value = &iv_info->uci_iv_value; - rc = output->rc; + rc = output->ivo_rc; if (cb_info->cci_rc != 0) rc = cb_info->cci_rc; @@ -2897,7 +2898,7 @@ bulk_update_transfer_done_aux(const struct crt_bulk_cb_info *info) D_GOTO(exit, rc); } rc = crt_bulk_free(cb_info->buc_bulk_hdl); - output->rc = rc; + output->ivo_rc = rc; iv_ops->ivo_on_put(ivns_internal, &cb_info->buc_iv_value, cb_info->buc_user_priv); crt_reply_send(info->bci_bulk_desc->bd_rpc); @@ -2913,7 +2914,7 @@ bulk_update_transfer_done_aux(const struct crt_bulk_cb_info *info) send_error: /* send back whatever error got us here */ - output->rc = rc; + output->ivo_rc = rc; rc = crt_bulk_free(cb_info->buc_bulk_hdl); if (rc != 0) DL_ERROR(rc, "crt_bulk_free() failed"); @@ -3016,7 +3017,7 @@ bulk_update_transfer_done(const struct crt_bulk_cb_info *info) return rc; send_error: - output->rc = rc; + output->ivo_rc = rc; crt_reply_send(info->bci_bulk_desc->bd_rpc); crt_bulk_free(cb_info->buc_bulk_hdl); @@ -3121,7 +3122,7 @@ crt_iv_update_inline_hdlr(crt_rpc_t *rpc, struct crt_ivns_internal *ivns_interna D_GOTO(exit, rc); } } else if (rc == 0) { - output->rc = rc; + output->ivo_rc = rc; crt_reply_send(rpc); iv_ops->ivo_on_put(ivns_internal, &iv_value, user_priv); } else { @@ -3136,7 +3137,7 @@ crt_iv_update_inline_hdlr(crt_rpc_t *rpc, struct crt_ivns_internal *ivns_interna iv_ops->ivo_on_put(ivns_internal, &iv_value, user_priv); send_error: - output->rc = rc; + output->ivo_rc = rc; crt_reply_send(rpc); if (update_cb_info) D_FREE(update_cb_info); @@ -3270,7 +3271,7 @@ crt_hdlr_iv_update(crt_rpc_t *rpc_req) } } else if (rc == 0) { - output->rc = rc; + output->ivo_rc = rc; rc = crt_reply_send(rpc_req); } else { D_GOTO(send_error, rc); @@ -3340,7 +3341,7 @@ crt_hdlr_iv_update(crt_rpc_t *rpc_req) return; send_error: - output->rc = rc; + output->ivo_rc = rc; crt_reply_send(rpc_req); if (put_needed) diff --git a/src/cart/crt_rpc.h b/src/cart/crt_rpc.h index 654d602fc95..496e15ff164 100644 --- a/src/cart/crt_rpc.h +++ b/src/cart/crt_rpc.h @@ -511,7 +511,7 @@ CRT_RPC_DECLARE(crt_iv_fetch, CRT_ISEQ_IV_FETCH, CRT_OSEQ_IV_FETCH) ((uint32_t) (padding) CRT_VAR) #define CRT_OSEQ_IV_UPDATE /* output fields */ \ - ((uint64_t) (rc) CRT_VAR) \ + ((uint64_t) (ivo_rc) CRT_VAR) \ ((d_sg_list_t) (ivo_iv_sgl) CRT_VAR) CRT_RPC_DECLARE(crt_iv_update, CRT_ISEQ_IV_UPDATE, CRT_OSEQ_IV_UPDATE) @@ -530,7 +530,7 @@ CRT_RPC_DECLARE(crt_iv_update, CRT_ISEQ_IV_UPDATE, CRT_OSEQ_IV_UPDATE) ((uint32_t) (ivs_class_id) CRT_VAR) \ #define CRT_OSEQ_IV_SYNC /* output fields */ \ - ((int32_t) (rc) CRT_VAR) + ((int32_t) (ivs_rc) CRT_VAR) CRT_RPC_DECLARE(crt_iv_sync, CRT_ISEQ_IV_SYNC, CRT_OSEQ_IV_SYNC) diff --git a/src/common/misc.c b/src/common/misc.c index 195e004e8bb..12b6d6c788d 100644 --- a/src/common/misc.c +++ b/src/common/misc.c @@ -219,15 +219,17 @@ daos_sgl_merge(d_sg_list_t *dst, d_sg_list_t *src) } daos_size_t -daos_sgl_data_len(d_sg_list_t *sgl) +daos_sgl_data_len(d_sg_list_t *sgl, bool out) { daos_size_t len; - int i; + uint32_t sg_nr; + uint32_t i; if (sgl == NULL || sgl->sg_iovs == NULL) return 0; - for (i = 0, len = 0; i < sgl->sg_nr; i++) + sg_nr = out ? sgl->sg_nr_out : sgl->sg_nr; + for (i = 0, len = 0; i < sg_nr; i++) len += sgl->sg_iovs[i].iov_len; return len; diff --git a/src/common/tests_lib.c b/src/common/tests_lib.c index 9cb2ebbcb95..7ee661f4c6a 100644 --- a/src/common/tests_lib.c +++ b/src/common/tests_lib.c @@ -1,5 +1,6 @@ /** * (C) Copyright 2015-2022 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -279,7 +280,7 @@ td_init(struct test_data *td, uint32_t iod_nr, struct td_init_args args) /* Initialize and create some data */ dts_sgl_generate(sgl, 1, args.ca_data_size, 0xAB); - D_ASSERT(daos_sgl_data_len(sgl) == data_len); + D_ASSERT(daos_sgl_data_len(sgl, false) == data_len); iod->iod_type = iod_types[i]; dts_iov_alloc_str(&iod->iod_name, "akey"); diff --git a/src/container/container_iv.c b/src/container/container_iv.c index 43d024d02a5..a063c685b9c 100644 --- a/src/container/container_iv.c +++ b/src/container/container_iv.c @@ -449,6 +449,7 @@ cont_iv_ent_fetch(struct ds_iv_entry *entry, struct ds_iv_key *key, d_sg_list_t *dst, void **priv) { struct cont_iv_entry *src_iv; + struct cont_iv_entry iv_entry = {0}; daos_handle_t root_hdl; d_iov_t key_iov; d_iov_t val_iov; @@ -496,7 +497,6 @@ cont_iv_ent_fetch(struct ds_iv_entry *entry, struct ds_iv_key *key, rc1 = ds_cont_hdl_rdb_lookup(entry->ns->iv_pool_uuid, civ_key->cont_uuid, &chdl); if (rc1 == 0) { - struct cont_iv_entry iv_entry = { 0 }; daos_prop_t *prop = NULL; struct daos_prop_entry *prop_entry; struct daos_co_status stat = { 0 }; @@ -546,8 +546,38 @@ cont_iv_ent_fetch(struct ds_iv_entry *entry, struct ds_iv_key *key, } else { rc = -DER_NONEXIST; } + } else if (class_id == IV_CONT_AGG_EPOCH_BOUNDRY) { + uint64_t ec_agg_eph; + + rc = ds_cont_ec_agg_eph_rdb_lookup(entry->ns->iv_pool_uuid, + civ_key->cont_uuid, &ec_agg_eph); + if (rc == 0) { + uuid_copy(iv_entry.cont_uuid, civ_key->cont_uuid); + iv_entry.iv_agg_eph.eph = ec_agg_eph; + iv_entry.iv_agg_eph.rank = dss_self_rank(); + d_iov_set(&val_iov, &iv_entry, sizeof(iv_entry)); + rc = dbtree_update(root_hdl, &key_iov, &val_iov); + DL_CDEBUG( + rc != 0, DLOG_ERR, DB_MD, rc, + DF_CONT ": dbtree_update ec_agg_eph " DF_X64, + DP_CONT(entry->ns->iv_pool_uuid, civ_key->cont_uuid), + ec_agg_eph); + if (rc) + goto failed; + /* on master node will not trigger on_refresh callback, + * so need to explicitly refresh its own cont child's + * sc_ec_agg_eph_boundary especially for the case of + * restart that the value is zero. + */ + rc = ds_cont_tgt_refresh_agg_eph(entry->ns->iv_pool_uuid, + civ_key->cont_uuid, + ec_agg_eph); + if (rc == 0) + goto again; + } } } +failed: D_DEBUG(DB_MGMT, DF_CONT "lookup cont: rc " DF_RC "\n", DP_CONT(entry->ns->iv_pool_uuid, civ_key->cont_uuid), DP_RC(rc)); D_GOTO(out, rc); @@ -653,8 +683,15 @@ cont_iv_ent_update(struct ds_iv_entry *entry, struct ds_iv_key *key, } else if (entry->iv_class->iv_class_id == IV_CONT_AGG_EPOCH_BOUNDRY) { rc = cont_iv_ent_agg_eph_refresh(entry, key, src); - if (rc) + if (rc) { + if (rc == -DER_NONEXIST) { + DL_INFO( + rc, DF_CONT " cont_iv_ent_agg_eph_refresh ignore", + DP_CONT(entry->ns->iv_pool_uuid, civ_key->cont_uuid)); + rc = 0; + } D_GOTO(out, rc); + } } } @@ -1116,8 +1153,7 @@ cont_iv_ec_agg_eph_update(void *ns, uuid_t cont_uuid, daos_epoch_t eph) int cont_iv_ec_agg_eph_refresh(void *ns, uuid_t cont_uuid, daos_epoch_t eph) { - return cont_iv_ec_agg_eph_update_internal(ns, cont_uuid, eph, - 0, CRT_IV_SYNC_LAZY, + return cont_iv_ec_agg_eph_update_internal(ns, cont_uuid, eph, 0, CRT_IV_SYNC_EAGER, IV_CONT_AGG_EPOCH_BOUNDRY); } diff --git a/src/container/srv_container.c b/src/container/srv_container.c index 7f15a275b5d..0971752888e 100644 --- a/src/container/srv_container.c +++ b/src/container/srv_container.c @@ -1691,6 +1691,7 @@ cont_ec_agg_alloc(struct cont_svc *cont_svc, uuid_t cont_uuid, uuid_copy(ec_agg->ea_cont_uuid, cont_uuid); ec_agg->ea_servers_num = rank_nr; ec_agg->ea_current_eph = 0; + ec_agg->ea_rdb_eph = 0; for (i = 0; i < rank_nr; i++) { ec_agg->ea_server_ephs[i].rank = doms[i].do_comp.co_rank; ec_agg->ea_server_ephs[i].eph = 0; @@ -1805,6 +1806,7 @@ cont_refresh_vos_agg_eph_one(void *data) if (cont_child->sc_ec_agg_eph_boundary < arg->min_eph) cont_child->sc_ec_agg_eph_boundary = arg->min_eph; + cont_child->sc_ec_agg_eph_valid = 1; ds_cont_child_put(cont_child); return rc; } @@ -1814,6 +1816,8 @@ ds_cont_tgt_refresh_agg_eph(uuid_t pool_uuid, uuid_t cont_uuid, daos_epoch_t eph) { struct refresh_vos_agg_eph_arg arg; + static uint64_t cnt; + static uint64_t gap = 1; int rc; uuid_copy(arg.pool_uuid, pool_uuid); @@ -1823,116 +1827,286 @@ ds_cont_tgt_refresh_agg_eph(uuid_t pool_uuid, uuid_t cont_uuid, rc = ds_pool_task_collective(pool_uuid, PO_COMP_ST_NEW | PO_COMP_ST_DOWN | PO_COMP_ST_DOWNOUT, cont_refresh_vos_agg_eph_one, &arg, DSS_ULT_FL_PERIODIC); + if (rc) { + DL_ERROR(rc, DF_CONT ": refresh ec_agg_eph " DF_X64 " failed.", + DP_CONT(pool_uuid, cont_uuid), eph); + } else { + if (cnt++ % gap == 0) { + D_INFO(DF_CONT ": refresh ec_agg_eph " DF_X64, + DP_CONT(pool_uuid, cont_uuid), eph); + if (gap <= 256) + gap <<= 1; + } else { + D_DEBUG(DB_MD, DF_CONT ": refresh ec_agg_eph " DF_X64, + DP_CONT(pool_uuid, cont_uuid), eph); + } + } return rc; } -#define EC_AGG_EPH_INTV (10ULL * 1000) /* seconds interval to check*/ -static void -cont_agg_eph_leader_ult(void *arg) +static int +cont_agg_eph_load(struct cont_svc *svc, uuid_t cont_uuid, uint64_t *ec_agg_eph) { - struct cont_svc *svc = arg; - struct ds_pool *pool = svc->cs_pool; - struct cont_ec_agg *ec_agg; - struct cont_ec_agg *tmp; - uint64_t cur_eph, new_eph; - int rc = 0; + struct rdb_tx tx; + struct cont *cont = NULL; + uint64_t agg_eph; + d_iov_t value; + int rc; - if (svc->cs_ec_leader_ephs_req == NULL) + D_ASSERT(dss_get_module_info()->dmi_xs_id == 0); + rc = rdb_tx_begin(svc->cs_rsvc->s_db, svc->cs_rsvc->s_term, &tx); + if (rc != 0) { + DL_CDEBUG(rc != -DER_NOTLEADER, DLOG_ERR, DB_MD, rc, + DF_CONT ": Failed to start rdb tx.", + DP_CONT(svc->cs_pool_uuid, cont_uuid)); + return rc; + } + + ABT_rwlock_rdlock(svc->cs_lock); + rc = cont_lookup(&tx, svc, cont_uuid, &cont); + if (rc != 0) { + D_ERROR(DF_CONT ": Failed to look container: %d\n", + DP_CONT(svc->cs_pool_uuid, cont_uuid), rc); + D_GOTO(out_lock, rc); + } + + d_iov_set(&value, &agg_eph, sizeof(agg_eph)); + rc = rdb_tx_lookup(&tx, &cont->c_prop, &ds_cont_prop_ec_agg_eph, &value); + DL_CDEBUG(rc != 0 && rc != -DER_NONEXIST && rc != -DER_NOTLEADER, DLOG_ERR, DB_MD, rc, + DF_CONT ": rdb_tx_lookup ec_agg_eph " DF_X64, + DP_CONT(svc->cs_pool_uuid, cont_uuid), agg_eph); + if (rc == -DER_NONEXIST) { + agg_eph = 0; + rc = 0; + } + if (rc == 0) + *ec_agg_eph = agg_eph; + cont_put(cont); + +out_lock: + ABT_rwlock_unlock(svc->cs_lock); + rdb_tx_end(&tx); + return rc; +} + +int +ds_cont_ec_agg_eph_rdb_lookup(uuid_t pool_uuid, uuid_t cont_uuid, uint64_t *ec_agg_eph) +{ + struct cont_svc *svc; + int rc; + + rc = cont_svc_lookup_leader(pool_uuid, 0 /* id */, &svc, NULL); + if (rc != 0) { + DL_ERROR(rc, DF_CONT ": find leader failed.", DP_CONT(pool_uuid, cont_uuid)); + return rc; + } + + rc = cont_agg_eph_load(svc, cont_uuid, ec_agg_eph); + cont_svc_put_leader(svc); + if (rc) + DL_ERROR(rc, DF_CONT ": cont_agg_eph_load failed.", DP_CONT(pool_uuid, cont_uuid)); + return rc; +} + +static int +cont_agg_eph_store(struct cont_svc *svc, uuid_t cont_uuid, uint64_t ec_agg_eph, uint64_t *rdb_eph) +{ + struct rdb_tx tx; + struct cont *cont = NULL; + d_iov_t value; + uint64_t old_eph; + int rc; + + D_ASSERT(dss_get_module_info()->dmi_xs_id == 0); + rc = rdb_tx_begin(svc->cs_rsvc->s_db, svc->cs_rsvc->s_term, &tx); + if (rc != 0) { + DL_CDEBUG(rc != -DER_NOTLEADER, DLOG_ERR, DB_MD, rc, + DF_CONT ": Failed to start rdb tx.", + DP_CONT(svc->cs_pool_uuid, cont_uuid)); + return rc; + } + + ABT_rwlock_wrlock(svc->cs_lock); + rc = cont_lookup(&tx, svc, cont_uuid, &cont); + if (rc != 0) { + D_ERROR(DF_CONT ": Failed to look container: %d\n", + DP_CONT(svc->cs_pool_uuid, cont_uuid), rc); + D_GOTO(out_lock, rc); + } + + d_iov_set(&value, &old_eph, sizeof(old_eph)); + rc = rdb_tx_lookup(&tx, &cont->c_prop, &ds_cont_prop_ec_agg_eph, &value); + if (rc == -DER_NONEXIST) { + rc = 0; + old_eph = 0; + } + if (rc != 0) goto out; - while (!dss_ult_exiting(svc->cs_ec_leader_ephs_req)) { - d_rank_list_t fail_ranks = { 0 }; + *rdb_eph = old_eph; + if (ec_agg_eph > old_eph) { + d_iov_set(&value, &ec_agg_eph, sizeof(ec_agg_eph)); + rc = rdb_tx_update(&tx, &cont->c_prop, &ds_cont_prop_ec_agg_eph, &value); + if (rc == 0) + rc = rdb_tx_commit(&tx); + if (rc == 0) + *rdb_eph = ec_agg_eph; + } else { + D_DEBUG(DB_MD, + DF_CONT ": bypass rdb update ec_agg_eph " DF_X64 ", in rdb eph " DF_X64, + DP_CONT(svc->cs_pool_uuid, cont_uuid), ec_agg_eph, old_eph); + } + +out: + DL_CDEBUG(rc != 0 && rc != -DER_NOTLEADER, DLOG_ERR, DB_MD, rc, + DF_CONT ": rdb_tx_update ec_agg_eph " DF_X64, + DP_CONT(svc->cs_pool_uuid, cont_uuid), ec_agg_eph); + cont_put(cont); +out_lock: + ABT_rwlock_unlock(svc->cs_lock); + rdb_tx_end(&tx); + return rc; +} - if (pool->sp_rebuilding) { - D_DEBUG(DB_MD, DF_UUID "skip during rebuilding.\n", - DP_UUID(pool->sp_uuid)); - goto yield; +static void +cont_agg_eph_sync(struct ds_pool *pool, struct cont_svc *svc) +{ + d_rank_list_t fail_ranks = {0}; + struct cont_ec_agg *ec_agg; + struct cont_ec_agg *tmp; + daos_epoch_t cur_eph, new_eph; + daos_epoch_t min_eph; + d_rank_t rank; + int i; + int rc; + + rc = map_ranks_init(pool->sp_map, PO_COMP_ST_DOWNOUT | PO_COMP_ST_DOWN, &fail_ranks); + if (rc) { + D_ERROR(DF_UUID ": ranks init failed: %d\n", DP_UUID(pool->sp_uuid), rc); + return; + } + + d_list_for_each_entry_safe(ec_agg, tmp, &svc->cs_ec_agg_list, ea_list) { + if (ec_agg->ea_deleted) { + d_list_del(&ec_agg->ea_list); + D_FREE(ec_agg->ea_server_ephs); + D_FREE(ec_agg); + continue; } - rc = map_ranks_init(pool->sp_map, PO_COMP_ST_DOWNOUT | PO_COMP_ST_DOWN, - &fail_ranks); - if (rc) { - D_ERROR(DF_UUID": ranks init failed: %d\n", - DP_UUID(pool->sp_uuid), rc); - goto yield; + if (ec_agg->ea_rdb_eph == 0) { + rc = cont_agg_eph_load(svc, ec_agg->ea_cont_uuid, &ec_agg->ea_rdb_eph); + if (rc) + DL_ERROR(rc, DF_CONT ": cont_agg_eph_load failed.", + DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid)); } - d_list_for_each_entry_safe(ec_agg, tmp, &svc->cs_ec_agg_list, ea_list) { - daos_epoch_t min_eph = DAOS_EPOCH_MAX; - int i; + min_eph = DAOS_EPOCH_MAX; + for (i = 0; i < ec_agg->ea_servers_num; i++) { + rank = ec_agg->ea_server_ephs[i].rank; - if (ec_agg->ea_deleted) { - d_list_del(&ec_agg->ea_list); - D_FREE(ec_agg->ea_server_ephs); - D_FREE(ec_agg); + if (d_rank_in_rank_list(&fail_ranks, rank)) { + D_DEBUG(DB_MD, DF_CONT " skip %u\n", + DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid), rank); continue; } - for (i = 0; i < ec_agg->ea_servers_num; i++) { - d_rank_t rank = ec_agg->ea_server_ephs[i].rank; + if (ec_agg->ea_server_ephs[i].eph < min_eph) + min_eph = ec_agg->ea_server_ephs[i].eph; + } - if (d_rank_in_rank_list(&fail_ranks, rank)) { - D_DEBUG(DB_MD, DF_CONT" skip %u\n", - DP_CONT(svc->cs_pool_uuid, - ec_agg->ea_cont_uuid), - rank); - continue; - } + /* for reboot case the ea_rdb_eph possibly higher than min_eph */ + if (min_eph < ec_agg->ea_rdb_eph) + min_eph = ec_agg->ea_rdb_eph; - if (ec_agg->ea_server_ephs[i].eph < min_eph) - min_eph = ec_agg->ea_server_ephs[i].eph; - } + if (min_eph == ec_agg->ea_current_eph) + continue; - if (min_eph == ec_agg->ea_current_eph) - continue; + /** + * NB: during extending or reintegration, the new + * server might cause the minimum epoch is less than + * ea_current_eph. + */ + D_DEBUG(DB_MD, DF_CONT " minimum " DF_U64 " current " DF_X64 "\n", + DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid), min_eph, + ec_agg->ea_current_eph); + + cur_eph = d_hlc2sec(ec_agg->ea_current_eph); + new_eph = d_hlc2sec(min_eph); + if (cur_eph && new_eph > cur_eph && (new_eph - cur_eph) >= 600) + D_WARN(DF_CONT ": Sluggish EC boundary reporting. " + "cur:" DF_U64 " new:" DF_U64 " gap:" DF_U64 "\n", + DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid), cur_eph, new_eph, + new_eph - cur_eph); + + if (min_eph > ec_agg->ea_rdb_eph) { + rc = cont_agg_eph_store(svc, ec_agg->ea_cont_uuid, min_eph, + &ec_agg->ea_rdb_eph); + if (rc) + DL_ERROR(rc, + DF_CONT ": rdb_tx_update ec_agg_eph " DF_X64 " failed.", + DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid), min_eph); + } - /** - * NB: during extending or reintegration, the new - * server might cause the minimum epoch is less than - * ea_current_eph. - */ - D_DEBUG(DB_MD, DF_CONT" minimum "DF_U64" current "DF_X64"\n", - DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid), - min_eph, ec_agg->ea_current_eph); - - cur_eph = d_hlc2sec(ec_agg->ea_current_eph); - new_eph = d_hlc2sec(min_eph); - if (cur_eph && new_eph > cur_eph && (new_eph - cur_eph) >= 600) - D_WARN(DF_CONT": Sluggish EC boundary reporting. " - "cur:"DF_U64" new:"DF_U64" gap:"DF_U64"\n", - DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid), - cur_eph, new_eph, new_eph - cur_eph); - - rc = cont_iv_ec_agg_eph_refresh(pool->sp_iv_ns, - ec_agg->ea_cont_uuid, - min_eph); - if (rc) { - DL_CDEBUG(rc == -DER_NONEXIST, DLOG_INFO, DLOG_ERR, rc, - DF_CONT ": refresh failed", - DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid)); - - /* If there are network error or pool map inconsistency, - * let's skip the following eph sync, which will fail - * anyway. - */ - if (daos_crt_network_error(rc) || rc == -DER_GRPVER) { - D_INFO(DF_UUID": skip refresh due to: "DF_RC"\n", - DP_UUID(svc->cs_pool_uuid), DP_RC(rc)); - break; - } + rc = cont_iv_ec_agg_eph_refresh(pool->sp_iv_ns, ec_agg->ea_cont_uuid, min_eph); + if (rc) { + DL_CDEBUG(rc == -DER_NONEXIST, DLOG_INFO, DLOG_ERR, rc, + DF_CONT ": refresh failed", + DP_CONT(svc->cs_pool_uuid, ec_agg->ea_cont_uuid)); - continue; - } - ec_agg->ea_current_eph = min_eph; - if (pool->sp_rebuilding) + /* If there are network error or pool map inconsistency, + * let's skip the following eph sync, which will fail + * anyway. + */ + if (daos_crt_network_error(rc) || rc == -DER_GRPVER) { + D_INFO(DF_UUID ": skip refresh due to: " DF_RC "\n", + DP_UUID(svc->cs_pool_uuid), DP_RC(rc)); break; + } + + continue; } + ec_agg->ea_current_eph = min_eph; + } - map_ranks_fini(&fail_ranks); + map_ranks_fini(&fail_ranks); +} + +int +ds_cont_svc_refresh_agg_eph(uuid_t pool_uuid) +{ + struct cont_svc *svc; + int rc; + + rc = cont_svc_lookup_leader(pool_uuid, 0 /* id */, &svc, NULL /* hint */); + if (rc != 0) + return rc; + + cont_agg_eph_sync(svc->cs_pool, svc); + + cont_svc_put_leader(svc); + return 0; +} + +#define EC_AGG_EPH_INTV (10ULL * 1000) /* seconds interval to check*/ +static void +cont_agg_eph_leader_ult(void *arg) +{ + struct cont_svc *svc = arg; + struct ds_pool *pool = svc->cs_pool; + struct cont_ec_agg *ec_agg; + struct cont_ec_agg *tmp; + int rc = 0; + + if (svc->cs_ec_leader_ephs_req == NULL) + goto out; + + while (!dss_ult_exiting(svc->cs_ec_leader_ephs_req)) { + cont_agg_eph_sync(pool, svc); if (dss_ult_exiting(svc->cs_ec_leader_ephs_req)) break; -yield: + sched_req_sleep(svc->cs_ec_leader_ephs_req, EC_AGG_EPH_INTV); } diff --git a/src/container/srv_internal.h b/src/container/srv_internal.h index ae5e5ec8a75..bb257a73212 100644 --- a/src/container/srv_internal.h +++ b/src/container/srv_internal.h @@ -67,10 +67,11 @@ struct ec_eph { struct cont_ec_agg { uuid_t ea_cont_uuid; daos_epoch_t ea_current_eph; + daos_epoch_t ea_rdb_eph; struct ec_eph *ea_server_ephs; d_list_t ea_list; int ea_servers_num; - uint32_t ea_deleted:1; + uint32_t ea_deleted : 1; }; /* @@ -310,4 +311,7 @@ int cont_child_gather_oids(struct ds_cont_child *cont, uuid_t coh_uuid, int ds_cont_hdl_rdb_lookup(uuid_t pool_uuid, uuid_t cont_hdl_uuid, struct container_hdl *chdl); +int +ds_cont_ec_agg_eph_rdb_lookup(uuid_t pool_uuid, uuid_t cont_uuid, uint64_t *ec_agg_eph); + #endif /* __CONTAINER_SRV_INTERNAL_H__ */ diff --git a/src/container/srv_layout.c b/src/container/srv_layout.c index 35bb16e0b71..ae1b16b3ae2 100644 --- a/src/container/srv_layout.c +++ b/src/container/srv_layout.c @@ -1,5 +1,6 @@ /** * (C) Copyright 2017-2023 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -54,6 +55,7 @@ RDB_STRING_KEY(ds_cont_prop_, scrubber_disabled); RDB_STRING_KEY(ds_cont_prop_, co_md_times); RDB_STRING_KEY(ds_cont_prop_, cont_obj_version); RDB_STRING_KEY(ds_cont_prop_, nhandles); +RDB_STRING_KEY(ds_cont_prop_, ec_agg_eph); /* dummy value for container roots, avoid malloc on demand */ static struct daos_prop_co_roots dummy_roots; diff --git a/src/container/srv_layout.h b/src/container/srv_layout.h index d4f2622aba2..7f10d948368 100644 --- a/src/container/srv_layout.h +++ b/src/container/srv_layout.h @@ -1,5 +1,6 @@ /* * (C) Copyright 2016-2023 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -137,6 +138,7 @@ extern d_iov_t ds_cont_prop_co_md_times; /* co_md_times */ extern d_iov_t ds_cont_prop_cont_obj_version; /* uint32_t */ extern d_iov_t ds_cont_prop_nhandles; /* uint32_t */ extern d_iov_t ds_cont_prop_oit_oids; /* snapshot OIT OID KVS */ +extern d_iov_t ds_cont_prop_ec_agg_eph; /* uint64_t */ /* Please read the IMPORTANT notes above before adding new keys. */ struct co_md_times { diff --git a/src/include/daos/common.h b/src/include/daos/common.h index f81b071a25f..b40f94ae5c4 100644 --- a/src/include/daos/common.h +++ b/src/include/daos/common.h @@ -387,7 +387,10 @@ int daos_sgl_copy_data(d_sg_list_t *dst, d_sg_list_t *src); int daos_sgl_alloc_copy_data(d_sg_list_t *dst, d_sg_list_t *src); int daos_sgls_alloc(d_sg_list_t *dst, d_sg_list_t *src, int nr); int daos_sgl_merge(d_sg_list_t *dst, d_sg_list_t *src); -daos_size_t daos_sgl_data_len(d_sg_list_t *sgl); +daos_size_t +daos_sgl_data_len(d_sg_list_t *sgl, bool out); +daos_size_t + daos_sgl_out_data_len(d_sg_list_t *sgl); daos_size_t daos_sgl_buf_size(d_sg_list_t *sgl); daos_size_t daos_sgls_buf_size(d_sg_list_t *sgls, int nr); daos_size_t daos_sgls_packed_size(d_sg_list_t *sgls, int nr, diff --git a/src/include/daos_srv/container.h b/src/include/daos_srv/container.h index 02f90794c9f..0853196b1f8 100644 --- a/src/include/daos_srv/container.h +++ b/src/include/daos_srv/container.h @@ -36,6 +36,8 @@ void ds_cont_svc_step_down(struct cont_svc *svc); int ds_cont_svc_set_prop(uuid_t pool_uuid, const char *cont_id, d_rank_list_t *ranks, daos_prop_t *prop); +int + ds_cont_svc_refresh_agg_eph(uuid_t pool_uuid); int ds_cont_list(uuid_t pool_uuid, struct daos_pool_cont_info **conts, uint64_t *ncont); int ds_cont_filter(uuid_t pool_uuid, daos_pool_cont_filter_t *filt, struct daos_pool_cont_info2 **conts, uint64_t *ncont); @@ -71,7 +73,9 @@ struct ds_cont_child { sc_dtx_delay_reset : 1, sc_dtx_registered : 1, sc_props_fetched : 1, sc_stopping : 1, sc_destroying : 1, sc_vos_agg_active : 1, sc_ec_agg_active : 1, /* flag of CONT_CAPA_READ_DATA/_WRITE_DATA disabled */ - sc_rw_disabled : 1, sc_scrubbing : 1, sc_rebuilding : 1; + sc_rw_disabled : 1, sc_scrubbing : 1, sc_rebuilding : 1, + /* flag of sc_ec_agg_eph_boundary valid */ + sc_ec_agg_eph_valid : 1; /* Tracks the schedule request for aggregation ULT */ struct sched_request *sc_agg_req; diff --git a/src/include/daos_srv/rebuild.h b/src/include/daos_srv/rebuild.h index 938a047feaa..bbf7abac479 100644 --- a/src/include/daos_srv/rebuild.h +++ b/src/include/daos_srv/rebuild.h @@ -71,7 +71,8 @@ int ds_rebuild_query(uuid_t pool_uuid, struct daos_rebuild_status *status); void ds_rebuild_running_query(uuid_t pool_uuid, uint32_t opc, uint32_t *rebuild_ver, daos_epoch_t *current_eph, uint32_t *rebuild_gen); -int ds_rebuild_regenerate_task(struct ds_pool *pool, daos_prop_t *prop); +int + ds_rebuild_regenerate_task(struct ds_pool *pool, daos_prop_t *prop, uint64_t delay_sec); void ds_rebuild_leader_stop_all(void); void ds_rebuild_abort(uuid_t pool_uuid, unsigned int version, uint32_t rebuild_gen, uint64_t term); diff --git a/src/object/cli_ec.c b/src/object/cli_ec.c index 2a6ee7409f2..73897d51abe 100644 --- a/src/object/cli_ec.c +++ b/src/object/cli_ec.c @@ -1885,7 +1885,9 @@ obj_ec_fetch_set_sgl(struct dc_object *obj, struct obj_reasb_req *reasb_req, uiod = &uiods[i]; riod = &riods[i]; usgl = &usgls[i]; - usgl->sg_nr_out = 0; + /* for data recovery case, the sg_nr_out possibly already set by obj_ec_sgl_copy */ + if (!reasb_req->orr_recov_data) + usgl->sg_nr_out = 0; tail_hole_size = 0; size_in_iod = daos_iods_len(uiod, 1); if (uiod->iod_size == 0) @@ -1933,7 +1935,7 @@ obj_ec_fetch_set_sgl(struct dc_object *obj, struct obj_reasb_req *reasb_req, * is set by obj_ec_recov_fill_back(). */ if (!reasb_req->orr_recov_data || - (size_in_iod - tail_hole_size) > daos_sgl_data_len(usgl)) + (size_in_iod - tail_hole_size) > daos_sgl_data_len(usgl, true)) dc_sgl_out_set(usgl, size_in_iod - tail_hole_size); return; @@ -2677,6 +2679,11 @@ obj_ec_sgl_copy(d_sg_list_t *sgl, uint64_t off, void *buf, uint64_t size) /* to copy data from [buf, buf + size) to sgl */ rc = daos_sgl_processor(sgl, true, &sgl_idx, size, oes_copy, &arg); D_ASSERT(rc == 0); + if (sgl_idx.iov_offset == 0) + sgl->sg_nr_out = sgl_idx.iov_idx; + else + sgl->sg_nr_out = sgl_idx.iov_idx + 1; + ; } /* copy the recovered data back to missed (to be recovered) recx list */ diff --git a/src/object/cli_shard.c b/src/object/cli_shard.c index 9f385b98f52..d6f85a71bf1 100644 --- a/src/object/cli_shard.c +++ b/src/object/cli_shard.c @@ -921,16 +921,18 @@ dc_rw_cb(tse_task_t *task, void *arg) orwo->orw_rels.ca_arrays, orwo->orw_rels.ca_count); if (rc) { - D_ERROR(DF_UOID " obj_ec_parity_check failed, " DF_RC "\n", - DP_UOID(orw->orw_oid), DP_RC(rc)); + DL_ERROR(rc, DF_CONT ", " DF_UOID " obj_ec_parity_check failed", + DP_CONT(orw->orw_pool_uuid, orw->orw_co_uuid), + DP_UOID(orw->orw_oid)); goto out; } } rc = dc_shard_update_size(rw_args, 0); if (rc) { - D_ERROR(DF_UOID " dc_shard_update_size failed, " DF_RC "\n", - DP_UOID(orw->orw_oid), DP_RC(rc)); + DL_ERROR(rc, DF_CONT ", " DF_UOID " dc_shard_update_size failed", + DP_CONT(orw->orw_pool_uuid, orw->orw_co_uuid), + DP_UOID(orw->orw_oid)); goto out; } diff --git a/src/object/srv_ec_aggregate.c b/src/object/srv_ec_aggregate.c index 5dc1baf14eb..ed30865f61d 100644 --- a/src/object/srv_ec_aggregate.c +++ b/src/object/srv_ec_aggregate.c @@ -1074,7 +1074,7 @@ agg_update_parity(struct ec_agg_entry *entry, uint8_t *bit_map, buf = entry->ae_sgl.sg_iovs[AGG_IOV_DATA].iov_buf; diff = entry->ae_sgl.sg_iovs[AGG_IOV_DIFF].iov_buf; - for (i = 0, j = 0; i < cell_cnt; i++) { + for (i = 0, j = 0; i < cell_cnt; i++, j++) { old = &obuf[i * cell_bytes]; new = &buf[i * cell_bytes]; vects[0] = old; @@ -1085,6 +1085,7 @@ agg_update_parity(struct ec_agg_entry *entry, uint8_t *bit_map, goto out; while (!isset(bit_map, j)) j++; + D_ASSERTF(j < k, "bad cell_idx %d, number of data shards %d\n", j, k); agg_diff_preprocess(entry, diff, j); ec_encode_data_update(cell_bytes, k, p, j, entry->ae_codec->ec_gftbls, diff, @@ -1950,15 +1951,15 @@ agg_process_stripe(struct ec_agg_param *agg_param, struct ec_agg_entry *entry) /* offload of ds_obj_update to push remote parity */ rc = agg_peer_update(entry, write_parity); if (rc) - D_ERROR("agg_peer_update fail: "DF_RC"\n", - DP_RC(rc)); + DL_ERROR(rc, "agg_peer_update failed, write_parity %d", + write_parity); } if (rc == 0) { rc = agg_update_vos(agg_param, entry, write_parity); if (rc) - D_ERROR("agg_update_vos failed: "DF_RC"\n", - DP_RC(rc)); + DL_ERROR(rc, "agg_update_vos failed, write_parity %d", + write_parity); } } diff --git a/src/object/srv_obj.c b/src/object/srv_obj.c index 8d927ce7dca..e883f5cb7e1 100644 --- a/src/object/srv_obj.c +++ b/src/object/srv_obj.c @@ -1363,6 +1363,25 @@ obj_rw_recx_list_post(struct obj_rw_in *orw, struct obj_rw_out *orwo, uint8_t *s return rc; } +struct ec_agg_boundary_arg { + struct ds_pool *eab_pool; + uuid_t eab_co_uuid; +}; + +static int +obj_fetch_ec_agg_boundary(void *data) +{ + struct ec_agg_boundary_arg *arg = data; + int rc; + + rc = ds_cont_fetch_ec_agg_boundary(arg->eab_pool->sp_iv_ns, arg->eab_co_uuid); + if (rc) + DL_ERROR(rc, DF_CONT ", ds_cont_fetch_ec_agg_boundary failed.", + DP_CONT(arg->eab_pool->sp_uuid, arg->eab_co_uuid)); + + return rc; +} + static int obj_local_rw_internal(crt_rpc_t *rpc, struct obj_io_context *ioc, daos_iod_t *iods, struct dcs_iod_csums *iod_csums, uint64_t *offs, uint8_t *skips, @@ -1483,6 +1502,32 @@ obj_local_rw_internal(crt_rpc_t *rpc, struct obj_io_context *ioc, daos_iod_t *io get_parity_list = ec_recov && is_parity_shard && ((orw->orw_flags & ORF_EC_RECOV_SNAP) == 0); } + if ((ec_deg_fetch || (ec_recov && get_parity_list)) && + ioc->ioc_coc->sc_ec_agg_eph_valid == 0) { + struct ec_agg_boundary_arg arg; + + arg.eab_pool = ioc->ioc_coc->sc_pool->spc_pool; + uuid_copy(arg.eab_co_uuid, ioc->ioc_coc->sc_uuid); + rc = dss_ult_execute(obj_fetch_ec_agg_boundary, &arg, NULL, NULL, + DSS_XS_SYS, 0, 0); + if (rc) { + DL_ERROR(rc, DF_CONT ", " DF_UOID " fetch ec_agg_boundary failed.", + DP_CONT(ioc->ioc_coc->sc_pool_uuid, ioc->ioc_coc->sc_uuid), + DP_UOID(orw->orw_oid)); + goto out; + } + if (ioc->ioc_coc->sc_ec_agg_eph_valid == 0) { + rc = -DER_FETCH_AGAIN; + DL_INFO(rc, DF_CONT ", " DF_UOID " zero ec_agg_boundary.", + DP_CONT(ioc->ioc_coc->sc_pool_uuid, ioc->ioc_coc->sc_uuid), + DP_UOID(orw->orw_oid)); + goto out; + } + D_DEBUG(DB_IO, + DF_CONT ", " DF_UOID " fetched ec_agg_eph_boundary " DF_X64 "\n", + DP_CONT(ioc->ioc_coc->sc_pool_uuid, ioc->ioc_coc->sc_uuid), + DP_UOID(orw->orw_oid), ioc->ioc_coc->sc_ec_agg_eph_boundary); + } if (get_parity_list) { D_ASSERT(!ec_deg_fetch); fetch_flags |= VOS_OF_FETCH_RECX_LIST; diff --git a/src/object/srv_obj_migrate.c b/src/object/srv_obj_migrate.c index 7772bcdd4e0..2a91c7f1722 100644 --- a/src/object/srv_obj_migrate.c +++ b/src/object/srv_obj_migrate.c @@ -764,7 +764,7 @@ mrone_obj_fetch_internal(struct migrate_one *mrone, daos_handle_t oh, d_sg_list_ retry: rc = dsc_obj_fetch(oh, eph, &mrone->mo_dkey, iod_num, iods, sgls, NULL, flags, extra_arg, csum_iov_fetch); - if (rc == -DER_TIMEDOUT && + if ((rc == -DER_TIMEDOUT || rc == -DER_FETCH_AGAIN) && tls->mpt_version + 1 >= tls->mpt_pool->spc_map_version) { if (tls->mpt_fini) { DL_ERROR(rc, DF_RB ": dsc_obj_fetch " DF_UOID "failed when mpt_fini", diff --git a/src/pool/srv_pool.c b/src/pool/srv_pool.c index 339a236e281..64582d9daeb 100644 --- a/src/pool/srv_pool.c +++ b/src/pool/srv_pool.c @@ -2268,7 +2268,7 @@ pool_svc_step_up_cb(struct ds_rsvc *rsvc) daos_prop_t *prop = NULL; bool cont_svc_up = false; bool events_initialized = false; - d_rank_t rank = dss_self_rank(); + d_rank_t rank = dss_self_rank(); int rc; D_ASSERTF(svc->ps_error == 0, "ps_error: " DF_RC "\n", DP_RC(svc->ps_error)); @@ -2367,7 +2367,7 @@ pool_svc_step_up_cb(struct ds_rsvc *rsvc) if (rc != 0) goto out; - rc = ds_rebuild_regenerate_task(svc->ps_pool, prop); + rc = ds_rebuild_regenerate_task(svc->ps_pool, prop, 0); if (rc != 0) goto out; diff --git a/src/pool/srv_target.c b/src/pool/srv_target.c index d3640f9ef01..76a0610a20a 100644 --- a/src/pool/srv_target.c +++ b/src/pool/srv_target.c @@ -2438,8 +2438,13 @@ cont_discard_cb(daos_handle_t ih, vos_iter_entry_t *entry, put: ds_cont_child_put(cont); + /* don't destroy vos container, to avoid ds_cont_tgt_refresh_agg_eph() failure, + * later depend on container recovery process to handle it. + */ +#if 0 if (rc == 0) rc = ds_cont_child_destroy(arg->tgt_discard->pool_uuid, entry->ie_couuid); +#endif return rc; } @@ -2600,7 +2605,7 @@ ds_pool_task_collective(uuid_t pool_uuid, uint32_t ex_status, int (*coll_func)(v } /* Discard the objects by epoch in this pool */ -static void +static int ds_pool_tgt_discard_ult(void *data) { struct ds_pool *pool; @@ -2627,6 +2632,7 @@ ds_pool_tgt_discard_ult(void *data) ds_pool_put(pool); free: tgt_discard_arg_free(arg); + return rc; } void @@ -2659,7 +2665,7 @@ ds_pool_tgt_discard_handler(crt_rpc_t *rpc) pool->sp_need_discard = 1; pool->sp_discard_status = 0; - rc = dss_ult_create(ds_pool_tgt_discard_ult, arg, DSS_XS_SYS, 0, 0, NULL); + rc = dss_ult_execute(ds_pool_tgt_discard_ult, arg, NULL, NULL, DSS_XS_SYS, 0, 0); ds_pool_put(pool); out: diff --git a/src/rebuild/srv.c b/src/rebuild/srv.c index 76971149ef8..817dda33ac4 100644 --- a/src/rebuild/srv.c +++ b/src/rebuild/srv.c @@ -1601,8 +1601,7 @@ rebuild_task_ult(void *arg) cur_ts = daos_gettime_coarse(); D_ASSERT(task->dst_schedule_time != (uint64_t)-1); if (cur_ts < task->dst_schedule_time) { - D_DEBUG(DB_REBUILD, "rebuild task sleep "DF_U64" second\n", - task->dst_schedule_time - cur_ts); + D_INFO("rebuild task sleep " DF_U64 " second\n", task->dst_schedule_time - cur_ts); dss_sleep((task->dst_schedule_time - cur_ts) * 1000); } @@ -1613,6 +1612,13 @@ rebuild_task_ult(void *arg) D_GOTO(out_task, rc = -DER_NONEXIST); } + rc = ds_cont_svc_refresh_agg_eph(task->dst_pool_uuid); + if (rc) { + D_ERROR(DF_UUID ": ds_cont_svc_refresh_agg_eph failed, " DF_RC "\n", + DP_UUID(task->dst_pool_uuid), DP_RC(rc)); + goto out_pool; + } + while (1) { /* Check if the leader pool map has been synced to all other targets * to avoid -DER_GRP error. @@ -2180,7 +2186,7 @@ regenerate_task_of_type(struct ds_pool *pool, pool_comp_state_t match_states, ui /* Regenerate the rebuild tasks when changing the leader. */ int -ds_rebuild_regenerate_task(struct ds_pool *pool, daos_prop_t *prop) +ds_rebuild_regenerate_task(struct ds_pool *pool, daos_prop_t *prop, uint64_t delay_sec) { struct daos_prop_entry *entry; char *env; @@ -2206,12 +2212,13 @@ ds_rebuild_regenerate_task(struct ds_pool *pool, daos_prop_t *prop) entry = daos_prop_entry_get(prop, DAOS_PROP_PO_SELF_HEAL); D_ASSERT(entry != NULL); if (entry->dpe_val & (DAOS_SELF_HEAL_AUTO_REBUILD | DAOS_SELF_HEAL_DELAY_REBUILD)) { - rc = regenerate_task_of_type(pool, PO_COMP_ST_DOWN, - entry->dpe_val & DAOS_SELF_HEAL_DELAY_REBUILD ? -1 : 0); + rc = regenerate_task_of_type( + pool, PO_COMP_ST_DOWN, + entry->dpe_val & DAOS_SELF_HEAL_DELAY_REBUILD ? -1 : delay_sec); if (rc != 0) return rc; - rc = regenerate_task_of_type(pool, PO_COMP_ST_DRAIN, 0); + rc = regenerate_task_of_type(pool, PO_COMP_ST_DRAIN, delay_sec); if (rc != 0) return rc; } else { @@ -2229,7 +2236,7 @@ ds_rebuild_regenerate_task(struct ds_pool *pool, daos_prop_t *prop) * discarding on an empty targets is harmless. So it is ok to use REINT to * do EXTEND here. */ - rc = regenerate_task_of_type(pool, PO_COMP_ST_UP, 0); + rc = regenerate_task_of_type(pool, PO_COMP_ST_UP, delay_sec); if (rc != 0) return rc; diff --git a/src/vos/vos_io.c b/src/vos/vos_io.c index 8615fb56b47..1b25ffb1015 100644 --- a/src/vos/vos_io.c +++ b/src/vos/vos_io.c @@ -1,5 +1,6 @@ /** * (C) Copyright 2018-2024 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -1007,14 +1008,44 @@ akey_fetch_recx(daos_handle_t toh, const daos_epoch_range_t *epr, holes += lo - index; } - /* Hole extent, with_shadow case only used for EC obj */ - if (bio_addr_is_hole(&ent->en_addr) || - (with_shadow && (ent->en_epoch < shadow_ep))) { + if ((with_shadow && (ent->en_epoch < shadow_ep))) { index = lo + nr; holes += nr; continue; } + /* Hole extent, with_shadow case only used for EC obj */ + if (bio_addr_is_hole(&ent->en_addr)) { + if (with_shadow) { + if (holes != 0) { + /* process the prev hole */ + rc = save_recx(ioc, lo - holes, holes, shadow_ep, inob, + DRT_SHADOW); + if (rc != 0) + goto failed; + biov_set_hole(&biov, holes * inob); + /* skip the hole */ + rc = iod_fetch(ioc, &biov); + if (rc != 0) + goto failed; + holes = 0; + } + /* process this punch ext, for degraded fetch just skip it */ + index = lo + nr; + holes = nr; + biov_set_hole(&biov, holes * inob); + /* skip the hole */ + rc = iod_fetch(ioc, &biov); + if (rc != 0) + goto failed; + holes = 0; + } else { + index = lo + nr; + holes += nr; + } + continue; + } + if (holes != 0) { if (with_shadow) { rc = save_recx(ioc, lo - holes, holes, From cbfcb647a3fa8df859777c894db527149ec32af6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 08:49:32 -0700 Subject: [PATCH 11/12] DAOS-18047 cq: Bump the gha-versions (#16949) (#16948) Updates `ossf/scorecard-action` from 2.4.2 to 2.4.3 - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/05b42c624433fc40578a4040d5cf5e36ddca8cde...4eaacf0543bb3f2c246792bd56e8cdeffafb205a) Updates `github/codeql-action` from 3.30.5 to 3.30.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/3599b3baa15b485a2e49ef411a7a4bb2452e7f93...64d10c13136e1c5bce3e5fbde8d4906eeaafc885) Signed-off-by: dependabot[bot] --- .github/workflows/ossf-scorecard.yml | 4 ++-- .github/workflows/trivy.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index fa39d27eb83..8546979fed1 100644 --- a/.github/workflows/ossf-scorecard.yml +++ b/.github/workflows/ossf-scorecard.yml @@ -38,7 +38,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif @@ -71,6 +71,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/upload-sarif@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 with: sarif_file: results.sarif diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 1f0c07c9c3e..92f84cd4b65 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -58,7 +58,7 @@ jobs: trivy-config: 'utils/trivy/trivy.yaml' - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/upload-sarif@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 with: sarif_file: 'trivy-results.sarif' From ea4ddaa05b7ff263449724642cc9485653aca28e Mon Sep 17 00:00:00 2001 From: Phil Henderson Date: Tue, 14 Oct 2025 11:17:23 -0400 Subject: [PATCH 12/12] SRE-3389 test: Fix Leap 15.6 lua-lmod install (#16973) (#16977) Add opensuse-oss-proxy-artifactory for lua-lmod package dependencies. Signed-off-by: Phil Henderson --- ci/provisioning/post_provision_config_nodes_LEAP.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/provisioning/post_provision_config_nodes_LEAP.sh b/ci/provisioning/post_provision_config_nodes_LEAP.sh index 4e6dc3e4e41..5a2a553e56f 100644 --- a/ci/provisioning/post_provision_config_nodes_LEAP.sh +++ b/ci/provisioning/post_provision_config_nodes_LEAP.sh @@ -9,7 +9,7 @@ bootstrap_dnf() { rm -rf "$REPOS_DIR" ln -s ../zypp/repos.d "$REPOS_DIR" dnf -y remove lua54 lua-lmod - dnf -y --nogpgcheck install lua-lmod '--repo=*lua*' --repo '*network-cluster*' + dnf -y --nogpgcheck install lua-lmod --repo '*lua*' --repo '*network-cluster*' --repo '*oss-proxy*' } group_repo_post() {