From 5e98dfd126cff27f2f093ce2e2398dd1048ff9e8 Mon Sep 17 00:00:00 2001 From: suman chakraborty Date: Tue, 27 Mar 2018 10:28:48 +0530 Subject: [PATCH] nvmf: add capability to add namespaces dynamically during active connection 1) The user should provide MaxNamespaces during the construction of the subsystem 2) The namespace which is added should have nsid less than or equal to MaxNamespaces 3) If the user does not provides MaxNamespaces then the exsisting behaviour continues where the nisd can grow dynamically when it is not connected. Change-Id: I54769d9669575a5f6bf56fe5a262191ac51c474d Signed-off-by: suman chakraborty Reviewed-on: https://review.gerrithub.io/405375 Reviewed-by: Daniel Verkamp Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris --- doc/jsonrpc.md | 1 + etc/spdk/nvmf.conf.in | 9 ++++++--- lib/event/subsystems/nvmf/conf.c | 8 +++++++- lib/event/subsystems/nvmf/nvmf_rpc.c | 5 ++++- lib/nvmf/nvmf_internal.h | 2 ++ lib/nvmf/subsystem.c | 10 ++++++++++ scripts/rpc.py | 2 ++ scripts/rpc/nvmf.py | 3 +++ 8 files changed, 35 insertions(+), 5 deletions(-) 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(",")]