diff --git a/site_scons/prereq_tools/base.py b/site_scons/prereq_tools/base.py index 00d00d2b1fb..a1cd84fab2a 100644 --- a/site_scons/prereq_tools/base.py +++ b/site_scons/prereq_tools/base.py @@ -518,6 +518,7 @@ def __init__(self, env, opts): opts.Add(EnumVariable('WARNING_LEVEL', "Set default warning level", 'error', ['warning', 'warn', 'error'], ignorecase=2)) opts.Add(('SANITIZERS', 'Instrument C code with google sanitizers', None)) + opts.Add(BoolVariable('CMOCKA_FILTER_SUPPORTED', 'Allows to filter cmocka tests', False)) opts.Update(self.__env) diff --git a/site_scons/site_tools/compiler_setup.py b/site_scons/site_tools/compiler_setup.py index 51909b8cfe6..2429e769cf7 100644 --- a/site_scons/site_tools/compiler_setup.py +++ b/site_scons/site_tools/compiler_setup.py @@ -54,7 +54,7 @@ def _base_setup(env): # Turn on -Wall first, then DESIRED_FLAGS may disable some of the options # that this brings in. - env.Append(CCFLAGS=['-g', '-Wextra', '-Wshadow', '-Wall', '-fpic']) + env.Append(CCFLAGS=['-g3', '-Wextra', '-Wshadow', '-Wall', '-fpic']) env.AppendIfSupported(CCFLAGS=DESIRED_FLAGS) @@ -106,7 +106,10 @@ def _base_setup(env): env.AppendUnique(CPPDEFINES={'FAULT_INJECTION': '1'}) env.AppendUnique(CPPDEFINES={'BUILD_PIPELINE': '1'}) - env.AppendUnique(CPPDEFINES={'CMOCKA_FILTER_SUPPORTED': '0'}) + if env['CMOCKA_FILTER_SUPPORTED']: + env.AppendUnique(CPPDEFINES={'CMOCKA_FILTER_SUPPORTED': '1'}) + else: + env.AppendUnique(CPPDEFINES={'CMOCKA_FILTER_SUPPORTED': '0'}) env.AppendUnique(CPPDEFINES='_GNU_SOURCE') diff --git a/src/control/cmd/ddb/commands_wrapper.go b/src/control/cmd/ddb/commands_wrapper.go index e393b7b7b47..e7f2a165bbb 100644 --- a/src/control/cmd/ddb/commands_wrapper.go +++ b/src/control/cmd/ddb/commands_wrapper.go @@ -349,3 +349,15 @@ func ddbDtxAggr(ctx *DdbContext, path string, cmt_time uint64, cmt_date string) /* Run the c code command */ return daosError(C.ddb_run_dtx_aggr(&ctx.ctx, &options)) } + +func ddbCsumDump(ctx *DdbContext, path string, dst string, epoch uint64) error { + /* Set up the options */ + options := C.struct_csum_dump_options{} + options.path = C.CString(path) + defer freeString(options.path) + options.dst = C.CString(dst) + defer freeString(options.dst) + options.epoch = C.uint64_t(epoch) + /* Run the c code command */ + return daosError(C.ddb_run_csum_dump(&ctx.ctx, &options)) +} diff --git a/src/control/cmd/ddb/ddb_commands.go b/src/control/cmd/ddb/ddb_commands.go index bee8aeddc4d..65307937a0f 100644 --- a/src/control/cmd/ddb/ddb_commands.go +++ b/src/control/cmd/ddb/ddb_commands.go @@ -442,4 +442,28 @@ the path must include the extent, otherwise, it must not.`, }, Completer: nil, }) + // Command csum_dump + app.AddCommand(&grumble.Command{ + Name: "csum_dump", + Aliases: nil, + Help: "Dump visible checksum(s)", + LongHelp: `Dump visible checksum(s) to the screen or in a file. The vos +path should be a complete path, including the akey and if the value is an array +value it should include the extent. If a path to a file was provided then the +value(s) will be written to the file, else it will be printed to the screen. +With array values it is possible to define the maximal epoch of the visible record +extent to select`, + HelpGroup: "vos", + Args: func(a *grumble.Args) { + a.String("path", "VOS tree path to dump.") + a.String("dst", "Optional, destination vos tree path to a value.", grumble.Default("")) + }, + Flags: func(f *grumble.Flags) { + f.Uint64("e", "epoch", math.MaxUint64, "Maximal epoch of the visible array value to select (default EPOCH_MAX).") + }, + Run: func(c *grumble.Context) error { + return ddbCsumDump(ctx, c.Args.String("path"), c.Args.String("dst"), c.Flags.Uint64("epoch")) + }, + Completer: nil, + }) } diff --git a/src/include/daos_srv/vos.h b/src/include/daos_srv/vos.h index 3eef3f4702d..ab81543db21 100644 --- a/src/include/daos_srv/vos.h +++ b/src/include/daos_srv/vos.h @@ -723,6 +723,16 @@ vos_obj_fetch_ex(daos_handle_t coh, daos_unit_oid_t oid, daos_epoch_t epoch, uint64_t flags, daos_key_t *dkey, unsigned int iod_nr, daos_iod_t *iods, d_sg_list_t *sgls, struct dtx_handle *dth); +// FIXME DAOS-17321 -- Old checksum fetch API, to be removed later +#if 0 +/** + * TODO DAOS-17321 + */ +int +vos_csum_fetch(daos_handle_t coh, daos_key_t *dkey, daos_unit_oid_t oid, daos_iod_t *iod, + struct daos_recx_ep_list *rel, struct dcs_ci_list *cil); +#endif + /** * Update records for the specified object. * If input buffer is not provided in \a sgl, then this function returns @@ -905,6 +915,7 @@ vos_obj_mark_corruption(daos_handle_t coh, daos_epoch_t epoch, uint32_t pm_ver, * I/O and release resources. * * TODO: add more detail descriptions for punched or missing records. + * TODO DAOS-17321 -- Add description for csum handling. * * \param[in] coh Container open handle * \param[in] oid Object ID diff --git a/src/include/daos_srv/vos_types.h b/src/include/daos_srv/vos_types.h index ca50a41658f..510c9978d9d 100644 --- a/src/include/daos_srv/vos_types.h +++ b/src/include/daos_srv/vos_types.h @@ -258,49 +258,51 @@ typedef enum { enum { /** Conditional Op: Punch key if it exists, fail otherwise */ - VOS_OF_COND_PUNCH = DAOS_COND_PUNCH, + VOS_OF_COND_PUNCH = DAOS_COND_PUNCH, /** Conditional Op: Insert dkey if it doesn't exist, fail otherwise */ - VOS_OF_COND_DKEY_INSERT = DAOS_COND_DKEY_INSERT, + VOS_OF_COND_DKEY_INSERT = DAOS_COND_DKEY_INSERT, /** Conditional Op: Update dkey if it exists, fail otherwise */ - VOS_OF_COND_DKEY_UPDATE = DAOS_COND_DKEY_UPDATE, + VOS_OF_COND_DKEY_UPDATE = DAOS_COND_DKEY_UPDATE, /** Conditional Op: Fetch dkey if it exists, fail otherwise */ - VOS_OF_COND_DKEY_FETCH = DAOS_COND_DKEY_FETCH, + VOS_OF_COND_DKEY_FETCH = DAOS_COND_DKEY_FETCH, /** Conditional Op: Insert akey if it doesn't exist, fail otherwise */ - VOS_OF_COND_AKEY_INSERT = DAOS_COND_AKEY_INSERT, + VOS_OF_COND_AKEY_INSERT = DAOS_COND_AKEY_INSERT, /** Conditional Op: Update akey if it exists, fail otherwise */ - VOS_OF_COND_AKEY_UPDATE = DAOS_COND_AKEY_UPDATE, + VOS_OF_COND_AKEY_UPDATE = DAOS_COND_AKEY_UPDATE, /** Conditional Op: Fetch akey if it exists, fail otherwise */ - VOS_OF_COND_AKEY_FETCH = DAOS_COND_AKEY_FETCH, + VOS_OF_COND_AKEY_FETCH = DAOS_COND_AKEY_FETCH, /** Indicates akey conditions are specified in iod_flags */ - VOS_OF_COND_PER_AKEY = DAOS_COND_PER_AKEY, + VOS_OF_COND_PER_AKEY = DAOS_COND_PER_AKEY, /* critical update - skip checks on SCM system/held space */ - VOS_OF_CRIT = (1 << 8), + VOS_OF_CRIT = (1 << 8), /** Instead of update or punch of extents, remove all extents * under the specified range. Intended for internal use only. */ - VOS_OF_REMOVE = (1 << 9), + VOS_OF_REMOVE = (1 << 9), /* only query iod_size */ - VOS_OF_FETCH_SIZE_ONLY = (1 << 10), + VOS_OF_FETCH_SIZE_ONLY = (1 << 10), /* query recx list */ - VOS_OF_FETCH_RECX_LIST = (1 << 11), + VOS_OF_FETCH_RECX_LIST = (1 << 11), /* only set read TS */ - VOS_OF_FETCH_SET_TS_ONLY = (1 << 12), + VOS_OF_FETCH_SET_TS_ONLY = (1 << 12), /* check the target (obj/dkey/akey) existence */ - VOS_OF_FETCH_CHECK_EXISTENCE = (1 << 13), + VOS_OF_FETCH_CHECK_EXISTENCE = (1 << 13), /** Set when propagating a punch that results in empty subtree */ - VOS_OF_PUNCH_PROPAGATE = (1 << 14), + VOS_OF_PUNCH_PROPAGATE = (1 << 14), /** replay punch (underwrite) */ - VOS_OF_REPLAY_PC = (1 << 15), + VOS_OF_REPLAY_PC = (1 << 15), /** Dedup update mode */ - VOS_OF_DEDUP = (1 << 16), + VOS_OF_DEDUP = (1 << 16), /** Dedup update with memcmp verify mode */ - VOS_OF_DEDUP_VERIFY = (1 << 17), + VOS_OF_DEDUP_VERIFY = (1 << 17), /** Ignore fetch only used by shadow fetch to ignore the evt fetch */ - VOS_OF_SKIP_FETCH = (1 << 18), + VOS_OF_SKIP_FETCH = (1 << 18), /** Operation on EC object (currently only applies to update) */ - VOS_OF_EC = (1 << 19), + VOS_OF_EC = (1 << 19), /** Update from rebuild */ - VOS_OF_REBUILD = (1 << 20), + VOS_OF_REBUILD = (1 << 20), + /* only query iod_size */ + VOS_OF_FETCH_CSUM = (1 << 21), }; enum { diff --git a/src/utils/ddb/SConscript b/src/utils/ddb/SConscript index 52861eca39c..cc61d6db90b 100644 --- a/src/utils/ddb/SConscript +++ b/src/utils/ddb/SConscript @@ -55,6 +55,10 @@ def scons(): ddblib = denv.d_library('ddb', src, LIBS=libs) denv.Install('$PREFIX/lib64/daos_srv/', ddblib) + # FIXME DAOS-17321 -- Conditional build for ddb legacies + ddbexe = denv.d_program('ddb_leg', src + ['ddb_entry.c'], LIBS=libs) + denv.Install('$PREFIX/bin', ddbexe) + # tests SConscript('tests/SConscript', exports=['denv']) diff --git a/src/utils/ddb/ddb.c b/src/utils/ddb/ddb.c index a0e975ad97d..d83e71dfc1a 100644 --- a/src/utils/ddb/ddb.c +++ b/src/utils/ddb/ddb.c @@ -49,6 +49,7 @@ #define COMMAND_NAME_DTX_STAT "dtx_stat" #define COMMAND_NAME_PROV_MEM "prov_mem" #define COMMAND_NAME_DTX_AGGR "dtx_aggr" +#define COMMAND_NAME_CSUM_DUMP "csum_dump" /* Parse command line options for the 'ls' command */ static int @@ -996,6 +997,56 @@ dtx_aggr_option_parse(struct ddb_ctx *ctx, struct dtx_aggr_options *cmd_args, ui return 0; } +/* Parse command line options for the 'dtx_aggr' command */ +static int +csum_dump_option_parse(struct ddb_ctx *ctx, struct csum_dump_options *cmd_args, uint32_t argc, + char **argv) +{ + int opt; + char *options_short = "e:"; + int index = 0; + char *endptr; + struct option options_long[] = {{"epoch", required_argument, NULL, 'e'}, {NULL}}; + + memset(cmd_args, 0, sizeof(*cmd_args)); + + /* Restart getopt */ + optind = 1; + opterr = 0; + cmd_args->epoch = DAOS_EPOCH_MAX; + while ((opt = getopt_long(argc, argv, options_short, options_long, &index)) != -1) { + switch (opt) { + case 'e': + errno = 0; + cmd_args->epoch = strtoull(optarg, &endptr, 10); + if (errno != 0 || endptr == optarg || *endptr != '\0') { + ddb_error(ctx, "'--epoch' option arg format is invalid\n"); + return -DER_INVAL; + } + break; + case '?': + ddb_printf(ctx, "Unknown option: '%c'\n", optopt); + break; + default: + return -DER_INVAL; + } + } + + index = optind; + cmd_args->path = NULL; + if (argc - index > 0 && *argv[index] != '\0') { + cmd_args->path = argv[index]; + index++; + } + + if (argc - index > 0) { + ddb_errorf(ctx, "Unexpected argument: %s\n", argv[index]); + return -DER_INVAL; + } + + return 0; +} + int ddb_parse_cmd_args(struct ddb_ctx *ctx, uint32_t argc, char **argv, struct ddb_cmd_info *info) { @@ -1132,6 +1183,11 @@ ddb_parse_cmd_args(struct ddb_ctx *ctx, uint32_t argc, char **argv, struct ddb_c return dtx_aggr_option_parse(ctx, &info->dci_cmd_option.dci_dtx_aggr, argc, argv); } + if (same(cmd, COMMAND_NAME_CSUM_DUMP)) { + info->dci_cmd = DDB_CMD_CSUM_DUMP; + return csum_dump_option_parse(ctx, &info->dci_cmd_option.dci_csum_dump, argc, argv); + } + ddb_errorf(ctx, "'%s' is not a valid command. Available commands are:" "'help', " @@ -1160,7 +1216,8 @@ ddb_parse_cmd_args(struct ddb_ctx *ctx, uint32_t argc, char **argv, struct ddb_c "'dev_replace', " "'dtx_stat', " "'prov_mem', " - "'dtx_aggr'\n", + "'dtx_aggr', " + "'csum_dump'\n", cmd); return -DER_INVAL; @@ -1348,6 +1405,10 @@ ddb_run_cmd(struct ddb_ctx *ctx, const char *cmd_str) rc = ddb_run_dtx_aggr(ctx, &info.dci_cmd_option.dci_dtx_aggr); break; + case DDB_CMD_CSUM_DUMP: + rc = ddb_run_csum_dump(ctx, &info.dci_cmd_option.dci_csum_dump); + break; + case DDB_CMD_UNKNOWN: ddb_error(ctx, "Unknown command\n"); rc = -DER_INVAL; @@ -1579,7 +1640,7 @@ ddb_commands_help(struct ddb_ctx *ctx) ddb_print(ctx, "\n"); /* Command: dtx_aggr */ - ddb_print(ctx, "dtx_aggr [path]\n"); + ddb_print(ctx, "dtx_aggr [Options] [path]\n"); ddb_print(ctx, "\tAggregate DTX entries until a given timestamp or duration.\n"); ddb_print(ctx, " [path]\n"); ddb_print(ctx, "\tOptional, VOS tree path of a container to aggregate.\n"); @@ -1589,6 +1650,16 @@ ddb_commands_help(struct ddb_ctx *ctx) ddb_print(ctx, " -d, --cmt_date\n"); ddb_print(ctx, "\tMax aggregation commit date (format '1970-01-01 00:00:00')\n"); ddb_print(ctx, "\n"); + + /* Command: csum_dump */ + ddb_print(ctx, "csum_dump [Options] \n"); + ddb_print(ctx, "\tDump visible checksum(s) information until a given epoch.\n"); + ddb_print(ctx, " [path]\n"); + ddb_print(ctx, "\tComplete VOS tree path to a Single Value or to an Array Extent.\n"); + ddb_print(ctx, "Options:\n"); + ddb_print(ctx, " -e, --epoch\n"); + ddb_print(ctx, "\tMax epoch to dump checksum(s) information (default MAX_EPOCH).\n"); + ddb_print(ctx, "\n"); } void @@ -1661,4 +1732,5 @@ ddb_program_help(struct ddb_ctx *ctx) ddb_print(ctx, " dtx_stat Stat on DTX entries\n"); ddb_print(ctx, " prov_mem Prepare memory environment for md-on-ssd mode.\n"); ddb_print(ctx, " dtx_aggr Aggregate DTX entries\n"); + ddb_print(ctx, " csum_dump Dump checksum information\n"); } diff --git a/src/utils/ddb/ddb.h b/src/utils/ddb/ddb.h index 3bc63c8f40f..139b2826a7b 100644 --- a/src/utils/ddb/ddb.h +++ b/src/utils/ddb/ddb.h @@ -126,6 +126,7 @@ enum ddb_cmd { DDB_CMD_DTX_STAT = 26, DDB_CMD_PROV_MEM = 27, DDB_CMD_DTX_AGGR = 28, + DDB_CMD_CSUM_DUMP = 29, }; /* option and argument structures for commands that need them */ @@ -236,6 +237,12 @@ struct dtx_aggr_options { char *cmt_date; }; +struct csum_dump_options { + char *path; + char *dst; + daos_epoch_t epoch; +}; + struct ddb_cmd_info { enum ddb_cmd dci_cmd; union { @@ -259,6 +266,7 @@ struct ddb_cmd_info { struct dtx_stat_options dci_dtx_stat; struct prov_mem_options dci_prov_mem; struct dtx_aggr_options dci_dtx_aggr; + struct csum_dump_options dci_csum_dump; } dci_cmd_option; }; @@ -330,6 +338,8 @@ int ddb_run_prov_mem(struct ddb_ctx *ctx, struct prov_mem_options *opt); int ddb_run_dtx_aggr(struct ddb_ctx *ctx, struct dtx_aggr_options *opt); +int +ddb_run_csum_dump(struct ddb_ctx *ctx, struct csum_dump_options *opt); void ddb_program_help(struct ddb_ctx *ctx); diff --git a/src/utils/ddb/ddb_commands.c b/src/utils/ddb/ddb_commands.c index 0e26686a24c..d6073c40b5a 100644 --- a/src/utils/ddb/ddb_commands.c +++ b/src/utils/ddb/ddb_commands.c @@ -366,6 +366,314 @@ ddb_run_value_dump(struct ddb_ctx *ctx, struct value_dump_options *opt) return rc; } +static void +print_csum_bufs(struct ddb_ctx *ctx, struct dcs_csum_info *ci) +{ + uint8_t *csum_buf; + int i; + + ddb_print(ctx, "0x"); + csum_buf = ci_idx2csum(ci, 0); + for (i = 0; i < ci->cs_len; i++) + ddb_printf(ctx, "%02" PRIx8, csum_buf[i]); + + for (i = 1; i < ci->cs_nr; i++) { + int j; + + csum_buf = ci_idx2csum(ci, i); + ddb_print(ctx, ", 0x"); + for (j = 0; j < ci->cs_len; j++) + ddb_printf(ctx, "%02" PRIx8, csum_buf[j]); + } + ddb_print(ctx, "\n"); +} + +struct dump_csum_args { + struct ddb_ctx *dca_ctx; + struct dv_indexed_tree_path *dca_vtp; + char *dca_dst_path; +}; + +static int +print_csum_recx(void *cb_args, struct daos_recx_ep_list *rel, struct dcs_ci_list *cil) +{ + struct dump_csum_args *args; + struct ddb_ctx *ctx; + struct dcs_csum_info *ci; + struct hash_ft *hf; + struct daos_recx_ep *rep; + uint32_t chunk_sz; + int i; + + args = cb_args; + ctx = args->dca_ctx; + + if (cil->dcl_csum_infos_nr == 0) { + ddb_print(ctx, "No checksum at "); + itp_print_full(ctx, args->dca_vtp); + ddb_print(ctx, "\n"); + return 0; + } + + D_ASSERT(rel != NULL); + D_ASSERT(cil->dcl_csum_infos_nr == rel->re_nr); + + ci = dcs_csum_info_get(cil, 0); + D_ASSERT(ci_is_valid(ci)); + rep = &rel->re_items[0]; + hf = daos_mhash_type2algo(ci->cs_type); + chunk_sz = ci->cs_chunksize; + + itp_print_full(ctx, args->dca_vtp); + ddb_print(ctx, "\n"); + ddb_printf(ctx, + "Checksum Type: %s, Checksum Length: %" PRIu16 ", Chunk Size: %" PRIu32 + ", Record Extent(s):\n", + hf->cf_name, ci->cs_len, chunk_sz); + + ddb_printf(ctx, + "- Record Indexes: {%" PRIu64 "-%" PRIu64 "}, Record Size: %" PRIu32 + ", Epoch: %" PRIu64 ", Checksum Value(s): ", + rep->re_recx.rx_idx, rep->re_recx.rx_idx + rep->re_recx.rx_nr - 1, + rep->re_rec_size, rep->re_ep); + print_csum_bufs(ctx, ci); + + for (i = 1; i < cil->dcl_csum_infos_nr; i++) { + ci = dcs_csum_info_get(cil, i); + D_ASSERT(ci_is_valid(ci)); + rep = &rel->re_items[i]; + + ddb_printf(ctx, + "- Record Indexes: {%" PRIu64 "-%" PRIu64 "}, Record Size: %" PRIu32 + ", Epoch: %" PRIu64 ", Checksum Value(s): ", + rep->re_recx.rx_idx, rep->re_recx.rx_idx + rep->re_recx.rx_nr - 1, + rep->re_rec_size, rep->re_ep); + print_csum_bufs(ctx, ci); + } + + return 0; +} + +static int +append_csums2value(d_iov_t *value, struct dcs_csum_info *ci) +{ + uint8_t *buf; + size_t new_len; + int i; + + new_len = value->iov_len + (ci->cs_nr * ci->cs_len); + D_REALLOC(buf, value->iov_buf, value->iov_buf_len, new_len); + if (buf == NULL) + return -DER_NOMEM; + value->iov_buf = buf; + value->iov_buf_len = new_len; + + for (i = 0; i < ci->cs_nr; i++) { + uint8_t *csum_buf = ci_idx2csum(ci, i); + + memcpy((uint8_t *)value->iov_buf + value->iov_len, csum_buf, ci->cs_len); + value->iov_len += ci->cs_len; + } + + return 0; +} + +static int +write_file_csum_recx(void *cb_args, struct daos_recx_ep_list *rel, struct dcs_ci_list *cil) +{ + struct dump_csum_args *args; + struct ddb_ctx *ctx; + struct dcs_csum_info *ci; + struct hash_ft *hf; + struct daos_recx_ep *rep; + uint32_t chunk_sz; + d_iov_t value = {0}; + int i; + int rc; + + args = cb_args; + ctx = args->dca_ctx; + + if (cil->dcl_csum_infos_nr == 0) { + ddb_print(ctx, "No checksum at "); + itp_print_full(ctx, args->dca_vtp); + ddb_print(ctx, "\n"); + rc = 0; + goto out; + } + + D_ASSERT(rel != NULL); + D_ASSERT(cil->dcl_csum_infos_nr == rel->re_nr); + + ci = dcs_csum_info_get(cil, 0); + D_ASSERT(ci_is_valid(ci)); + rep = &rel->re_items[0]; + hf = daos_mhash_type2algo(ci->cs_type); + chunk_sz = ci->cs_chunksize; + + itp_print_full(ctx, args->dca_vtp); + ddb_print(ctx, "\n"); + ddb_printf(ctx, + "Dumping checksum(s) (Type: %s, Length: %" PRIu16 ", Chunk Size: %" PRIu32 + ") at %s\n", + hf->cf_name, ci->cs_len, chunk_sz, args->dca_dst_path); + + ddb_printf(ctx, + "- Record Indexes: {%" PRIu64 "-%" PRIu64 "}, Record Size: %" PRIu32 + ", Epoch: %" PRIu64 "\n", + rep->re_recx.rx_idx, rep->re_recx.rx_idx + rep->re_recx.rx_nr - 1, + rep->re_rec_size, rep->re_ep); + rc = append_csums2value(&value, ci); + if (!SUCCESS(rc)) + goto out_buf; + + for (i = 1; i < cil->dcl_csum_infos_nr; i++) { + ci = dcs_csum_info_get(cil, i); + D_ASSERT(ci_is_valid(ci)); + rep = &rel->re_items[i]; + + ddb_printf(ctx, + "- Record Indexes: {%" PRIu64 "-%" PRIu64 "}, Record Size: %" PRIu32 + ", Epoch: %" PRIu64 "\n", + rep->re_recx.rx_idx, rep->re_recx.rx_idx + rep->re_recx.rx_nr - 1, + rep->re_rec_size, rep->re_ep); + rc = append_csums2value(&value, ci); + if (!SUCCESS(rc)) + goto out_buf; + } + + rc = ctx->dc_io_ft.ddb_write_file(args->dca_dst_path, &value); + +out_buf: + D_FREE(value.iov_buf); +out: + return rc; +} + +static int +print_csum_sv(void *cb_args, struct daos_recx_ep_list *rel, struct dcs_ci_list *cil) +{ + struct dump_csum_args *args; + struct ddb_ctx *ctx; + struct dcs_csum_info *ci; + struct hash_ft *hf; + + args = cb_args; + ctx = args->dca_ctx; + + if (cil->dcl_csum_infos_nr == 0) { + ddb_print(ctx, "No checksum at: "); + itp_print_full(ctx, args->dca_vtp); + ddb_print(ctx, "\n"); + return 0; + } + D_ASSERT(cil->dcl_csum_infos_nr == 1); + + ci = dcs_csum_info_get(cil, 0); + D_ASSERT(ci_is_valid(ci)); + D_ASSERT(ci->cs_nr == 1); + hf = daos_mhash_type2algo(ci->cs_type); + + itp_print_full(ctx, args->dca_vtp); + ddb_print(ctx, "\n"); + ddb_printf(ctx, "Type: %s, Length: %" PRIu16 ", Value: ", hf->cf_name, ci->cs_len); + print_csum_bufs(ctx, ci); + + return 0; +} + +static int +write_file_csum_sv(void *cb_args, struct daos_recx_ep_list *rel, struct dcs_ci_list *cil) +{ + struct dump_csum_args *args; + struct ddb_ctx *ctx; + struct dcs_csum_info *ci; + struct hash_ft *hf; + d_iov_t value; + int rc; + + args = cb_args; + ctx = args->dca_ctx; + + D_ASSERT(ctx->dc_io_ft.ddb_write_file); + + if (cil->dcl_csum_infos_nr == 0) { + ddb_print(ctx, "No checksum at: "); + itp_print_full(ctx, args->dca_vtp); + ddb_print(ctx, "\n"); + rc = 0; + goto out; + } + D_ASSERT(cil->dcl_csum_infos_nr == 1); + + ci = dcs_csum_info_get(cil, 0); + D_ASSERT(ci_is_valid(ci)); + D_ASSERT(ci->cs_nr == 1); + hf = daos_mhash_type2algo(ci->cs_type); + + value.iov_buf = ci_idx2csum(ci, 0); + value.iov_len = ci->cs_len; + value.iov_buf_len = ci->cs_buf_len; + + ddb_printf(ctx, "Dumping checksum (type: %s, length: %" PRIu16 ") to %s\n", hf->cf_name, + ci->cs_len, args->dca_dst_path); + rc = ctx->dc_io_ft.ddb_write_file(args->dca_dst_path, &value); + +out: + return rc; +} + +int +ddb_run_csum_dump(struct ddb_ctx *ctx, struct csum_dump_options *opt) +{ + struct dv_indexed_tree_path itp = {0}; + struct dv_tree_path vtp; + struct dump_csum_args dca = {0}; + dv_dump_csum_cb cb = NULL; + int rc; + + if (!opt->path) { + ddb_error(ctx, "A VOS path to dump is required.\n"); + rc = -DER_INVAL; + goto out; + } + + rc = init_path(ctx, opt->path, &itp); + if (!SUCCESS(rc)) + goto out; + + if (!itp_has_value(&itp)) { + ddb_errorf(ctx, "Path [%s] is incomplete.\n", opt->path); + rc = -DDBER_INCOMPLETE_PATH_VALUE; + goto out_itp; + } + + if (!itp_has_recx(&itp) && opt->epoch != DAOS_EPOCH_MAX) { + ddb_error(ctx, "Epoch option not allowed with Single value.\n"); + rc = -DER_INVAL; + goto out_itp; + } + + if (opt->dst && opt->dst[0] != '\0') + cb = (itp_has_recx(&itp)) ? write_file_csum_recx : write_file_csum_sv; + else + cb = (itp_has_recx(&itp)) ? print_csum_recx : print_csum_sv; + + dca.dca_dst_path = opt->dst; + dca.dca_ctx = ctx; + dca.dca_vtp = &itp; + + itp_to_vos_path(&itp, &vtp); + + rc = dv_dump_csum(ctx->dc_poh, &vtp, opt->epoch, cb, &dca); + +out_itp: + itp_free(&itp); + +out: + return rc; +} + static int dump_ilog_entry_cb(void *cb_arg, struct ddb_ilog_entry *entry) { diff --git a/src/utils/ddb/ddb_printer.c b/src/utils/ddb/ddb_printer.c index aadd7cd4b48..6f579998f18 100644 --- a/src/utils/ddb/ddb_printer.c +++ b/src/utils/ddb/ddb_printer.c @@ -1,5 +1,6 @@ /** * (C) Copyright 2022-2024 Intel Corporation. + * (C) Copyright 2025 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -135,22 +136,20 @@ void ddb_print_sv(struct ddb_ctx *ctx, struct ddb_sv *sv, uint32_t indent) { print_indent(ctx, indent); - ddb_printf(ctx, DF_IDX" Single Value (Length: "DF_U64" bytes)\n", - sv->ddbs_idx, - sv->ddbs_record_size); + ddb_printf(ctx, DF_IDX " Single Value (Length: " DF_U64 " bytes, Epoch: %" PRIu64 ")\n", + sv->ddbs_idx, sv->ddbs_record_size, sv->ddbs_epoch); } void ddb_print_array(struct ddb_ctx *ctx, struct ddb_array *array, uint32_t indent) { print_indent(ctx, indent); - ddb_printf(ctx, DF_IDX" Array Value (Length: "DF_U64" records, Record Indexes: " - "{"DF_U64"-"DF_U64"}, Record Size: "DF_U64")\n", - array->ddba_idx, - array->ddba_recx.rx_nr, - array->ddba_recx.rx_idx, - array->ddba_recx.rx_idx + array->ddba_recx.rx_nr - 1, - array->ddba_record_size); + ddb_printf(ctx, + DF_IDX " Array Value (Length: " DF_U64 " records, Record Indexes: " + "{" DF_U64 "-" DF_U64 "}, Record Size: " DF_U64 ", Epoch: " DF_U64 ")\n", + array->ddba_idx, array->ddba_recx.rx_nr, array->ddba_recx.rx_idx, + array->ddba_recx.rx_idx + array->ddba_recx.rx_nr - 1, array->ddba_record_size, + array->ddba_epoch); } void diff --git a/src/utils/ddb/ddb_vos.c b/src/utils/ddb/ddb_vos.c index 5d53e8b3609..4fae27a9f18 100644 --- a/src/utils/ddb/ddb_vos.c +++ b/src/utils/ddb/ddb_vos.c @@ -778,8 +778,9 @@ handle_sv(struct ddb_iter_ctx *ctx, vos_iter_entry_t *entry) D_ASSERT(ctx && ctx->handlers && ctx->handlers->ddb_sv_handler); value.ddbs_record_size = entry->ie_rsize; - value.ddbs_idx = ctx->value_seen++; - value.ddbs_path = &ctx->itp; + value.ddbs_epoch = entry->ie_epoch; + value.ddbs_idx = ctx->value_seen++; + value.ddbs_path = &ctx->itp; return ctx->handlers->ddb_sv_handler(&value, ctx->handler_args); } @@ -791,10 +792,11 @@ handle_array(struct ddb_iter_ctx *ctx, vos_iter_entry_t *entry) D_ASSERT(ctx && ctx->handlers && ctx->handlers->ddb_array_handler); itp_set_recx(&ctx->itp, &entry->ie_orig_recx, ctx->value_seen); - value.ddba_path = &ctx->itp; + value.ddba_path = &ctx->itp; value.ddba_record_size = entry->ie_rsize; - value.ddba_recx = entry->ie_orig_recx; - value.ddba_idx = ctx->value_seen++; + value.ddba_recx = entry->ie_orig_recx; + value.ddba_epoch = entry->ie_epoch; + value.ddba_idx = ctx->value_seen++; return ctx->handlers->ddb_array_handler(&value, ctx->handler_args); } @@ -1027,6 +1029,170 @@ dv_dump_value(daos_handle_t poh, struct dv_tree_path *path, dv_dump_value_cb dum return rc; } +static int +dump_csum_sv(daos_handle_t coh, daos_key_t *dkey, daos_unit_oid_t *oid, daos_iod_t *iod, + dv_dump_csum_cb dump_cb, void *cb_arg) +{ + daos_handle_t ioh; + struct dcs_ci_list *cil; + int rc; + + rc = vos_fetch_begin(coh, *oid, DAOS_EPOCH_MAX, dkey, 1, iod, VOS_OF_FETCH_CSUM, NULL, &ioh, + NULL); + if (rc) { + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(*oid), + DP_RC(rc)); + goto out; + } + + cil = vos_ioh2ci(ioh); + + rc = dump_cb(cb_arg, NULL, cil); + if (!SUCCESS(rc)) + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(*oid), + DP_RC(rc)); + + rc = vos_fetch_end(ioh, NULL, rc); + if (rc != 0) + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(*oid), + DP_RC(rc)); + +out: + return rc; +} + +static int +dump_csum_recx(daos_handle_t coh, daos_key_t *dkey, daos_unit_oid_t *oid, daos_iod_t *iod, + daos_epoch_t epoch, dv_dump_csum_cb dump_cb, void *cb_arg) +{ + daos_handle_t ioh; + struct dcs_ci_list *cil; + struct daos_recx_ep_list *rel; + int rc; + + rc = vos_fetch_begin(coh, *oid, epoch, dkey, 1, iod, VOS_OF_FETCH_CSUM, NULL, &ioh, NULL); + if (rc) { + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(*oid), + DP_RC(rc)); + goto out; + } + + cil = vos_ioh2ci(ioh); + rel = vos_ioh2recx_list(ioh); + + rc = dump_cb(cb_arg, rel, cil); + if (!SUCCESS(rc)) + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(*oid), + DP_RC(rc)); + + daos_recx_ep_list_free(rel, iod->iod_nr); + rc = vos_fetch_end(ioh, NULL, rc); + if (rc != 0) + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(*oid), + DP_RC(rc)); + +out: + return rc; +} + +int +dv_dump_csum(daos_handle_t poh, struct dv_tree_path *path, daos_epoch_t epoch, + dv_dump_csum_cb dump_cb, void *cb_arg) +{ + daos_handle_t coh; + daos_iod_t iod = {0}; + int rc; + + rc = vos_cont_open(poh, path->vtp_cont, &coh); + if (!SUCCESS(rc)) { + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(path->vtp_oid), + DP_RC(rc)); + goto out; + } + + iod.iod_name = path->vtp_akey; + iod.iod_recxs = &path->vtp_recx; + iod.iod_nr = 1; + iod.iod_size = 0; + if (path->vtp_is_recx) { + iod.iod_type = DAOS_IOD_ARRAY; + rc = dump_csum_recx(coh, &path->vtp_dkey, &path->vtp_oid, &iod, epoch, dump_cb, + cb_arg); + } else { + iod.iod_type = DAOS_IOD_SINGLE; + rc = dump_csum_sv(coh, &path->vtp_dkey, &path->vtp_oid, &iod, dump_cb, cb_arg); + } + +out: + return rc; +} + +#if 0 +// Old implementation kept for reference +int +dv_dump_csum(daos_handle_t poh, struct dv_tree_path *path, dv_dump_csum_cb dump_cb, void *cb_arg) +{ + daos_iod_t iod = {0}; + daos_handle_t coh; + struct daos_recx_ep_list *rel; + struct dcs_ci_list cil; + int rc; + + rc = vos_cont_open(poh, path->vtp_cont, &coh); + if (!SUCCESS(rc)) { + D_ERROR("Unable to fetch object: " DF_RC "\n", DP_RC(rc)); + goto out; + } + + iod.iod_name = path->vtp_akey; + iod.iod_recxs = &path->vtp_recx; + iod.iod_nr = 1; + iod.iod_size = 0; + iod.iod_type = path->vtp_is_recx ? DAOS_IOD_ARRAY : DAOS_IOD_SINGLE; + + rel = NULL; + if (iod.iod_type == DAOS_IOD_ARRAY) { + D_ALLOC_PTR(rel); + if (rel == NULL) { + rc = -DER_NOMEM; + goto out_cont; + } + } + + rc = dcs_csum_info_list_init(&cil, 0); + if (!SUCCESS(rc)) { + D_ERROR("Unable to init csum list: " DF_RC "\n", DP_RC(rc)); + goto out_rel; + } + + rc = vos_csum_fetch(coh, &path->vtp_dkey, path->vtp_oid, &iod, rel, &cil); + if (!SUCCESS(rc)) { + D_ERROR("Unable to fetch csum: " DF_RC "\n", DP_RC(rc)); + goto out_cil; + } + + if (!dump_cb) + goto out_cil; + rc = dump_cb(cb_arg, rel, &cil); + if (!SUCCESS(rc)) { + D_ERROR("Unable to dump csum: " DF_RC "\n", DP_RC(rc)); + } + +out_cil: + dcs_csum_info_list_fini(&cil); + +out_rel: + if (rel != NULL) + daos_recx_ep_free(rel); + +out_cont: + vos_cont_close(coh); + +out: + return rc; +} +#endif + static void ilog_entry_status(enum ilog_status status, char *status_str, uint32_t status_str_len) { diff --git a/src/utils/ddb/ddb_vos.h b/src/utils/ddb/ddb_vos.h index 465ad12ccfc..a6b61d42b82 100644 --- a/src/utils/ddb/ddb_vos.h +++ b/src/utils/ddb/ddb_vos.h @@ -36,17 +36,18 @@ struct ddb_key { }; struct ddb_sv { - uint64_t ddbs_record_size; - uint32_t ddbs_idx; - struct dv_indexed_tree_path *ddbs_path; + uint64_t ddbs_record_size; + daos_epoch_t ddbs_epoch; + uint32_t ddbs_idx; + struct dv_indexed_tree_pat *ddbs_path; }; struct ddb_array { - uint64_t ddba_record_size; - daos_recx_t ddba_recx; - uint32_t ddba_idx; - struct dv_indexed_tree_path *ddba_path; - + uint64_t ddba_record_size; + daos_recx_t ddba_recx; + daos_epoch_t ddba_epoch; + uint32_t ddba_idx; + struct dv_indexed_tree_path *ddba_path; }; /* Open and close a pool for a ddb_ctx */ @@ -139,6 +140,13 @@ typedef int (*dv_dump_value_cb)(void *cb_arg, d_iov_t *value); int dv_dump_value(daos_handle_t poh, struct dv_tree_path *path, dv_dump_value_cb dump_cb, void *cb_arg); +typedef int (*dv_dump_csum_cb)(void *cb_arg, struct daos_recx_ep_list *rel, + struct dcs_ci_list *cil); + +int +dv_dump_csum(daos_handle_t poh, struct dv_tree_path *path, daos_epoch_t epoch, + dv_dump_csum_cb dump_cb, void *cb_arg); + struct ddb_ilog_entry { uint32_t die_idx; int32_t die_status; diff --git a/src/vos/tests/vos_tests.c b/src/vos/tests/vos_tests.c index 4fa1ac00c42..ca4c79b7f28 100644 --- a/src/vos/tests/vos_tests.c +++ b/src/vos/tests/vos_tests.c @@ -166,7 +166,7 @@ main(int argc, char **argv) #if CMOCKA_FILTER_SUPPORTED == 1 /** requires cmocka 1.1.5 */ cmocka_set_skip_filter(optarg); #else - D_PRINT("filter not enabled"); + D_PRINT("filter not enabled\n"); #endif break; @@ -181,7 +181,7 @@ main(int argc, char **argv) printf("Test filter: %s\n", filter); } #else - D_PRINT("filter not enabled"); + D_PRINT("filter not enabled\n"); #endif break; case FORCE_CSUM: diff --git a/src/vos/tests/vts_io.c b/src/vos/tests/vts_io.c index fdad31e03bb..a3cff7f6e34 100644 --- a/src/vos/tests/vts_io.c +++ b/src/vos/tests/vts_io.c @@ -2315,9 +2315,9 @@ io_sgl_fetch(void **state) /* Write/Update */ rc = vos_obj_update(arg->ctx.tc_co_hdl, arg->oid, 1, 0, 0, &dkey, 1, &iod, NULL, &sgl); + d_sgl_fini(&sgl, false); if (rc) goto exit; - d_sgl_fini(&sgl, false); inc_cntr(arg->ta_flags); /* Allocate memory for the scatter-gather list */ @@ -2446,6 +2446,97 @@ io_fetch_hole(void **state) assert_memory_equal(ground_truth, fetch_buf, 3 * 1024); } +#if 0 +/* FIXME DAOS-17321: + * - uss array and single value + * - use different diff csum algorithms + * - verify csum after fetch + * - use shard smaller than array size + * - Use overlap recx + * */ +static void +io_array_csum(void **state) +{ + struct io_test_args *arg; + daos_key_t dkey; + daos_key_t akey; + daos_recx_t rex; + daos_iod_t iod; + d_sg_list_t sgl; + struct dcs_ci_list cil; + struct dcs_iod_csums *iod_csums; + struct daos_csummer *csummer; + char dkey_buf[UPDATE_DKEY_SIZE]; + char akey_buf[UPDATE_AKEY_SIZE]; + char update_buf[SGL_TEST_BUF_COUNT * SGL_TEST_BUF_SIZE * 4]; + int rc; + + arg = *state; + + /* Set up dkey and akey */ + vts_key_gen(&dkey_buf[0], arg->dkey_size, true, arg); + vts_key_gen(&akey_buf[0], arg->akey_size, false, arg); + set_iov(&dkey, &dkey_buf[0], is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64)); + set_iov(&akey, &akey_buf[0], is_daos_obj_type_set(arg->otype, DAOS_OT_AKEY_UINT64)); + + rex.rx_idx = hash_key(&dkey, is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64)); + rex.rx_nr = 1; + + iod.iod_type = DAOS_IOD_ARRAY; + iod.iod_size = SGL_TEST_BUF_COUNT * SGL_TEST_BUF_SIZE; + iod.iod_name = akey; + iod.iod_recxs = &rex; + iod.iod_nr = 4; + + /* Fill the buffer with random letters */ + dts_buf_render(&update_buf[0], SGL_TEST_BUF_COUNT * SGL_TEST_BUF_SIZE * 4); + /* Attach the buffer to the scatter-gather list */ + rc = d_sgl_init(&sgl, 1); + if (rc) + goto out; + d_iov_set(sgl.sg_iovs, &update_buf[0], SGL_TEST_BUF_COUNT * + SGL_TEST_BUF_SIZE * 4); + + /* Add csumer */ + rc = io_test_add_csums(&iod, &sgl, &csummer, &iod_csums); + if (rc) + goto out_sgl; + + /* Write/Update */ + rc = vos_obj_update(arg->ctx.tc_co_hdl, arg->oid, 1, 0, 0, &dkey, 1, + &iod, iod_csums, &sgl); + if (rc) + goto out_csummer; + inc_cntr(arg->ta_flags); + + /* TODO DAOS-17321 -- call vos_obj_update with checksum enabled. + * io_test_obj_fetch is an example of function using checksum. + */ + rc = dcs_csum_info_list_init(&cil, 0); + if (rc) + goto out_csummer; + + rc = vos_csum_fetch(arg->ctx.tc_co_hdl, &dkey, arg->oid, &iod, &cil); + if (rc) + goto out_cil; + + /* TODO DAOS-17321 -- Verify csum */ + +out_cil: + dcs_csum_info_list_fini(&cil); + +out_csummer: + daos_csummer_free_ic(csummer, &iod_csums); + daos_csummer_destroy(&csummer); + +out_sgl: + d_sgl_fini(&sgl, false); + +out: + assert_rc_equal(rc, 0); +} +#endif + static void io_pool_overflow_test(void **state) { @@ -3064,6 +3155,7 @@ static const struct CMUnitTest io_tests[] = { {"VOS206: Simple scatter-gather list test, multiple update buffers", io_sgl_update, NULL, NULL}, {"VOS207: Simple scatter-gather list test, multiple fetch buffers", io_sgl_fetch, NULL, NULL}, {"VOS208: Extent hole test", io_fetch_hole, NULL, NULL}, + /* {"VOS209: Simple csum buffers", io_array_csum, NULL, NULL}, */ {"VOS220: 100K update/fetch/verify test", io_multiple_dkey, NULL, NULL}, {"VOS222: overwrite test", io_idx_overwrite, NULL, NULL}, {"VOS245.0: Object iter test (for oid)", oid_iter_test, oid_iter_test_setup, NULL}, diff --git a/src/vos/vos_io.c b/src/vos/vos_io.c index cebf9181aaa..420c84d844a 100644 --- a/src/vos/vos_io.c +++ b/src/vos/vos_io.c @@ -81,7 +81,7 @@ struct vos_io_context { ic_dedup : 1, /** candidate for dedup */ ic_dedup_verify : 1, ic_read_ts_only : 1, ic_check_existence : 1, ic_remove : 1, ic_skip_fetch : 1, ic_agg_needed : 1, ic_skip_akey_support : 1, ic_rebuild : 1, - ic_ec : 1; /**< see VOS_OF_EC */ + ic_csum_fetch : 1, ic_ec : 1; /**< see VOS_OF_EC */ /** * Input shadow recx lists, one for each iod. Now only used for degraded * mode EC obj fetch handling. @@ -717,6 +717,7 @@ vos_ioc_create(daos_handle_t coh, daos_unit_oid_t oid, bool read_only, ioc->ic_remove = ((vos_flags & VOS_OF_REMOVE) != 0); ioc->ic_ec = ((vos_flags & VOS_OF_EC) != 0); ioc->ic_rebuild = ((vos_flags & VOS_OF_REBUILD) != 0); + ioc->ic_csum_fetch = ((vos_flags & VOS_OF_FETCH_CSUM) != 0); ioc->ic_umoffs_cnt = 0; ioc->ic_iod_csums = iod_csums; vos_ilog_fetch_init(&ioc->ic_dkey_info); @@ -796,7 +797,7 @@ vos_ioc_create(daos_handle_t coh, daos_unit_oid_t oid, bool read_only, } /* Don't bother to initialize SGLs for size fetch */ - if (ioc->ic_size_fetch) + if (ioc->ic_size_fetch || ioc->ic_csum_fetch) continue; bsgl = bio_iod_sgl(ioc->ic_biod, i); @@ -819,7 +820,7 @@ iod_fetch(struct vos_io_context *ioc, struct bio_iov *biov) struct bio_sglist *bsgl; int iov_nr, iov_at; - if (ioc->ic_size_fetch) + if (ioc->ic_size_fetch || ioc->ic_csum_fetch) return 0; bsgl = bio_iod_sgl(ioc->ic_biod, ioc->ic_sgl_at); @@ -873,7 +874,7 @@ iod_gang_fetch(struct vos_io_context *ioc, struct bio_iov *biov) uint32_t data_len; int i, rc = 0; - if (ioc->ic_size_fetch) + if (ioc->ic_size_fetch || ioc->ic_csum_fetch) return 0; if (biov->bi_addr.ba_gang_nr < 2) { @@ -962,6 +963,8 @@ akey_fetch_single(daos_handle_t toh, const daos_epoch_range_t *epr, if (ci_is_valid(&csum_info)) save_csum(ioc, &csum_info, NULL, 0); + if (ioc->ic_csum_fetch) + goto out; if (BIO_ADDR_IS_CORRUPTED(&rbund.rb_biov->bi_addr)) { D_DEBUG(DB_CSUM, "Found corrupted record\n"); @@ -1164,6 +1167,7 @@ akey_fetch_recx(daos_handle_t toh, const daos_epoch_range_t *epr, D_ASSERT(rsize == inob); if (ioc->ic_save_recx) { + D_ASSERT(!ioc->ic_csum_fetch); rc = save_recx(ioc, lo, nr, ent->en_epoch, inob, DRT_NORMAL); if (rc != 0) @@ -1184,9 +1188,24 @@ akey_fetch_recx(daos_handle_t toh, const daos_epoch_range_t *epr, "but not all\n"); } - rc = iod_fetch(ioc, &biov); - if (rc != 0) - goto failed; + if (ioc->ic_csum_fetch && csum_enabled) { + daos_off_t ex_lo; + daos_size_t ex_nr; + + D_ASSERT(!ioc->ic_save_recx); + D_ASSERT(!with_shadow); + D_ASSERT(ioc->ic_iod_nr = 1); + + ex_lo = ent->en_ext.ex_lo; + ex_nr = ent->en_ext.ex_hi - ex_lo + 1; + rc = save_recx(ioc, ex_lo, ex_nr, ent->en_epoch, inob, DRT_NORMAL); + if (rc != 0) + goto failed; + } else { + rc = iod_fetch(ioc, &biov); + if (rc != 0) + goto failed; + } index = lo + nr; } @@ -1223,7 +1242,7 @@ ioc_trim_tail_holes(struct vos_io_context *ioc) struct bio_iov *biov; int i; - if (ioc->ic_size_fetch) + if (ioc->ic_size_fetch || ioc->ic_csum_fetch) return; bsgl = bio_iod_sgl(ioc->ic_biod, ioc->ic_sgl_at); @@ -3179,6 +3198,73 @@ vos_obj_fetch(daos_handle_t coh, daos_unit_oid_t oid, daos_epoch_t epoch, sgls, NULL); } +// FIXME DAOS-17321 -- Old checksum fetch API, to be removed later +#if 0 +// FIXME DAOS-17321 -- Add epoch range support +int +vos_csum_fetch(daos_handle_t coh, daos_key_t *dkey, daos_unit_oid_t oid, daos_iod_t *iod, + struct daos_recx_ep_list *rel, struct dcs_ci_list *cil) +{ + daos_handle_t ioh; + uint32_t idx; + struct vos_io_context *ioc; + struct dcs_ci_list *cil_tmp; + struct daos_recx_ep_list *rel_tmp; + int rc; + + D_ASSERT(iod->iod_nr == 1); + + rc = vos_fetch_begin(coh, oid, DAOS_EPOCH_MAX, dkey, 1, iod, VOS_OF_FETCH_CSUM, NULL, &ioh, NULL); + /* rc = vos_fetch_begin(coh, oid, 2472910871729537023, dkey, 1, iod, VOS_OF_FETCH_CSUM, NULL, &ioh, NULL); */ + if (rc) { + VOS_TX_TRACE_FAIL(rc, "Cannot fetch csum "DF_UOID": "DF_RC"\n", DP_UOID(oid), DP_RC(rc)); + goto out; + } + + ioc = vos_ioh2ioc(ioh); + cil_tmp = &ioc->ic_csum_list; + rel_tmp = NULL; + if (ioc->ic_recx_lists != NULL) { + D_ASSERT(iod->iod_type == DAOS_IOD_ARRAY); + + rel_tmp = &ioc->ic_recx_lists[0]; + D_ASSERT(cil_tmp->dcl_csum_infos_nr == rel_tmp->re_nr); + } + for (idx = 0; idx < cil_tmp->dcl_csum_infos_nr; idx++) { + struct dcs_csum_info *ci; + + ci = dcs_csum_info_get(cil_tmp, idx); + rc = dcs_csum_info_save(cil, ci); + if (rc != 0) { + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(oid), + DP_RC(rc)); + goto out_ioh; + } + + if (rel == NULL || rel_tmp == NULL) + continue; + + rc = daos_recx_ep_add(rel, &rel_tmp->re_items[idx]); + if (rc != 0) { + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(oid), + DP_RC(rc)); + goto out_ioh; + } + } + +out_ioh: + daos_recx_ep_list_free(ioc->ic_recx_lists, ioc->ic_iod_nr); + ioc->ic_recx_lists = NULL; + rc = vos_fetch_end(ioh, NULL, rc); + if (rc != 0) + D_ERROR("Checksum fetch of " DF_UOID " failed: " DF_RC "\n", DP_UOID(oid), + DP_RC(rc)); + +out: + return rc; +} +#endif + int vos_obj_layout_upgrade(daos_handle_t coh, daos_unit_oid_t oid, uint32_t layout_ver) {