diff --git a/fabrics.c b/fabrics.c index af27b726e6..6ff9cc4c13 100644 --- a/fabrics.c +++ b/fabrics.c @@ -58,6 +58,14 @@ #define NVMF_DEF_DISC_TMO 30 +#if DEFAULT_EPCSD_ENABLED +#define EPCSD_DISABLED_DEFAULT_STR +#define EPCSD_ENABLED_DEFAULT_STR " (default)" +#else +#define EPCSD_ENABLED_DEFAULT_STR +#define EPCSD_DISABLED_DEFAULT_STR " (default)" +#endif + /* Name of file to output log pages in their raw format */ static char *raw; static bool persistent; @@ -197,6 +205,7 @@ static int setup_common_context(struct libnvmf_context *fctx, struct hook_fabrics_data { struct nvmf_args *fa; + struct libnvme_global_ctx *ctx; nvme_print_flags_t flags; bool quiet; char *raw; @@ -322,6 +331,8 @@ static int set_fabrics_options(struct libnvmf_context *fctx, static int hook_parser_next_line(struct libnvmf_context *fctx, void *user_data) { struct hook_fabrics_data *hfd = user_data; + bool epcsd_enabled = false, epcsd_disabled = false; + struct libnvme_host *h = NULL; struct nvmf_args fa; char *ptr, *p; static char line[4096]; @@ -329,6 +340,8 @@ static int hook_parser_next_line(struct libnvmf_context *fctx, void *user_data) bool force = false; NVMF_ARGS(opts, fa, + OPT_FLAG("epcsd", 0, &epcsd_enabled, "Enable persistent discovery for controllers that support it"), + OPT_FLAG("no-epcsd", 0, &epcsd_disabled, "Disable persistent discovery for controllers that support it"), OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation")); @@ -349,6 +362,11 @@ static int hook_parser_next_line(struct libnvmf_context *fctx, void *user_data) fa.subsysnqn = NVME_DISC_SUBSYS_NAME; if (argconfig_parse(argc, hfd->argv, "config", opts)) continue; + + if (epcsd_enabled && epcsd_disabled) { + fprintf(stderr, "--epcsd and --no-epcsd are mutually exclusive\n"); + continue; + } } while (!fa.transport && !fa.traddr); if (!fa.trsvcid) @@ -361,6 +379,13 @@ static int hook_parser_next_line(struct libnvmf_context *fctx, void *user_data) libnvmf_context_set_discovery_hooks(fctx, hook_discovery_log, hook_parser_init, hook_parser_cleanup, hook_parser_next_line); + libnvme_get_host(hfd->ctx, fa.hostnqn, fa.hostid, &h); + if (epcsd_enabled) + libnvme_host_set_epcsd_enabled(h, true); + + if (epcsd_disabled) + libnvme_host_set_epcsd_enabled(h, false); + return 0; } @@ -557,13 +582,17 @@ int fabrics_discovery(const char *desc, int argc, char **argv, bool connect) char *device = NULL; bool force = false; bool json_config = false; + bool epcsd_enabled = false, epcsd_disabled = false; bool nbft = false, nonbft = false; char *nbft_path = NBFT_SYSFS_PATH; char *owner = NULL; + struct libnvme_host *h = NULL; NVMF_ARGS(opts, fa, OPT_STRING("device", 'd', "DEV", &device, "use existing discovery controller device"), OPT_FILE("raw", 'r', &raw, "save raw output to file"), + OPT_FLAG("epcsd", 0, &epcsd_enabled, "Enable persistent discovery for controllers that support it." EPCSD_ENABLED_DEFAULT_STR), + OPT_FLAG("no-epcsd", 0, &epcsd_disabled, "Disable persistent discovery for controllers that support it." EPCSD_DISABLED_DEFAULT_STR), OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), OPT_FLAG("quiet", 0, &quiet, "suppress already connected errors"), OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), @@ -588,6 +617,11 @@ int fabrics_discovery(const char *desc, int argc, char **argv, bool connect) return ret; } + if (epcsd_enabled && epcsd_disabled) { + fprintf(stderr, "--epcsd and --no-epcsd options are mutually exclusive\n"); + return -EINVAL; + } + if (!strcmp(config_file, "none")) config_file = NULL; @@ -637,6 +671,7 @@ int fabrics_discovery(const char *desc, int argc, char **argv, bool connect) struct hook_fabrics_data dld = { .fa = &fa, + .ctx = ctx, .flags = flags, .raw = raw, }; @@ -662,6 +697,12 @@ int fabrics_discovery(const char *desc, int argc, char **argv, bool connect) goto out_free; } + libnvme_get_host(ctx, fa.hostnqn, fa.hostid, &h); + if (epcsd_enabled) + libnvme_host_set_epcsd_enabled(h, true); + + if (epcsd_disabled) + libnvme_host_set_epcsd_enabled(h, false); ret = libnvmf_discovery(ctx, fctx, connect, force); out_free: diff --git a/libnvme/doc/config-schema.json b/libnvme/doc/config-schema.json index 79fac1c6b5..8ad9e3460d 100644 --- a/libnvme/doc/config-schema.json +++ b/libnvme/doc/config-schema.json @@ -41,6 +41,10 @@ "description": "Enable/disable Persistent Discovery Controller", "type": "boolean" }, + "supported_persistent_discovery_ctrl": { + "description": "Enable/disable persistent discovery for controllers that support it.", + "type": "boolean" + }, "subsystems": { "description": "Array of NVMe subsystem properties", "type": "array", diff --git a/libnvme/doc/config-schema.json.in b/libnvme/doc/config-schema.json.in index 79fac1c6b5..8ad9e3460d 100644 --- a/libnvme/doc/config-schema.json.in +++ b/libnvme/doc/config-schema.json.in @@ -41,6 +41,10 @@ "description": "Enable/disable Persistent Discovery Controller", "type": "boolean" }, + "supported_persistent_discovery_ctrl": { + "description": "Enable/disable persistent discovery for controllers that support it.", + "type": "boolean" + }, "subsystems": { "description": "Array of NVMe subsystem properties", "type": "array", diff --git a/libnvme/libnvme/accessors.i b/libnvme/libnvme/accessors.i index 0060e8d269..4c97efdc6e 100644 --- a/libnvme/libnvme/accessors.i +++ b/libnvme/libnvme/accessors.i @@ -189,8 +189,10 @@ Subsystem.__setattr__ = _nvme_guarded_setattr /* struct libnvme_host */ %rename(Host) libnvme_host; %rename(libnvme_host_pdc_enabled_set) libnvme_host_set_pdc_enabled; +%rename(libnvme_host_epcsd_enabled_set) libnvme_host_set_epcsd_enabled; %{ #define libnvme_host_pdc_enabled_set libnvme_host_set_pdc_enabled + #define libnvme_host_epcsd_enabled_set libnvme_host_set_epcsd_enabled %} struct libnvme_host { %immutable hostnqn; diff --git a/libnvme/src/libnvme.ld b/libnvme/src/libnvme.ld index 9c7a10dd34..c793c75a20 100644 --- a/libnvme/src/libnvme.ld +++ b/libnvme/src/libnvme.ld @@ -64,8 +64,10 @@ LIBNVME_3 { libnvme_get_uuid_list; libnvme_get_version; libnvme_host_get_global_ctx; + libnvme_host_is_epcsd_enabled; libnvme_host_is_pdc_enabled; libnvme_host_release_fds; + libnvme_host_set_epcsd_enabled; libnvme_host_set_pdc_enabled; libnvme_init_ctrl; libnvme_namespace_first_path; diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index dd41dbd035..363c858e98 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -2351,6 +2351,20 @@ static int _nvmf_discovery(struct libnvme_global_ctx *ctx, } numrec = le64_to_cpu(log->numrec); + + for (int i = 0; i < numrec; i++) { + struct nvmf_disc_log_entry *e = &log->entries[i]; + uint16_t eflags = le16_to_cpu(e->eflags); + + if ((e->subtype == NVME_NQN_DISC || + e->subtype == NVME_NQN_CURR) && + (eflags & NVMF_DISC_EFLAGS_EPCSD) && + libnvme_host_is_epcsd_enabled(h, DEFAULT_EPCSD_ENABLED)) { + libnvmf_context_set_persistent(fctx, true); + break; + } + } + if (fctx->hooks.discovery_log) fctx->hooks.discovery_log(fctx, connect, log, numrec, fctx->hooks.user_data); diff --git a/libnvme/src/nvme/json.c b/libnvme/src/nvme/json.c index c3596ad731..fa2e2b76f1 100644 --- a/libnvme/src/nvme/json.c +++ b/libnvme/src/nvme/json.c @@ -175,6 +175,9 @@ static void json_parse_host(struct libnvme_global_ctx *ctx, struct json_object * attr_obj = json_object_object_get(host_obj, "persistent_discovery_ctrl"); if (attr_obj) libnvme_host_set_pdc_enabled(h, json_object_get_boolean(attr_obj)); + attr_obj = json_object_object_get(host_obj, "supported_persistent_discovery_ctrl"); + if (attr_obj) + libnvme_host_set_epcsd_enabled(h, json_object_get_boolean(attr_obj)); subsys_array = json_object_object_get(host_obj, "subsystems"); if (!subsys_array) return; @@ -437,6 +440,9 @@ int json_update_config(struct libnvme_global_ctx *ctx, int fd) if (h->pdc_enabled_valid) json_object_object_add(host_obj, "persistent_discovery_ctrl", json_object_new_boolean(h->pdc_enabled)); + if (h->epcsd_enabled_valid) + json_object_object_add(host_obj, "supported_persistent_discovery_ctrl", + json_object_new_boolean(h->epcsd_enabled)); subsys_array = json_object_new_array(); libnvme_for_each_subsystem(h, s) { json_update_subsys(subsys_array, s); @@ -664,6 +670,9 @@ int json_dump_tree(struct libnvme_global_ctx *ctx) if (h->pdc_enabled_valid) json_object_object_add(host_obj, "persistent_discovery_ctrl", json_object_new_boolean(h->pdc_enabled)); + if (h->epcsd_enabled_valid) + json_object_object_add(host_obj, "supported_persistent_discovery_ctrl", + json_object_new_boolean(h->epcsd_enabled)); subsys_array = json_object_new_array(); libnvme_for_each_subsystem(h, s) { json_dump_subsys(subsys_array, s); diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index d84ab763ad..4b28edda73 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -395,6 +395,13 @@ struct libnvme_host { // !generate-accessors:read=generated,write=none !generat */ bool pdc_enabled; // !access:read=none,write=custom bool pdc_enabled_valid; // !access:read=none + + /* epcsd_enabled and epcsd_enabled_valid work together. epcsd_enabled_valid, + * when true, indicates that epcsd_enabled has been explicitly defined. + * epcsd_enabled_valid is internal meta-data for epcsd_enabled. + */ + bool epcsd_enabled; // !access:read=none,write=custom + bool epcsd_enabled_valid; // !access:read=none }; struct libnvme_fabric_options { // !generate-accessors diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c index 4ca0cd53f0..26beaf0f52 100644 --- a/libnvme/src/nvme/tree.c +++ b/libnvme/src/nvme/tree.c @@ -225,6 +225,21 @@ __libnvme_public struct libnvme_global_ctx *libnvme_host_get_global_ctx( return h->ctx; } +__libnvme_public void libnvme_host_set_epcsd_enabled( + libnvme_host_t h, bool enabled) +{ + h->epcsd_enabled_valid = true; + h->epcsd_enabled = enabled; +} + +__libnvme_public bool libnvme_host_is_epcsd_enabled( + libnvme_host_t h, bool fallback) +{ + if (h->epcsd_enabled_valid) + return h->epcsd_enabled; + return fallback; +} + __libnvme_public void libnvme_host_set_pdc_enabled( libnvme_host_t h, bool enabled) { diff --git a/libnvme/src/nvme/tree.h b/libnvme/src/nvme/tree.h index a20ef951a6..21f124cd75 100644 --- a/libnvme/src/nvme/tree.h +++ b/libnvme/src/nvme/tree.h @@ -76,6 +76,28 @@ libnvme_host_t libnvme_next_host(struct libnvme_global_ctx *ctx, */ struct libnvme_global_ctx *libnvme_host_get_global_ctx(libnvme_host_t h); +/** + * libnvme_host_set_epcsd_enabled() - Set Explicit Persistent Discovery Controller flag + * @h: Host for which the falg should be set + * @enabled: The bool to set the enabled flag + * + * When libnvme_host_set_epcsd_enabled() is not used to set the PDC flag, + * libnvme_host_is_epcsd_enabled() will return the default value which was + * passed into the function and not the undefined flag value. + */ +void libnvme_host_set_epcsd_enabled(libnvme_host_t h, bool enabled); + +/** + * libnvme_host_is_epcsd_enabled() - Is Persistenct Discovery Controller enabled + * @h: Host which to check if PDC is enabled + * @fallback: The fallback default value of the flag when + * @libnvme_host_set_epcsd_enabled has not be used + * to set the flag. + * + * Return: true if PDC is enabled for @h, else false + */ +bool libnvme_host_is_epcsd_enabled(libnvme_host_t h, bool fallback); + /** * libnvme_host_set_pdc_enabled() - Set Persistent Discovery Controller flag * @h: Host for which the falg should be set diff --git a/meson.build b/meson.build index e4e654b109..f2b6cccf62 100644 --- a/meson.build +++ b/meson.build @@ -182,6 +182,8 @@ conf.set('NVME_VERSION', '"@0@"'.format(meson.project_version())) conf.set('LIBNVME_VERSION', '"@0@"'.format(meson.project_version())) conf.set10('DEFAULT_PDC_ENABLED', get_option('pdc-enabled')) +conf.set10('DEFAULT_EPCSD_ENABLED', get_option('default-epcsd-enabled')) + # local (cross-compilable) implementations of ccan configure steps conf.set10( diff --git a/meson_options.txt b/meson_options.txt index 7549b115c1..44224350f9 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -95,6 +95,12 @@ option( value : false, description : 'set default Persistent Discovery Controllers behavior' ) +option( + 'default-epcsd-enabled', + type: 'boolean', + value : true, + description : 'by default set Supported Persistent Discovery Controllers to be persistent' +) option( 'rundir', type: 'string',