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 <suman.chakraborty@wdc.com>
Reviewed-on: https://review.gerrithub.io/405375
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
suman chakraborty 2018-03-27 10:28:48 +05:30 committed by Jim Harris
parent 3709dfd674
commit 5e98dfd126
8 changed files with 35 additions and 5 deletions

View File

@ -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}

View File

@ -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 <bdev_name> [<nsid>]
@ -130,6 +132,7 @@
AllowAnyHost No
Host nqn.2016-06.io.spdk:init
SN SPDK00000000000001
MaxNamespaces 20
Namespace Nvme0n1 1
Namespace Nvme1n1 2

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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):

View File

@ -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(",")]