diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 8fb6e3d0f..54555ed7e 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -244,6 +244,7 @@ hosts | Optional | array | Array of strings containing a allow_any_host | Optional | boolean | Allow any host (`true`) or enforce allowed host whitelist (`false`). Default: `false`. serial_number | Required | string | Serial number of virtual controller namespaces | Optional | array | Array of @ref rpc_construct_nvmf_subsystem_namespace objects. Default: No namespaces. +MaxNamespaces | Optional | number | Maximum number of namespaces that can be attached to the subsystem. Default: 0 (Unlimited) ### listen_address {#rpc_construct_nvmf_subsystem_listen_address} diff --git a/etc/spdk/nvmf.conf.in b/etc/spdk/nvmf.conf.in index 66d5fe1bd..a93963908 100644 --- a/etc/spdk/nvmf.conf.in +++ b/etc/spdk/nvmf.conf.in @@ -114,11 +114,13 @@ # - Between 0 and 255 Host directives are allowed. This defines the # NQNs of allowed hosts. If no Host directive is specified, all hosts # are allowed to connect. -# - Between 0 and 255 Namespace directives are allowed. These define the +# - Between 0 and 255 Namespace directives are allowed. These define the # namespaces accessible from this subsystem. +# The user must specify MaxNamespaces to allow for adding namespaces +# during active connection. By default it is 0 # The user must specify a bdev name for each namespace, and may optionally -# specify a namespace ID. If nsid is omitted, the namespace will be -# assigned the next available NSID. The NSID must be unique within the +# specify a namespace ID. If nsid is omitted, the namespace will be +# assigned the next available NSID. The NSID must be unique within the # subsystem. # Syntax: # Namespace [] @@ -130,6 +132,7 @@ AllowAnyHost No Host nqn.2016-06.io.spdk:init SN SPDK00000000000001 + MaxNamespaces 20 Namespace Nvme0n1 1 Namespace Nvme1n1 2 diff --git a/lib/event/subsystems/nvmf/conf.c b/lib/event/subsystems/nvmf/conf.c index a3591dc0c..1b3147bc9 100644 --- a/lib/event/subsystems/nvmf/conf.c +++ b/lib/event/subsystems/nvmf/conf.c @@ -138,10 +138,16 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) bool allow_any_host; const char *sn; struct spdk_nvmf_subsystem *subsystem; + int num_ns; nqn = spdk_conf_section_get_val(sp, "NQN"); mode = spdk_conf_section_get_val(sp, "Mode"); lcore = spdk_conf_section_get_intval(sp, "Core"); + num_ns = spdk_conf_section_get_intval(sp, "MaxNamespaces"); + + if (num_ns < 1) { + num_ns = 0; + } /* Mode is no longer a valid parameter, but print out a nice * message if it exists to inform users. @@ -173,7 +179,7 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) return -1; } - subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); + subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, num_ns); if (subsystem == NULL) { goto done; } diff --git a/lib/event/subsystems/nvmf/nvmf_rpc.c b/lib/event/subsystems/nvmf/nvmf_rpc.c index bfed7b05c..55a538e3c 100644 --- a/lib/event/subsystems/nvmf/nvmf_rpc.c +++ b/lib/event/subsystems/nvmf/nvmf_rpc.c @@ -532,6 +532,7 @@ struct rpc_subsystem { char *pci_address; char *serial_number; struct rpc_namespaces namespaces; + uint32_t num_ns; }; static void @@ -570,6 +571,7 @@ static const struct spdk_json_object_decoder rpc_subsystem_decoders[] = { {"allow_any_host", offsetof(struct rpc_subsystem, allow_any_host), spdk_json_decode_bool, true}, {"serial_number", offsetof(struct rpc_subsystem, serial_number), spdk_json_decode_string, true}, {"namespaces", offsetof(struct rpc_subsystem, namespaces), decode_rpc_namespaces, true}, + {"max_namespaces", offsetof(struct rpc_subsystem, num_ns), spdk_json_decode_uint32, true}, }; static void @@ -613,7 +615,8 @@ spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_request *request, SPDK_NOTICELOG("Ignoring it and continuing.\n"); } - subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, req.nqn, SPDK_NVMF_SUBTYPE_NVME, 0); + subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, req.nqn, SPDK_NVMF_SUBTYPE_NVME, + req.num_ns); if (!subsystem) { goto invalid; } diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index a3aac7022..38b54aede 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -204,6 +204,8 @@ struct spdk_nvmf_subsystem { /* Array of pointers to namespaces of size max_nsid indexed by nsid - 1 */ struct spdk_nvmf_ns **ns; uint32_t max_nsid; + /* This is the maximum allowed nsid to a subsystem */ + uint32_t max_allowed_nsid; uint32_t num_allocated_nsid; TAILQ_HEAD(, spdk_nvmf_ctrlr) ctrlrs; diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 982e08687..8f2ab6662 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -265,6 +265,11 @@ spdk_nvmf_subsystem_create(struct spdk_nvmf_tgt *tgt, subsystem->id = sid; subsystem->subtype = type; subsystem->max_nsid = num_ns; + /* + * Initially max_nsid and max_allowed_nsid will be same. If max_allowed_nsid is zero nsid range can grow dynamically + * but if it is more than 1 nsid range cannot be extended beyond max_allowed_nsid + */ + subsystem->max_allowed_nsid = num_ns; subsystem->num_allocated_nsid = 0; subsystem->next_cntlid = 0; snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn); @@ -894,6 +899,11 @@ spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bd return 0; } + if ((subsystem->max_allowed_nsid > 0) && (opts.nsid > subsystem->max_allowed_nsid)) { + SPDK_ERRLOG("Can't extend NSID range above MaxNamespaces\n"); + return 0; + } + if (opts.nsid > subsystem->max_nsid || (opts.nsid == 0 && subsystem->num_allocated_nsid == subsystem->max_nsid)) { struct spdk_nvmf_ns **new_ns_array; diff --git a/scripts/rpc.py b/scripts/rpc.py index 8d1775640..a325a8f5b 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -566,6 +566,8 @@ if __name__ == "__main__": Format: 'bdev_name1[:nsid1] bdev_name2[:nsid2] bdev_name3[:nsid3]' etc Example: '1:Malloc0 2:Malloc1 3:Malloc2' *** The devices must pre-exist ***""") + p.add_argument("-m", "--max-namespaces", help="Maximum number of namespaces allowed to added during active connection", + type=int, default=0) p.set_defaults(func=construct_nvmf_subsystem) def delete_nvmf_subsystem(args): diff --git a/scripts/rpc/nvmf.py b/scripts/rpc/nvmf.py index 23c548daf..3e17413ab 100755 --- a/scripts/rpc/nvmf.py +++ b/scripts/rpc/nvmf.py @@ -8,6 +8,9 @@ def construct_nvmf_subsystem(client, args): 'serial_number': args.serial_number, } + if args.max_namespaces: + params['max_namespaces'] = args.max_namespaces + if args.listen: params['listen_addresses'] = [dict(u.split(":", 1) for u in a.split(" ")) for a in args.listen.split(",")]