From c74d15dca23d911d9d9cf9495ea6dc4f8045dc97 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Sat, 11 Jan 2025 01:27:20 +0800 Subject: [PATCH] DAOS-16386 utils: Add DDB Feature and RM_POOL Support (#15062) (#15474) This PR enhances the DDB functionality for CR purposes with the following updates: 1. Pool Behavior Control: Administrators can now control certain vos pool behaviors, such as skipping vos pool loading or setting a vos pool to immutable mode. 2. Manual Pool Shard Removal: A new command ddb rm_pool has been introduced, allowing administrators to manually remove pool shards. 3. SPDK Environment Initialization Bug Fix: Fixed an issue where spdk_env_init() would fail during reinitialization. These updates aim to improve system flexibility and stability, providing administrators with more robust management capabilities. Signed-off-by: Wang Shilong --- src/bio/bio_xstream.c | 4 +- src/control/cmd/ddb/command_completers.go | 37 ++- src/control/cmd/ddb/commands_wrapper.go | 35 ++- src/control/cmd/ddb/ddb_commands.go | 37 ++- src/control/cmd/ddb/main.go | 24 +- src/dtx/dtx_resync.c | 6 + src/include/daos_srv/pool.h | 8 +- src/include/daos_srv/vos.h | 50 ++++ src/include/daos_srv/vos_types.h | 12 +- src/pool/srv_target.c | 21 ++ src/utils/ddb/ddb.c | 266 +++++++++++++++++++--- src/utils/ddb/ddb.h | 73 ++++-- src/utils/ddb/ddb_commands.c | 89 +++++++- src/utils/ddb/ddb_main.c | 41 +++- src/utils/ddb/ddb_printer.c | 4 +- src/utils/ddb/ddb_vos.c | 106 ++++++++- src/utils/ddb/ddb_vos.h | 16 +- src/utils/ddb/tests/ddb_commands_tests.c | 42 ++-- src/utils/ddb/tests/ddb_main_tests.c | 2 +- src/utils/ddb/tests/ddb_parse_tests.c | 31 ++- src/utils/ddb/tests/ddb_test_driver.c | 24 +- src/utils/ddb/tests/ddb_test_driver.h | 15 +- src/utils/ddb/tests/ddb_vos_tests.c | 85 ++++--- src/vos/vos_pool.c | 47 +++- 24 files changed, 919 insertions(+), 156 deletions(-) diff --git a/src/bio/bio_xstream.c b/src/bio/bio_xstream.c index 87e7ad40f3f..2193e252fa4 100644 --- a/src/bio/bio_xstream.c +++ b/src/bio/bio_xstream.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "bio_internal.h" #include @@ -172,7 +173,8 @@ bio_spdk_env_init(void) } } - rc = spdk_env_init(&opts); + /* Don't pass opt for reinitialization, otherwise it will fail */ + rc = spdk_env_init(spdk_env_dpdk_external_init() ? &opts : NULL); if (rc != 0) { rc = -DER_INVAL; /* spdk_env_init() returns -1 */ D_ERROR("Failed to initialize SPDK env, "DF_RC"\n", DP_RC(rc)); diff --git a/src/control/cmd/ddb/command_completers.go b/src/control/cmd/ddb/command_completers.go index 51065826a8f..3c5a95a97b0 100644 --- a/src/control/cmd/ddb/command_completers.go +++ b/src/control/cmd/ddb/command_completers.go @@ -1,5 +1,5 @@ // -// (C) Copyright 2022 Intel Corporation. +// (C) Copyright 2022-2024 Intel Corporation. // // SPDX-License-Identifier: BSD-2-Clause-Patent // @@ -16,7 +16,7 @@ const ( defMntPrefix = "/mnt" ) -func listDir(match string) (result []string) { +func listDirVos(match string) (result []string) { if strings.HasSuffix(match, "vos-") { match = filepath.Dir(match) } @@ -33,9 +33,9 @@ func listDir(match string) (result []string) { return } -func openCompleter(prefix string, args []string) []string { - suggestions := []string{"-h", "-w", "--write_mode"} - suggestions = append(suggestions, listDir(defMntPrefix)...) +func filterSuggestions(prefix string, initialSuggestions, additionalSuggestions []string) []string { + suggestions := append([]string{}, initialSuggestions...) + suggestions = append(suggestions, additionalSuggestions...) if len(prefix) > 0 { var newSuggestions []string @@ -49,5 +49,32 @@ func openCompleter(prefix string, args []string) []string { } return suggestions +} + +func openCompleter(prefix string, args []string) []string { + return filterSuggestions(prefix, []string{"-h", "-w", "--write_mode"}, listDirVos(defMntPrefix)) +} + +func featureCompleter(prefix string, args []string) []string { + return filterSuggestions(prefix, []string{"-h", "-e", "--enable", "-d", "--disable", "-s", "--show"}, + listDirVos(defMntPrefix)) +} + +func listDirPool(match string) (result []string) { + if strings.HasSuffix(match, "vos-") { + match = filepath.Dir(match) + } + filepath.Walk(match, func(path string, info fs.FileInfo, err error) error { + if err != nil { + /* ignore error */ + return nil + } + result = append(result, path) + return nil + }) + return +} +func rmPoolCompleter(prefix string, args []string) []string { + return filterSuggestions(prefix, []string{"-h"}, listDirPool(defMntPrefix)) } diff --git a/src/control/cmd/ddb/commands_wrapper.go b/src/control/cmd/ddb/commands_wrapper.go index 0e41a9f2670..e19cff9a51f 100644 --- a/src/control/cmd/ddb/commands_wrapper.go +++ b/src/control/cmd/ddb/commands_wrapper.go @@ -1,5 +1,5 @@ // -// (C) Copyright 2022-2023 Intel Corporation. +// (C) Copyright 2022-2024 Intel Corporation. // // SPDX-License-Identifier: BSD-2-Clause-Patent // @@ -223,3 +223,36 @@ func ddbDtxActAbort(ctx *DdbContext, path string, dtx_id string) error { /* Run the c code command */ return daosError(C.ddb_run_dtx_act_abort(&ctx.ctx, &options)) } + +func ddbFeature(ctx *DdbContext, path, enable, disable string, show bool) error { + /* Set up the options */ + options := C.struct_feature_options{} + options.path = C.CString(path) + defer freeString(options.path) + if enable != "" { + err := daosError(C.ddb_feature_string2flags(&ctx.ctx, C.CString(enable), + &options.set_compat_flags, &options.set_incompat_flags)) + if err != nil { + return err + } + } + if disable != "" { + err := daosError(C.ddb_feature_string2flags(&ctx.ctx, C.CString(disable), + &options.clear_compat_flags, &options.clear_incompat_flags)) + if err != nil { + return err + } + } + options.show_features = C.bool(show) + /* Run the c code command */ + return daosError(C.ddb_run_feature(&ctx.ctx, &options)) +} + +func ddbRmPool(ctx *DdbContext, path string) error { + /* Set up the options */ + options := C.struct_rm_pool_options{} + options.path = C.CString(path) + defer freeString(options.path) + /* Run the c code command */ + return daosError(C.ddb_run_rm_pool(&ctx.ctx, &options)) +} diff --git a/src/control/cmd/ddb/ddb_commands.go b/src/control/cmd/ddb/ddb_commands.go index 018818ea130..b87ea681dc4 100644 --- a/src/control/cmd/ddb/ddb_commands.go +++ b/src/control/cmd/ddb/ddb_commands.go @@ -1,5 +1,5 @@ // -// (C) Copyright 2022-2023 Intel Corporation. +// (C) Copyright 2022-2024 Intel Corporation. // // SPDX-License-Identifier: BSD-2-Clause-Patent // @@ -297,4 +297,39 @@ the path must include the extent, otherwise, it must not.`, }, Completer: nil, }) + // Command: feature + app.AddCommand(&grumble.Command{ + Name: "feature", + Aliases: nil, + Help: "Manage vos pool features", + LongHelp: "", + HelpGroup: "vos", + Flags: func(f *grumble.Flags) { + f.String("e", "enable", "", "Enable vos pool features") + f.String("d", "disable", "", "Disable vos pool features") + f.Bool("s", "show", false, "Show current features") + }, + Args: func(a *grumble.Args) { + a.String("path", "Optional, Path to the vos file", grumble.Default("")) + }, + Run: func(c *grumble.Context) error { + return ddbFeature(ctx, c.Args.String("path"), c.Flags.String("enable"), c.Flags.String("disable"), c.Flags.Bool("show")) + }, + Completer: featureCompleter, + }) + // Command: rm_pool + app.AddCommand(&grumble.Command{ + Name: "rm_pool", + Aliases: nil, + Help: "Remove a vos pool.", + LongHelp: "", + HelpGroup: "vos", + Args: func(a *grumble.Args) { + a.String("path", "Optional, Path to the vos file", grumble.Default("")) + }, + Run: func(c *grumble.Context) error { + return ddbRmPool(ctx, c.Args.String("path")) + }, + Completer: rmPoolCompleter, + }) } diff --git a/src/control/cmd/ddb/main.go b/src/control/cmd/ddb/main.go index a74c9493803..18239b319ad 100644 --- a/src/control/cmd/ddb/main.go +++ b/src/control/cmd/ddb/main.go @@ -1,5 +1,5 @@ // -// (C) Copyright 2022-2023 Intel Corporation. +// (C) Copyright 2022-2024 Intel Corporation. // // SPDX-License-Identifier: BSD-2-Clause-Patent // @@ -14,6 +14,7 @@ import ( "runtime/debug" "sort" "strings" + "unsafe" "github.com/desertbit/grumble" "github.com/jessevdk/go-flags" @@ -24,6 +25,11 @@ import ( "github.com/daos-stack/daos/src/control/logging" ) +/* + #include +*/ +import "C" + func exitWithError(log logging.Logger, err error) { cmdName := path.Base(os.Args[0]) log.Errorf("%s: %v", cmdName, err) @@ -51,7 +57,7 @@ func (pathStr vosPathStr) Complete(match string) (comps []flags.Completion) { if match == "" || match == "/" { match = defMntPrefix } - for _, comp := range listDir(match) { + for _, comp := range listDirVos(match) { comps = append(comps, flags.Completion{Item: comp}) } sort.Slice(comps, func(i, j int) bool { return comps[i].Item < comps[j].Item }) @@ -176,9 +182,11 @@ Example Paths: app := createGrumbleApp(ctx) if opts.Args.VosPath != "" { - log.Debugf("Connect to path: %s\n", opts.Args.VosPath) - if err := ddbOpen(ctx, string(opts.Args.VosPath), opts.WriteMode); err != nil { - return errors.Wrapf(err, "Error opening path: %s", opts.Args.VosPath) + if !strings.HasPrefix(string(opts.Args.RunCmd), "feature") && !strings.HasPrefix(string(opts.Args.RunCmd), "rm_pool") { + log.Debugf("Connect to path: %s\n", opts.Args.VosPath) + if err := ddbOpen(ctx, string(opts.Args.VosPath), opts.WriteMode); err != nil { + return errors.Wrapf(err, "Error opening path: %s", opts.Args.VosPath) + } } } @@ -186,12 +194,16 @@ Example Paths: return errors.New("Cannot use both command file and a command string") } + if opts.Args.VosPath != "" { + ctx.ctx.dc_pool_path = C.CString(string(opts.Args.VosPath)) + defer C.free(unsafe.Pointer(ctx.ctx.dc_pool_path)) + } if opts.Args.RunCmd != "" || opts.CmdFile != "" { // Non-interactive mode if opts.Args.RunCmd != "" { err := runCmdStr(app, string(opts.Args.RunCmd), opts.Args.RunCmdArgs...) if err != nil { - log.Errorf("Error running command %s\n", string(opts.Args.RunCmd)) + log.Errorf("Error running command %q %s\n", string(opts.Args.RunCmd), err) } } else { err := runFileCmds(log, app, opts.CmdFile) diff --git a/src/dtx/dtx_resync.c b/src/dtx/dtx_resync.c index 756dfe0ca44..8ece2d3bb26 100644 --- a/src/dtx/dtx_resync.c +++ b/src/dtx/dtx_resync.c @@ -612,6 +612,12 @@ dtx_resync(daos_handle_t po_hdl, uuid_t po_uuid, uuid_t co_uuid, uint32_t ver, b crt_group_rank(NULL, &myrank); pool = cont->sc_pool->spc_pool; + if (pool->sp_disable_dtx_resync) { + D_DEBUG(DB_MD, "Skip DTX resync (%s) for " DF_UUID "/" DF_UUID " with ver %u\n", + block ? "block" : "non-block", DP_UUID(po_uuid), DP_UUID(co_uuid), ver); + goto out; + } + ABT_rwlock_rdlock(pool->sp_lock); rc = pool_map_find_target_by_rank_idx(pool->sp_map, myrank, dss_get_module_info()->dmi_tgt_id, &target); diff --git a/src/include/daos_srv/pool.h b/src/include/daos_srv/pool.h index 231cbf2b7d5..d8a39b21c84 100644 --- a/src/include/daos_srv/pool.h +++ b/src/include/daos_srv/pool.h @@ -82,12 +82,8 @@ struct ds_pool { */ uuid_t sp_srv_cont_hdl; uuid_t sp_srv_pool_hdl; - uint32_t sp_stopping:1, - sp_cr_checked:1, - sp_immutable:1, - sp_fetch_hdls:1, - sp_need_discard:1, - sp_disable_rebuild:1; + uint32_t sp_stopping : 1, sp_cr_checked : 1, sp_immutable : 1, sp_fetch_hdls : 1, + sp_need_discard : 1, sp_disable_rebuild : 1, sp_disable_dtx_resync : 1; /* pool_uuid + map version + leader term + rebuild generation define a * rebuild job. */ diff --git a/src/include/daos_srv/vos.h b/src/include/daos_srv/vos.h index 3b838c2b4a6..2121f972111 100644 --- a/src/include/daos_srv/vos.h +++ b/src/include/daos_srv/vos.h @@ -20,6 +20,56 @@ #include #include +#define VOS_POOL_COMPAT_FLAG_IMMUTABLE (1ULL << 0) +#define VOS_POOL_COMPAT_FLAG_SKIP_START (1ULL << 1) +#define VOS_POOL_COMPAT_FLAG_SKIP_REBUILD (1ULL << 2) +#define VOS_POOL_COMPAT_FLAG_SKIP_DTX_RESYNC (1ULL << 3) + +#define VOS_POOL_COMPAT_FLAG_SUPP \ + (VOS_POOL_COMPAT_FLAG_IMMUTABLE | VOS_POOL_COMPAT_FLAG_SKIP_START | \ + VOS_POOL_COMPAT_FLAG_SKIP_REBUILD | VOS_POOL_COMPAT_FLAG_SKIP_DTX_RESYNC) + +#define VOS_POOL_INCOMPAT_FLAG_SUPP 0 + +#define VOS_MAX_FLAG_NAME_LEN 32 + +static inline uint64_t +vos_pool_name2flag(const char *name, bool *compat_feature) +{ + *compat_feature = false; + + if (strncmp(name, "immutable", VOS_MAX_FLAG_NAME_LEN) == 0) { + *compat_feature = true; + return VOS_POOL_COMPAT_FLAG_IMMUTABLE; + } + if (strncmp(name, "skip_start", VOS_MAX_FLAG_NAME_LEN) == 0) { + *compat_feature = true; + return VOS_POOL_COMPAT_FLAG_SKIP_START; + } + if (strncmp(name, "skip_rebuild", VOS_MAX_FLAG_NAME_LEN) == 0) { + *compat_feature = true; + return VOS_POOL_COMPAT_FLAG_SKIP_REBUILD; + } + if (strncmp(name, "skip_dtx_resync", VOS_MAX_FLAG_NAME_LEN) == 0) { + *compat_feature = true; + return VOS_POOL_COMPAT_FLAG_SKIP_DTX_RESYNC; + } + + return 0; +} + +bool +vos_pool_feature_skip_start(daos_handle_t poh); + +bool +vos_pool_feature_immutable(daos_handle_t poh); + +bool +vos_pool_feature_skip_rebuild(daos_handle_t poh); + +bool +vos_pool_feature_skip_dtx_resync(daos_handle_t poh); + /** Initialize the vos reserve/cancel related fields in dtx handle * * \param dth [IN] The dtx handle diff --git a/src/include/daos_srv/vos_types.h b/src/include/daos_srv/vos_types.h index 194b2434c28..dde07ce7ec3 100644 --- a/src/include/daos_srv/vos_types.h +++ b/src/include/daos_srv/vos_types.h @@ -78,19 +78,21 @@ D_CASSERT(sizeof(struct dtx_entry) == /** Pool open flags (for vos_pool_create and vos_pool_open) */ enum vos_pool_open_flags { /** Pool is small (for sys space reservation); implies VOS_POF_EXCL */ - VOS_POF_SMALL = (1 << 0), + VOS_POF_SMALL = (1 << 0), /** Exclusive (-DER_BUSY if already opened) */ - VOS_POF_EXCL = (1 << 1), + VOS_POF_EXCL = (1 << 1), /** Ignore the pool uuid passed into vos_pool_open */ VOS_POF_SKIP_UUID_CHECK = (1 << 2), /** Caller does VEA flush periodically */ - VOS_POF_EXTERNAL_FLUSH = (1 << 3), + VOS_POF_EXTERNAL_FLUSH = (1 << 3), /** RDB pool */ - VOS_POF_RDB = (1 << 4), + VOS_POF_RDB = (1 << 4), /** SYS DB pool */ - VOS_POF_SYSDB = (1 << 5), + VOS_POF_SYSDB = (1 << 5), /** Open the pool for daos check query, that will bypass EXEL flags. */ VOS_POF_FOR_CHECK_QUERY = (1 << 6), + /** Open the pool for feature fetch/update, that will skip VEA load */ + VOS_POF_FOR_FEATURE_FLAG = (1 << 7), }; enum vos_oi_attr { diff --git a/src/pool/srv_target.c b/src/pool/srv_target.c index 113fb757fd9..95b70eb8b66 100644 --- a/src/pool/srv_target.c +++ b/src/pool/srv_target.c @@ -505,6 +505,27 @@ pool_child_start(struct ds_pool_child *child, bool recreate) goto done; } + if (!ds_pool_skip_for_check(child->spc_pool) && + vos_pool_feature_skip_start(child->spc_hdl)) { + D_INFO(DF_UUID ": skipped to start\n", DP_UUID(child->spc_uuid)); + rc = -DER_SHUTDOWN; + goto out_close; + } + + if (vos_pool_feature_immutable(child->spc_hdl)) + child->spc_pool->sp_immutable = 1; + + /* + * Rebuild depends on DTX resync, if DTX resync is skipped, + * then rebuild also needs to be skipped. + */ + if (vos_pool_feature_skip_rebuild(child->spc_hdl) || + vos_pool_feature_skip_dtx_resync(child->spc_hdl)) + child->spc_pool->sp_disable_rebuild = 1; + + if (vos_pool_feature_skip_dtx_resync(child->spc_hdl)) + child->spc_pool->sp_disable_dtx_resync = 1; + if (!ds_pool_restricted(child->spc_pool, false)) { rc = start_gc_ult(child); if (rc != 0) diff --git a/src/utils/ddb/ddb.c b/src/utils/ddb/ddb.c index eeeaa293e35..8493852f24f 100644 --- a/src/utils/ddb/ddb.c +++ b/src/utils/ddb/ddb.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "ddb.h" #include "ddb_common.h" @@ -34,6 +35,8 @@ #define COMMAND_NAME_VEA_UPDATE "vea_update" #define COMMAND_NAME_DTX_ACT_COMMIT "dtx_act_commit" #define COMMAND_NAME_DTX_ACT_ABORT "dtx_act_abort" +#define COMMAND_NAME_FEATURE "feature" +#define COMMAND_NAME_RM_POOL "rm_pool" /* Parse command line options for the 'ls' command */ static int @@ -629,6 +632,137 @@ dtx_act_abort_option_parse(struct ddb_ctx *ctx, struct dtx_act_abort_options *cm return 0; } +int +ddb_feature_string2flags(struct ddb_ctx *ctx, const char *string, uint64_t *compat_flags, + uint64_t *incompat_flags) +{ + char *tmp; + char *tok; + int rc = 0; + uint64_t flag; + uint64_t ret_compat_flags = 0; + uint64_t ret_incompat_flags = 0; + bool compat_feature; + + tmp = strndup(string, PATH_MAX); + if (tmp == NULL) + return -DER_NOMEM; + tok = strtok(tmp, ","); + while (tok != NULL) { + flag = vos_pool_name2flag(tok, &compat_feature); + if (flag == 0) { + ddb_printf(ctx, "Unknown flag: '%s'\n", tok); + rc = -DER_INVAL; + break; + } + if (compat_feature) + ret_compat_flags |= flag; + else + ret_incompat_flags |= flag; + tok = strtok(NULL, ","); + } + + free(tmp); + if (rc == 0) { + *compat_flags = ret_compat_flags; + *incompat_flags = ret_incompat_flags; + } + + return rc; +} + +static int +feature_option_parse(struct ddb_ctx *ctx, struct feature_options *cmd_args, uint32_t argc, + char **argv) +{ + char *options_short = "e:d:s"; + int index = 0, opt; + int rc = 0; + struct option options_long[] = {{"enable", required_argument, NULL, 'e'}, + {"disable", required_argument, NULL, 'd'}, + {"show", no_argument, NULL, 's'}, + {NULL}}; + + memset(cmd_args, 0, sizeof(*cmd_args)); + /* Restart getopt */ + optind = 1; + opterr = 0; + while ((opt = getopt_long(argc, argv, options_short, options_long, &index)) != -1) { + switch (opt) { + case 'e': + rc = ddb_feature_string2flags(ctx, optarg, &cmd_args->set_compat_flags, + &cmd_args->set_incompat_flags); + if (rc) + return rc; + break; + case 'd': + rc = ddb_feature_string2flags(ctx, optarg, &cmd_args->clear_compat_flags, + &cmd_args->clear_incompat_flags); + if (rc) + return rc; + break; + case 's': + cmd_args->show_features = true; + break; + case '?': + ddb_printf(ctx, "Unknown option: '%c'\n", optopt); + break; + default: + return -DER_INVAL; + } + } + + index = optind; + if (argc - index > 0) { + cmd_args->path = argv[index]; + index++; + } else if (ctx->dc_pool_path) { + cmd_args->path = ctx->dc_pool_path; + } + + if (argc - index > 0) { + ddb_printf(ctx, "Unexpected argument: %s\n", argv[index]); + return -DER_INVAL; + } + + return 0; +} + +/* Parse command line options for the 'rm_pool' command */ +static int +rm_pool_option_parse(struct ddb_ctx *ctx, struct rm_pool_options *cmd_args, uint32_t argc, + char **argv) +{ + char *options_short = ""; + int index = 0; + struct option options_long[] = {{NULL}}; + + memset(cmd_args, 0, sizeof(*cmd_args)); + + /* Restart getopt */ + optind = 1; + opterr = 0; + if (getopt_long(argc, argv, options_short, options_long, &index) != -1) { + ddb_printf(ctx, "Unknown option: '%c'\n", optopt); + return -DER_INVAL; + } + + index = optind; + if (argc - index > 0) { + cmd_args->path = argv[index]; + index++; + } else if (ctx->dc_pool_path) { + cmd_args->path = ctx->dc_pool_path; + } + + if (argc - index > 0) { + ddb_printf(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) { @@ -728,42 +862,91 @@ ddb_parse_cmd_args(struct ddb_ctx *ctx, uint32_t argc, char **argv, struct ddb_c return dtx_act_abort_option_parse(ctx, &info->dci_cmd_option.dci_dtx_act_abort, argc, argv); } - - ddb_errorf(ctx, "'%s' is not a valid command. Available commands are:" - "'help', " - "'quit', " - "'ls', " - "'open', " - "'version', " - "'close', " - "'superblock_dump', " - "'value_dump', " - "'rm', " - "'value_load', " - "'ilog_dump', " - "'ilog_commit', " - "'ilog_clear', " - "'dtx_dump', " - "'dtx_cmt_clear', " - "'smd_sync', " - "'vea_dump', " - "'vea_update', " - "'dtx_act_commit', " - "'dtx_act_abort'\n", cmd); + if (same(cmd, COMMAND_NAME_RM_POOL)) { + info->dci_cmd = DDB_CMD_RM_POOL; + return rm_pool_option_parse(ctx, &info->dci_cmd_option.dci_rm_pool, argc, argv); + } + if (same(cmd, COMMAND_NAME_FEATURE)) { + info->dci_cmd = DDB_CMD_FEATURE; + return feature_option_parse(ctx, &info->dci_cmd_option.dci_feature, argc, argv); + } + + ddb_errorf(ctx, + "'%s' is not a valid command. Available commands are:" + "'help', " + "'quit', " + "'ls', " + "'open', " + "'version', " + "'close', " + "'superblock_dump', " + "'value_dump', " + "'rm', " + "'value_load', " + "'ilog_dump', " + "'ilog_commit', " + "'ilog_clear', " + "'dtx_dump', " + "'dtx_cmt_clear', " + "'smd_sync', " + "'vea_dump', " + "'vea_update', " + "'dtx_act_commit', " + "'dtx_act_abort', " + "'feature', " + "'rm_pool'\n", + cmd); return -DER_INVAL; } int -ddb_run_cmd(struct ddb_ctx *ctx, const char *cmd_str, bool write_mode) +ddb_parse_cmd_str(struct ddb_ctx *ctx, const char *cmd_str, bool *open) { - struct argv_parsed parse_args = {0}; - struct ddb_cmd_info info = {0}; + struct argv_parsed parse_args = {0}; int rc; char *cmd_copy; D_STRNDUP(cmd_copy, cmd_str, MAX_COMMAND_LEN); + if (cmd_copy == NULL) + return -DER_NOMEM; + + /* Remove newline if needed */ + if (cmd_copy[strlen(cmd_copy) - 1] == '\n') + cmd_copy[strlen(cmd_copy) - 1] = '\0'; + + rc = ddb_str2argv_create(cmd_copy, &parse_args); + if (!SUCCESS(rc)) { + D_FREE(cmd_copy); + return rc; + } + + if (parse_args.ap_argc == 0) { + D_ERROR("Nothing parsed\n"); + D_GOTO(done, rc = -DER_INVAL); + } + + if (same(parse_args.ap_argv[0], COMMAND_NAME_RM_POOL) || + same(parse_args.ap_argv[0], COMMAND_NAME_FEATURE)) + *open = false; + else + *open = true; +done: + ddb_str2argv_free(&parse_args); + D_FREE(cmd_copy); + return rc; +} + +int +ddb_run_cmd(struct ddb_ctx *ctx, const char *cmd_str) +{ + struct ddb_cmd_info info = {0}; + int rc; + struct argv_parsed parse_args = {0}; + char *cmd_copy; + + D_STRNDUP(cmd_copy, cmd_str, MAX_COMMAND_LEN); if (cmd_copy == NULL) return -DER_NOMEM; @@ -787,7 +970,6 @@ ddb_run_cmd(struct ddb_ctx *ctx, const char *cmd_str, bool write_mode) D_GOTO(done, rc); switch (info.dci_cmd) { - case DDB_CMD_HELP: rc = ddb_run_help(ctx); break; @@ -868,11 +1050,20 @@ ddb_run_cmd(struct ddb_ctx *ctx, const char *cmd_str, bool write_mode) rc = ddb_run_dtx_act_abort(ctx, &info.dci_cmd_option.dci_dtx_act_abort); break; + case DDB_CMD_FEATURE: + rc = ddb_run_feature(ctx, &info.dci_cmd_option.dci_feature); + break; + + case DDB_CMD_RM_POOL: + rc = ddb_run_rm_pool(ctx, &info.dci_cmd_option.dci_rm_pool); + break; + case DDB_CMD_UNKNOWN: ddb_error(ctx, "Unknown command\n"); rc = -DER_INVAL; break; } + done: ddb_str2argv_free(&parse_args); D_FREE(cmd_copy); @@ -880,7 +1071,6 @@ ddb_run_cmd(struct ddb_ctx *ctx, const char *cmd_str, bool write_mode) return rc; } - void ddb_commands_help(struct ddb_ctx *ctx) { @@ -1036,6 +1226,24 @@ ddb_commands_help(struct ddb_ctx *ctx) ddb_print(ctx, " \n"); ddb_print(ctx, "\tDTX id of the entry to abort.\n"); ddb_print(ctx, "\n"); + + /* Command: rm_pool */ + ddb_print(ctx, "rm_pool \n"); + ddb_print(ctx, "\tremove pool shard\n"); + ddb_print(ctx, " \n"); + ddb_print(ctx, "\n"); + + /* Command: feature */ + ddb_print(ctx, "feature\n"); + ddb_print(ctx, "\tManage vos pool features\n"); + ddb_print(ctx, "Options:\n"); + ddb_print(ctx, " -e, --enable\n"); + ddb_print(ctx, "\tEnable vos pool features\n"); + ddb_print(ctx, " -d, --disable\n"); + ddb_print(ctx, "\tDisable vos pool features\n"); + ddb_print(ctx, " -s, --show\n"); + ddb_print(ctx, "\tShow current features\n"); + ddb_print(ctx, "\n"); } void @@ -1099,4 +1307,6 @@ ddb_program_help(struct ddb_ctx *ctx) ddb_print(ctx, " vea_update Alter the VEA tree to mark a region as free.\n"); ddb_print(ctx, " dtx_act_commit Mark the active dtx entry as committed\n"); ddb_print(ctx, " dtx_act_abort Mark the active dtx entry as aborted\n"); -} \ No newline at end of file + ddb_print(ctx, " feature Manage vos pool features\n"); + ddb_print(ctx, " rm_pool Remove pool shard\n"); +} diff --git a/src/utils/ddb/ddb.h b/src/utils/ddb/ddb.h index 5cae879368f..a82bb292239 100644 --- a/src/utils/ddb/ddb.h +++ b/src/utils/ddb/ddb.h @@ -1,5 +1,5 @@ /** - * (C) Copyright 2022 Intel Corporation. + * (C) Copyright 2022-2024 Intel Corporation. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -86,6 +86,7 @@ struct ddb_ctx { daos_handle_t dc_poh; bool dc_should_quit; bool dc_write_mode; + const char *dc_pool_path; }; void ddb_ctx_init(struct ddb_ctx *ctx); @@ -93,27 +94,29 @@ int ddb_init(void); void ddb_fini(void); enum ddb_cmd { - DDB_CMD_UNKNOWN = 0, - DDB_CMD_HELP = 1, - DDB_CMD_QUIT = 2, - DDB_CMD_LS = 3, - DDB_CMD_OPEN = 4, - DDB_CMD_VERSION = 5, - DDB_CMD_CLOSE = 6, + DDB_CMD_UNKNOWN = 0, + DDB_CMD_HELP = 1, + DDB_CMD_QUIT = 2, + DDB_CMD_LS = 3, + DDB_CMD_OPEN = 4, + DDB_CMD_VERSION = 5, + DDB_CMD_CLOSE = 6, DDB_CMD_SUPERBLOCK_DUMP = 7, - DDB_CMD_VALUE_DUMP = 8, - DDB_CMD_RM = 9, - DDB_CMD_VALUE_LOAD = 10, - DDB_CMD_ILOG_DUMP = 11, - DDB_CMD_ILOG_COMMIT = 12, - DDB_CMD_ILOG_CLEAR = 13, - DDB_CMD_DTX_DUMP = 14, - DDB_CMD_DTX_CMT_CLEAR = 15, - DDB_CMD_SMD_SYNC = 16, - DDB_CMD_VEA_DUMP = 17, - DDB_CMD_VEA_UPDATE = 18, - DDB_CMD_DTX_ACT_COMMIT = 19, - DDB_CMD_DTX_ACT_ABORT = 20, + DDB_CMD_VALUE_DUMP = 8, + DDB_CMD_RM = 9, + DDB_CMD_VALUE_LOAD = 10, + DDB_CMD_ILOG_DUMP = 11, + DDB_CMD_ILOG_COMMIT = 12, + DDB_CMD_ILOG_CLEAR = 13, + DDB_CMD_DTX_DUMP = 14, + DDB_CMD_DTX_CMT_CLEAR = 15, + DDB_CMD_SMD_SYNC = 16, + DDB_CMD_VEA_DUMP = 17, + DDB_CMD_VEA_UPDATE = 18, + DDB_CMD_DTX_ACT_COMMIT = 19, + DDB_CMD_DTX_ACT_ABORT = 20, + DDB_CMD_FEATURE = 21, + DDB_CMD_RM_POOL = 22, }; /* option and argument structures for commands that need them */ @@ -184,6 +187,19 @@ struct dtx_act_abort_options { char *dtx_id; }; +struct feature_options { + uint64_t set_compat_flags; + uint64_t set_incompat_flags; + uint64_t clear_compat_flags; + uint64_t clear_incompat_flags; + bool show_features; + const char *path; +}; + +struct rm_pool_options { + const char *path; +}; + struct ddb_cmd_info { enum ddb_cmd dci_cmd; union { @@ -201,11 +217,16 @@ struct ddb_cmd_info { struct vea_update_options dci_vea_update; struct dtx_act_commit_options dci_dtx_act_commit; struct dtx_act_abort_options dci_dtx_act_abort; + struct feature_options dci_feature; + struct rm_pool_options dci_rm_pool; } dci_cmd_option; }; int ddb_parse_cmd_args(struct ddb_ctx *ctx, uint32_t argc, char **argv, struct ddb_cmd_info *info); -int ddb_run_cmd(struct ddb_ctx *ctx, const char *cmd_str, bool write_mode); +int +ddb_parse_cmd_str(struct ddb_ctx *ctx, const char *cmd_str, bool *open); +int + ddb_run_cmd(struct ddb_ctx *ctx, const char *cmd_str); /* Run commands ... */ int ddb_run_help(struct ddb_ctx *ctx); int ddb_run_quit(struct ddb_ctx *ctx); @@ -228,7 +249,13 @@ int ddb_run_vea_dump(struct ddb_ctx *ctx); int ddb_run_vea_update(struct ddb_ctx *ctx, struct vea_update_options *opt); int ddb_run_dtx_act_commit(struct ddb_ctx *ctx, struct dtx_act_commit_options *opt); int ddb_run_dtx_act_abort(struct ddb_ctx *ctx, struct dtx_act_abort_options *opt); - +int +ddb_run_feature(struct ddb_ctx *ctx, struct feature_options *opt); +int +ddb_feature_string2flags(struct ddb_ctx *ctx, const char *string, uint64_t *compat_flags, + uint64_t *incompat_flags); +int + ddb_run_rm_pool(struct ddb_ctx *ctx, struct rm_pool_options *opt); void ddb_program_help(struct ddb_ctx *ctx); void ddb_commands_help(struct ddb_ctx *ctx); diff --git a/src/utils/ddb/ddb_commands.c b/src/utils/ddb/ddb_commands.c index 77fc72d9c17..3dd2261f504 100644 --- a/src/utils/ddb/ddb_commands.c +++ b/src/utils/ddb/ddb_commands.c @@ -1,10 +1,11 @@ /** - * (C) Copyright 2022-2023 Intel Corporation. + * (C) Copyright 2022-2024 Intel Corporation. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ #include +#include #include "ddb_common.h" #include "ddb_parse.h" #include "ddb.h" @@ -56,7 +57,7 @@ ddb_run_open(struct ddb_ctx *ctx, struct open_options *opt) return -DER_EXIST; } ctx->dc_write_mode = opt->write_mode; - return dv_pool_open(opt->path, &ctx->dc_poh); + return dv_pool_open(opt->path, &ctx->dc_poh, 0); } int @@ -990,3 +991,87 @@ int ddb_run_dtx_act_abort(struct ddb_ctx *ctx, struct dtx_act_abort_options *opt dtx_modify_fini(&args); return rc; } + +static inline bool +feature_write_action(struct feature_options *opt) +{ + return opt->set_compat_flags || opt->set_incompat_flags || opt->clear_compat_flags || + opt->clear_incompat_flags; +} + +int +ddb_run_feature(struct ddb_ctx *ctx, struct feature_options *opt) +{ + int rc; + uint64_t new_compat_flags; + uint64_t new_incompat_flags; + bool close = false; + + if (!opt->show_features && !feature_write_action(opt)) + return -DER_INVAL; + + if (ddb_pool_is_open(ctx)) { + if (feature_write_action(opt) && !ctx->dc_write_mode) + return -DER_NO_PERM; + goto skip; + } + + ctx->dc_write_mode = feature_write_action(opt); + if (feature_write_action(opt) && !ctx->dc_write_mode) + return -DER_NO_PERM; + + if (!opt->path || strnlen(opt->path, PATH_MAX) == 0) + opt->path = ctx->dc_pool_path; + + rc = dv_pool_open(opt->path, &ctx->dc_poh, VOS_POF_FOR_FEATURE_FLAG); + if (rc) + return rc; + close = true; + +skip: + rc = dv_pool_get_flags(ctx->dc_poh, &new_compat_flags, &new_incompat_flags); + if (rc) { + ddb_error(ctx, "Error with pool superblock"); + goto out; + } + + if (ctx->dc_write_mode) { + if (opt->set_compat_flags || opt->clear_compat_flags) { + new_compat_flags |= (opt->set_compat_flags & VOS_POOL_COMPAT_FLAG_SUPP); + new_compat_flags &= ~(opt->clear_compat_flags & VOS_POOL_COMPAT_FLAG_SUPP); + } + if (opt->set_incompat_flags || opt->clear_incompat_flags) { + new_incompat_flags |= + (opt->set_incompat_flags & VOS_POOL_INCOMPAT_FLAG_SUPP); + new_incompat_flags &= + ~(opt->clear_incompat_flags & VOS_POOL_INCOMPAT_FLAG_SUPP); + } + rc = dv_pool_update_flags(ctx->dc_poh, new_compat_flags, new_incompat_flags); + if (rc) { + ddb_printf(ctx, "Failed to update flags: %d\n", rc); + goto out; + } + } + if (opt->show_features) { + ddb_printf(ctx, "Compat Flags: %lu\n", new_compat_flags); + ddb_printf(ctx, "Incompat Flags: %lu\n", new_incompat_flags); + } +out: + if (close) + rc = dv_pool_close(ctx->dc_poh); + ctx->dc_poh = DAOS_HDL_INVAL; + ctx->dc_write_mode = false; + + return rc; +} + +int +ddb_run_rm_pool(struct ddb_ctx *ctx, struct rm_pool_options *opt) +{ + if (ddb_pool_is_open(ctx)) { + ddb_error(ctx, "Must close pool before can open another\n"); + return -DER_BUSY; + } + + return dv_pool_destroy(opt->path); +} diff --git a/src/utils/ddb/ddb_main.c b/src/utils/ddb/ddb_main.c index 59231bfd759..a5c368f6a6a 100644 --- a/src/utils/ddb/ddb_main.c +++ b/src/utils/ddb/ddb_main.c @@ -1,5 +1,5 @@ /** - * (C) Copyright 2022 Intel Corporation. + * (C) Copyright 2022-2024 Intel Corporation. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -180,11 +180,36 @@ process_line_cb(void *cb_args, char *line, uint32_t line_len) /* ignore empty lines */ if (all_whitespace(line, line_len)) return 0; - return ddb_run_cmd(ctx, line, ctx->dc_write_mode); + return ddb_run_cmd(ctx, line); } #define str_has_value(str) ((str) != NULL && strlen(str) > 0) +static int +open_if_needed(struct ddb_ctx *ctx, struct program_args *pa, bool *open) +{ + int rc = 0; + + if (!str_has_value(pa->pa_pool_path)) { + *open = false; + goto out; + } + ctx->dc_pool_path = pa->pa_pool_path; + + if (str_has_value(pa->pa_r_cmd_run)) { + rc = ddb_parse_cmd_str(ctx, pa->pa_r_cmd_run, open); + if (rc) + return rc; + } else if (str_has_value(pa->pa_cmd_file)) { + *open = true; + } else { + *open = false; + } + +out: + return rc; +} + int ddb_main(struct ddb_io_ft *io_ft, int argc, char *argv[]) { @@ -193,6 +218,7 @@ ddb_main(struct ddb_io_ft *io_ft, int argc, char *argv[]) char *input_buf; int rc; struct ddb_ctx ctx = {0}; + bool open = true; D_ASSERT(io_ft); ctx.dc_io_ft = *io_ft; @@ -217,14 +243,17 @@ ddb_main(struct ddb_io_ft *io_ft, int argc, char *argv[]) D_GOTO(done, rc = -DER_INVAL); } - if (str_has_value(pa.pa_pool_path)) { - rc = dv_pool_open(pa.pa_pool_path, &ctx.dc_poh); + rc = open_if_needed(&ctx, &pa, &open); + if (!SUCCESS(rc)) + D_GOTO(done, rc); + if (open) { + rc = dv_pool_open(pa.pa_pool_path, &ctx.dc_poh, 0); if (!SUCCESS(rc)) D_GOTO(done, rc); } if (str_has_value(pa.pa_r_cmd_run)) { - rc = ddb_run_cmd(&ctx, pa.pa_r_cmd_run, pa.pa_write_mode); + rc = ddb_run_cmd(&ctx, pa.pa_r_cmd_run); if (!SUCCESS(rc)) D_ERROR("Command '%s' failed: "DF_RC"\n", input_buf, DP_RC(rc)); D_GOTO(done, rc); @@ -248,7 +277,7 @@ ddb_main(struct ddb_io_ft *io_ft, int argc, char *argv[]) if (input_buf[strlen(input_buf) - 1] == '\n') input_buf[strlen(input_buf) - 1] = '\0'; - rc = ddb_run_cmd(&ctx, input_buf, pa.pa_write_mode); + rc = ddb_run_cmd(&ctx, input_buf); if (!SUCCESS(rc)) { D_ERROR("Command '%s' failed: "DF_RC"\n", input_buf, DP_RC(rc)); ddb_printf(&ctx, "Command '%s' failed: "DF_RC"\n", input_buf, DP_RC(rc)); diff --git a/src/utils/ddb/ddb_printer.c b/src/utils/ddb/ddb_printer.c index a78ce92e37b..aadd7cd4b48 100644 --- a/src/utils/ddb/ddb_printer.c +++ b/src/utils/ddb/ddb_printer.c @@ -1,5 +1,5 @@ /** - * (C) Copyright 2022 Intel Corporation. + * (C) Copyright 2022-2024 Intel Corporation. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -189,6 +189,8 @@ ddb_print_superblock(struct ddb_ctx *ctx, struct ddb_superblock *sb) ddb_printf(ctx, "Pool UUID: "DF_UUIDF"\n", DP_UUID(sb->dsb_id)); ddb_printf(ctx, "Format Version: %d\n", sb->dsb_durable_format_version); ddb_printf(ctx, "Containers: %lu\n", sb->dsb_cont_nr); + ddb_printf(ctx, "Compat Flags: %lu\n", sb->dsb_compat_flags); + ddb_printf(ctx, "Incompat Flags: %lu\n", sb->dsb_incompat_flags); print_bytes(ctx, "SCM Size", sb->dsb_scm_sz); print_bytes(ctx, "NVME Size", sb->dsb_nvme_sz); print_bytes(ctx, "Block Size", sb->dsb_blk_sz); diff --git a/src/utils/ddb/ddb_vos.c b/src/utils/ddb/ddb_vos.c index b331e830fdd..64e33cde4f7 100644 --- a/src/utils/ddb/ddb_vos.c +++ b/src/utils/ddb/ddb_vos.c @@ -18,10 +18,9 @@ anchors, cb, NULL, args, NULL) int -dv_pool_open(char *path, daos_handle_t *poh) +dv_pool_open(const char *path, daos_handle_t *poh, uint32_t flags) { - struct vos_file_parts path_parts = {0}; - uint32_t flags = 0; /* Will need to be a flag to ignore uuid check */ + struct vos_file_parts path_parts = {0}; int rc; /* @@ -50,6 +49,35 @@ dv_pool_open(char *path, daos_handle_t *poh) return rc; } +int +dv_pool_destroy(const char *path) +{ + struct vos_file_parts path_parts = {0}; + int rc, flags = 0; + + rc = vos_path_parse(path, &path_parts); + if (!SUCCESS(rc)) + return rc; + + rc = vos_self_init(path_parts.vf_db_path, true, path_parts.vf_target_idx); + if (!SUCCESS(rc)) { + D_ERROR("Failed to initialize VOS with path '%s': " DF_RC "\n", + path_parts.vf_db_path, DP_RC(rc)); + return rc; + } + + if (strncmp(path_parts.vf_vos_file, "rdb", 3) == 0) + flags |= VOS_POF_RDB; + + rc = vos_pool_destroy_ex(path, path_parts.vf_pool_uuid, flags); + if (!SUCCESS(rc)) + D_ERROR("Failed to destroy pool: " DF_RC "\n", DP_RC(rc)); + + vos_self_fini(); + + return rc; +} + int dv_pool_close(daos_handle_t poh) { @@ -896,7 +924,7 @@ dv_iterate(daos_handle_t poh, struct dv_tree_path *path, bool recursive, int dv_superblock(daos_handle_t poh, dv_dump_superblock_cb cb, void *cb_args) { - struct ddb_superblock sb = {0}; + struct ddb_superblock sb = {0}; struct vos_pool *pool; struct vos_pool_df *pool_df; @@ -921,7 +949,8 @@ dv_superblock(daos_handle_t poh, dv_dump_superblock_cb cb, void *cb_args) sb.dsb_blk_sz = pool_df->pd_vea_df.vsd_blk_sz; sb.dsb_hdr_blks = pool_df->pd_vea_df.vsd_hdr_blks; sb.dsb_tot_blks = pool_df->pd_vea_df.vsd_tot_blks; - + sb.dsb_compat_flags = pool_df->pd_compat_flags; + sb.dsb_incompat_flags = pool_df->pd_incompat_flags; cb(cb_args, &sb); @@ -1851,3 +1880,70 @@ dv_vea_free_region(daos_handle_t poh, uint32_t offset, uint32_t blk_cnt) return rc; } + +int +dv_pool_update_flags(daos_handle_t poh, uint64_t compat_flags, uint64_t incompat_flags) +{ + struct vos_pool *pool; + struct vos_pool_df *pool_df; + int rc; + + pool = vos_hdl2pool(poh); + if (pool == NULL) + return -DER_INVAL; + + pool_df = pool->vp_pool_df; + + rc = umem_tx_begin(&pool->vp_umm, NULL); + if (rc != 0) + return rc; + + rc = umem_tx_add_ptr(&pool->vp_umm, &pool_df->pd_compat_flags, + sizeof(pool_df->pd_compat_flags)); + if (rc != 0) + goto end; + + pool_df->pd_compat_flags = compat_flags; + rc = umem_tx_add_ptr(&pool->vp_umm, &pool_df->pd_incompat_flags, + sizeof(pool_df->pd_incompat_flags)); + if (rc != 0) + goto end; + pool_df->pd_incompat_flags = incompat_flags; + +end: + rc = umem_tx_end(&pool->vp_umm, rc); + return rc; +} + +struct vos_pool_feature_flags { + uint64_t compat_flags; + uint64_t incompat_flags; +}; + +static int +get_flags_cb(void *cb_arg, struct ddb_superblock *sb) +{ + struct vos_pool_feature_flags *pff = cb_arg; + + pff->compat_flags = sb->dsb_compat_flags; + pff->incompat_flags = sb->dsb_incompat_flags; + + return 0; +} +int +dv_pool_get_flags(daos_handle_t poh, uint64_t *compat_flags, uint64_t *incompat_flags) +{ + int rc; + struct vos_pool_feature_flags pff; + + rc = dv_superblock(poh, get_flags_cb, &pff); + if (rc == -DER_DF_INVAL) + return rc; + + if (compat_flags) + *compat_flags = pff.compat_flags; + if (incompat_flags) + *incompat_flags = pff.incompat_flags; + + return 0; +} diff --git a/src/utils/ddb/ddb_vos.h b/src/utils/ddb/ddb_vos.h index d1bba07c541..e4a2ad26992 100644 --- a/src/utils/ddb/ddb_vos.h +++ b/src/utils/ddb/ddb_vos.h @@ -1,5 +1,5 @@ /** - * (C) Copyright 2022 Intel Corporation. + * (C) Copyright 2022-2024 Intel Corporation. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -48,8 +48,18 @@ struct ddb_array { }; /* Open and close a pool for a ddb_ctx */ -int dv_pool_open(char *path, daos_handle_t *poh); +int + dv_pool_open(const char *path, daos_handle_t *poh, uint32_t flags); int dv_pool_close(daos_handle_t poh); +int +dv_pool_destroy(const char *path); + +/* Update vos pool flags */ +int +dv_pool_update_flags(daos_handle_t poh, uint64_t compat_flags, uint64_t incompat_flags); +/* Get vos pool flags */ +int + dv_pool_get_flags(daos_handle_t poh, uint64_t *compat_flags, uint64_t *incompat_flags); /* Open and close a cont for a ddb_ctx */ int dv_cont_open(daos_handle_t poh, uuid_t uuid, daos_handle_t *coh); @@ -111,6 +121,8 @@ struct ddb_superblock { uint64_t dsb_cont_nr; uint64_t dsb_nvme_sz; uint64_t dsb_scm_sz; + uint64_t dsb_compat_flags; + uint64_t dsb_incompat_flags; uint64_t dsb_tot_blks; /* vea: Block device capacity */ uint32_t dsb_durable_format_version; uint32_t dsb_blk_sz; /* vea: Block size, 4k bytes by default */ diff --git a/src/utils/ddb/tests/ddb_commands_tests.c b/src/utils/ddb/tests/ddb_commands_tests.c index f6e5a4a89e7..ee3b8175d6a 100644 --- a/src/utils/ddb/tests/ddb_commands_tests.c +++ b/src/utils/ddb/tests/ddb_commands_tests.c @@ -362,6 +362,19 @@ dtx_abort_entry_tests(void **state) assert_success(ddb_run_dtx_act_abort(&g_ctx, &opt)); } +static void +feature_cmd_tests(void **state) +{ + struct dt_vos_pool_ctx *tctx; + struct feature_options opt = {0}; + + tctx = *state; + assert_invalid(ddb_run_feature(&g_ctx, &opt)); + opt.path = tctx->dvt_pmem_file; + opt.show_features = true; + assert_success(ddb_run_feature(&g_ctx, &opt)); +} + /* * -------------------------------------------------------------- * End test functions @@ -377,7 +390,7 @@ dcv_suit_setup(void **state) /* test setup creates the pool, but doesn't open it ... leave it open for these tests */ tctx = *state; - assert_success(dv_pool_open(tctx->dvt_pmem_file, &tctx->dvt_poh)); + assert_success(dv_pool_open(tctx->dvt_pmem_file, &tctx->dvt_poh, 0)); g_ctx.dc_poh = tctx->dvt_poh; @@ -406,19 +419,20 @@ int ddb_commands_tests_run() { const struct CMUnitTest tests[] = { - TEST(quit_cmd_tests), - TEST(ls_cmd_tests), - TEST(dump_value_cmd_tests), - TEST(dump_ilog_cmd_tests), - TEST(dump_superblock_cmd_tests), - TEST(dump_dtx_cmd_tests), - TEST(rm_cmd_tests), - TEST(load_cmd_tests), - TEST(rm_ilog_cmd_tests), - TEST(process_ilog_cmd_tests), - TEST(clear_cmt_dtx_cmd_tests), - TEST(dtx_commit_entry_tests), - TEST(dtx_abort_entry_tests), + TEST(quit_cmd_tests), + TEST(ls_cmd_tests), + TEST(dump_value_cmd_tests), + TEST(dump_ilog_cmd_tests), + TEST(dump_superblock_cmd_tests), + TEST(dump_dtx_cmd_tests), + TEST(rm_cmd_tests), + TEST(load_cmd_tests), + TEST(rm_ilog_cmd_tests), + TEST(process_ilog_cmd_tests), + TEST(clear_cmt_dtx_cmd_tests), + TEST(dtx_commit_entry_tests), + TEST(dtx_abort_entry_tests), + TEST(feature_cmd_tests), }; return cmocka_run_group_tests_name("DDB commands tests", tests, diff --git a/src/utils/ddb/tests/ddb_main_tests.c b/src/utils/ddb/tests/ddb_main_tests.c index b60b579674d..ba7b3cf0958 100644 --- a/src/utils/ddb/tests/ddb_main_tests.c +++ b/src/utils/ddb/tests/ddb_main_tests.c @@ -241,7 +241,7 @@ ddb_main_suit_setup(void **state) /* test setup creates the pool, but doesn't open it ... leave it open for these tests */ tctx = *state; - assert_success(dv_pool_open(tctx->dvt_pmem_file, &tctx->dvt_poh)); + assert_success(dv_pool_open(tctx->dvt_pmem_file, &tctx->dvt_poh, 0)); return 0; } diff --git a/src/utils/ddb/tests/ddb_parse_tests.c b/src/utils/ddb/tests/ddb_parse_tests.c index 46da5d623a3..155b9c1bcc4 100644 --- a/src/utils/ddb/tests/ddb_parse_tests.c +++ b/src/utils/ddb/tests/ddb_parse_tests.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include "ddb_cmocka.h" @@ -324,6 +325,29 @@ keys_are_parsed_correctly(void **state) daos_iov_free(&key); } +static void +pool_flags_tests(void **state) +{ + struct ddb_ctx ctx = {.dc_io_ft.ddb_print_message = fake_print, + .dc_io_ft.ddb_print_error = fake_print}; + uint64_t compat_flags, incompat_flags; + uint64_t expected_flags; + int rc; + + expected_flags = VOS_POOL_COMPAT_FLAG_IMMUTABLE | VOS_POOL_COMPAT_FLAG_SKIP_START; + rc = ddb_feature_string2flags(&ctx, "immutable,skip_start", &compat_flags, &incompat_flags); + assert_success(rc); + assert(compat_flags == expected_flags); + expected_flags = 0; + if (incompat_flags != expected_flags) { + print_error("ERROR: %lu != %lu\n", incompat_flags, expected_flags); + assert_success(-DER_INVAL); + } + + rc = ddb_feature_string2flags(&ctx, "immutablexxx", &compat_flags, &incompat_flags); + assert_rc_equal(-DER_INVAL, rc); +} + /* * ----------------------------------------------- * Execute @@ -334,11 +358,8 @@ int ddb_parse_tests_run() { static const struct CMUnitTest tests[] = { - TEST(vos_file_parts_tests), - TEST(string_to_argv_tests), - TEST(parse_args_tests), - TEST(parse_dtx_id_tests), - TEST(keys_are_parsed_correctly), + TEST(vos_file_parts_tests), TEST(string_to_argv_tests), TEST(parse_args_tests), + TEST(parse_dtx_id_tests), TEST(keys_are_parsed_correctly), TEST(pool_flags_tests), }; return cmocka_run_group_tests_name("DDB helper parsing function tests", tests, NULL, NULL); diff --git a/src/utils/ddb/tests/ddb_test_driver.c b/src/utils/ddb/tests/ddb_test_driver.c index 2f9c24f931f..64d4491d800 100644 --- a/src/utils/ddb/tests/ddb_test_driver.c +++ b/src/utils/ddb/tests/ddb_test_driver.c @@ -4,16 +4,6 @@ * SPDX-License-Identifier: BSD-2-Clause-Patent */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ddb_cmocka.h" #include "ddb_test_driver.h" #define DEFINE_IOV(str) {.iov_buf = str, .iov_buf_len = strlen(str), .iov_len = strlen(str)} @@ -313,19 +303,25 @@ int ddb_teardown_vos(void **state) { struct dt_vos_pool_ctx *tctx = *state; + int rc = 0; if (tctx == NULL) { fail_msg("Test context not setup correctly"); return -DER_UNKNOWN; } - vos_self_init("/mnt/daos", false, 0); - assert_success(vos_pool_destroy(tctx->dvt_pmem_file, tctx->dvt_pool_uuid)); - vos_self_fini(); + if (tctx->dvt_special_pool_destroy) { + rc = dv_pool_destroy(tctx->dvt_pmem_file); + } else { + vos_self_init("/mnt/daos", false, 0); + assert_success(vos_pool_destroy(tctx->dvt_pmem_file, tctx->dvt_pool_uuid)); + vos_self_fini(); + } + close(tctx->dvt_fd); D_FREE(tctx); - return 0; + return rc; } void diff --git a/src/utils/ddb/tests/ddb_test_driver.h b/src/utils/ddb/tests/ddb_test_driver.h index 229112d48d9..e5cc649d0d6 100644 --- a/src/utils/ddb/tests/ddb_test_driver.h +++ b/src/utils/ddb/tests/ddb_test_driver.h @@ -1,11 +1,23 @@ /** - * (C) Copyright 2022 Intel Corporation. + * (C) Copyright 2022-2024 Intel Corporation. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ #ifndef DAOS_DDB_TEST_DRIVER_H #define DAOS_DDB_TEST_DRIVER_H +#include "ddb_cmocka.h" +#include "ddb_vos.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + extern bool g_verbose; extern const char *g_uuids_str[10]; extern const char *g_invalid_uuid_str; @@ -29,6 +41,7 @@ struct dt_vos_pool_ctx { uint32_t dvt_obj_count; uint32_t dvt_dkey_count; uint32_t dvt_akey_count; + bool dvt_special_pool_destroy; }; daos_unit_oid_t dvt_gen_uoid(uint32_t i); diff --git a/src/utils/ddb/tests/ddb_vos_tests.c b/src/utils/ddb/tests/ddb_vos_tests.c index f0c73a4f367..16cda54c04c 100644 --- a/src/utils/ddb/tests/ddb_vos_tests.c +++ b/src/utils/ddb/tests/ddb_vos_tests.c @@ -1,5 +1,5 @@ /** - * (C) Copyright 2022-2023 Intel Corporation. + * (C) Copyright 2022-2024 Intel Corporation. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -181,13 +181,13 @@ open_pool_test(void **state) daos_handle_t poh; struct dt_vos_pool_ctx *tctx = *state; - assert_rc_equal(-DER_INVAL, dv_pool_open("/bad/path", &poh)); + assert_rc_equal(-DER_INVAL, dv_pool_open("/bad/path", &poh, 0)); - assert_success(dv_pool_open(tctx->dvt_pmem_file, &poh)); + assert_success(dv_pool_open(tctx->dvt_pmem_file, &poh, 0)); assert_success(dv_pool_close(poh)); /* should be able to open again after closing */ - assert_success(dv_pool_open(tctx->dvt_pmem_file, &poh)); + assert_success(dv_pool_open(tctx->dvt_pmem_file, &poh, 0)); assert_success(dv_pool_close(poh)); } @@ -1054,7 +1054,16 @@ delete_path_parts_tests(void **state) static int dv_suit_setup(void **state) { - return ddb_test_setup_vos(state); + int rc; + struct dt_vos_pool_ctx *tctx; + + rc = ddb_test_setup_vos(state); + if (rc) + return rc; + tctx = *state; + tctx->dvt_special_pool_destroy = true; + + return 0; } static int @@ -1077,7 +1086,7 @@ dv_test_setup(void **state) active_entry_handler_called = 0; committed_entry_handler_called = 0; - assert_success(dv_pool_open(tctx->dvt_pmem_file, &tctx->dvt_poh)); + assert_success(dv_pool_open(tctx->dvt_pmem_file, &tctx->dvt_poh, 0)); return 0; } @@ -1090,6 +1099,25 @@ dv_test_teardown(void **state) return 0; } +static void +pool_flags_tests(void **state) +{ + daos_handle_t poh; + struct dt_vos_pool_ctx *tctx = *state; + uint64_t compat_flags; + uint64_t incompat_flags; + + assert_success(dv_pool_open(tctx->dvt_pmem_file, &poh, VOS_POF_FOR_FEATURE_FLAG)); + assert_success(dv_pool_get_flags(poh, &compat_flags, &incompat_flags)); + assert(compat_flags == 0); + assert(incompat_flags == 0); + assert_success( + dv_pool_update_flags(poh, VOS_POOL_COMPAT_FLAG_SUPP, VOS_POOL_INCOMPAT_FLAG_SUPP)); + assert_success(dv_pool_get_flags(poh, &compat_flags, &incompat_flags)); + assert(compat_flags == VOS_POOL_COMPAT_FLAG_SUPP); + assert(incompat_flags == VOS_POOL_INCOMPAT_FLAG_SUPP); + assert_success(dv_pool_close(poh)); +} /* * All these tests use the same VOS tree that is created at suit_setup. Therefore, tests @@ -1097,28 +1125,29 @@ dv_test_teardown(void **state) */ #define TEST(x) { #x, x, dv_test_setup, dv_test_teardown } const struct CMUnitTest dv_test_cases[] = { - { "open_pool", open_pool_test, NULL, NULL }, /* don't want this test to run with setup */ - TEST(list_items_test), - TEST(get_cont_uuid_from_idx_tests), - TEST(get_dkey_from_idx_tests), - TEST(get_akey_from_idx_tests), - TEST(get_recx_from_idx_tests), - TEST(get_value_tests), - TEST(get_obj_ilog_tests), - TEST(abort_obj_ilog_tests), - TEST(get_dkey_ilog_tests), - TEST(abort_dkey_ilog_tests), - TEST(get_superblock_tests), - TEST(obj_id_2_ddb_test), - TEST(get_dtx_tables_tests), - TEST(delete_path_parts_tests), - TEST(verify_correct_params_for_update_value_tests), - TEST(update_value_to_modify_tests), - TEST(update_value_to_insert_tests), - TEST(clear_committed_table), - TEST(dtx_commit_active_table), - TEST(dtx_abort_active_table), - TEST(path_verify), + {"open_pool", open_pool_test, NULL, NULL}, /* don't want this test to run with setup */ + TEST(list_items_test), + TEST(get_cont_uuid_from_idx_tests), + TEST(get_dkey_from_idx_tests), + TEST(get_akey_from_idx_tests), + TEST(get_recx_from_idx_tests), + TEST(get_value_tests), + TEST(get_obj_ilog_tests), + TEST(abort_obj_ilog_tests), + TEST(get_dkey_ilog_tests), + TEST(abort_dkey_ilog_tests), + TEST(get_superblock_tests), + TEST(obj_id_2_ddb_test), + TEST(get_dtx_tables_tests), + TEST(delete_path_parts_tests), + TEST(verify_correct_params_for_update_value_tests), + TEST(update_value_to_modify_tests), + TEST(update_value_to_insert_tests), + TEST(clear_committed_table), + TEST(dtx_commit_active_table), + TEST(dtx_abort_active_table), + TEST(path_verify), + {"pool_flag_update", pool_flags_tests, NULL, NULL}, }; int diff --git a/src/vos/vos_pool.c b/src/vos/vos_pool.c index af958eafd5d..cf1c72ebaaa 100644 --- a/src/vos/vos_pool.c +++ b/src/vos/vos_pool.c @@ -1372,7 +1372,8 @@ pool_open(void *ph, struct vos_pool_df *pool_df, unsigned int flags, void *metri } pool->vp_metrics = metrics; - if (bio_nvme_configured(SMD_DEV_TYPE_DATA) && pool_df->pd_nvme_sz != 0) { + if (!(flags & VOS_POF_FOR_FEATURE_FLAG) && bio_nvme_configured(SMD_DEV_TYPE_DATA) && + pool_df->pd_nvme_sz != 0) { struct vea_unmap_context unmap_ctxt; struct vos_pool_metrics *vp_metrics = metrics; void *vea_metrics = NULL; @@ -1750,3 +1751,47 @@ vos_pool_biov2addr(daos_handle_t poh, struct bio_iov *biov) return umem_off2ptr(vos_pool2umm(pool), bio_iov2raw_off(biov)); } + +bool +vos_pool_feature_skip_start(daos_handle_t poh) +{ + struct vos_pool *vos_pool; + + vos_pool = vos_hdl2pool(poh); + D_ASSERT(vos_pool != NULL); + + return vos_pool->vp_pool_df->pd_compat_flags & VOS_POOL_COMPAT_FLAG_SKIP_START; +} + +bool +vos_pool_feature_immutable(daos_handle_t poh) +{ + struct vos_pool *vos_pool; + + vos_pool = vos_hdl2pool(poh); + D_ASSERT(vos_pool != NULL); + + return vos_pool->vp_pool_df->pd_compat_flags & VOS_POOL_COMPAT_FLAG_IMMUTABLE; +} + +bool +vos_pool_feature_skip_rebuild(daos_handle_t poh) +{ + struct vos_pool *vos_pool; + + vos_pool = vos_hdl2pool(poh); + D_ASSERT(vos_pool != NULL); + + return vos_pool->vp_pool_df->pd_compat_flags & VOS_POOL_COMPAT_FLAG_SKIP_REBUILD; +} + +bool +vos_pool_feature_skip_dtx_resync(daos_handle_t poh) +{ + struct vos_pool *vos_pool; + + vos_pool = vos_hdl2pool(poh); + D_ASSERT(vos_pool != NULL); + + return vos_pool->vp_pool_df->pd_compat_flags & VOS_POOL_COMPAT_FLAG_SKIP_DTX_RESYNC; +}