diff --git a/lib/nvmf/nvmf.c b/lib/nvmf/nvmf.c index 6817ae4be5..30c3d9dca7 100644 --- a/lib/nvmf/nvmf.c +++ b/lib/nvmf/nvmf.c @@ -416,11 +416,18 @@ spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group, if (subsystem->id >= group->num_sgroups) { void *buf; - group->num_sgroups = subsystem->id + 1; - buf = realloc(group->sgroups, group->num_sgroups * sizeof(*sgroup)); + + buf = realloc(group->sgroups, (subsystem->id + 1) * sizeof(*sgroup)); if (!buf) { return -ENOMEM; } + + /* Zero out the newly allocated memory */ + memset(&group->sgroups[group->num_sgroups], + 0, + (subsystem->id + 1 - group->num_sgroups) * sizeof(struct spdk_io_channel *)); + + group->num_sgroups = subsystem->id + 1; group->sgroups = buf; } @@ -468,6 +475,50 @@ spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, return 0; } +int +spdk_nvmf_poll_group_add_ns(struct spdk_nvmf_poll_group *group, + struct spdk_nvmf_subsystem *subsystem, + struct spdk_nvmf_ns *ns) +{ + struct spdk_nvmf_subsystem_poll_group *sgroup; + uint32_t ns_idx; + + sgroup = &group->sgroups[subsystem->id]; + + /* The index into the channels array is (nsid - 1) */ + ns_idx = ns->id - 1; + + if (ns_idx >= sgroup->num_channels) { + void *buf; + + buf = realloc(sgroup->channels, + ns->id * sizeof(struct spdk_io_channel *)); + if (!buf) { + return -ENOMEM; + } + + /* Zero out the newly allocated memory */ + memset(&sgroup->channels[sgroup->num_channels], + 0, + (ns->id - sgroup->num_channels) * sizeof(struct spdk_io_channel *)); + + sgroup->num_channels = ns->id; + sgroup->channels = buf; + } + + /* The channel could have been created in response to a subsystem creation + * event already propagating through the system */ + if (sgroup->channels[ns_idx] == NULL) { + sgroup->channels[ns_idx] = spdk_bdev_get_io_channel(ns->desc); + } + + if (sgroup->channels[ns_idx] == NULL) { + return -1; + } + + return 0; +} + SPDK_TRACE_REGISTER_FN(nvmf_trace) { spdk_trace_register_object(OBJECT_NVMF_IO, 'r'); diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index ce0b991431..ce0499b2c9 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -223,6 +223,9 @@ int spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group, struct spdk_nvmf_subsystem *subsystem); int spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, struct spdk_nvmf_subsystem *subsystem); +int spdk_nvmf_poll_group_add_ns(struct spdk_nvmf_poll_group *group, + struct spdk_nvmf_subsystem *subsystem, + struct spdk_nvmf_ns *ns); void spdk_nvmf_request_exec(struct spdk_nvmf_request *req); int spdk_nvmf_request_complete(struct spdk_nvmf_request *req); diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 1f27142681..588b29aa78 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -393,11 +393,36 @@ spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener) return &listener->trid; } +struct spdk_nvmf_subsystem_add_ns_ctx { + struct spdk_nvmf_subsystem *subsystem; + struct spdk_nvmf_ns *ns; +}; + +static void +spdk_nvmf_subsystem_add_ns_done(void *io_device, void *ctx, int status) +{ + free(ctx); +} + +static int +spdk_nvmf_subsystem_ns_update_poll_group(void *io_device, + struct spdk_io_channel *ch, + void *c) +{ + struct spdk_nvmf_poll_group *group; + struct spdk_nvmf_subsystem_add_ns_ctx *ctx = c; + + group = spdk_io_channel_get_ctx(ch); + + return spdk_nvmf_poll_group_add_ns(group, ctx->subsystem, ctx->ns); +} + uint32_t spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev, uint32_t nsid) { struct spdk_nvmf_ns *ns; + struct spdk_nvmf_subsystem_add_ns_ctx *ctx; uint32_t i; int rc; @@ -473,6 +498,25 @@ spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bd subsystem->max_nsid = spdk_max(subsystem->max_nsid, nsid); subsystem->num_allocated_nsid++; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + return -ENOMEM; + } + ctx->subsystem = subsystem; + ctx->ns = ns; + + /* Send a message to each poll group to notify it that a new namespace + * is available. + * TODO: This call does not currently allow the user to wait for these + * messages to propagate. It also does not protect against two calls + * to this function overlapping + */ + spdk_for_each_channel(subsystem->tgt, + spdk_nvmf_subsystem_ns_update_poll_group, + ctx, + spdk_nvmf_subsystem_add_ns_done); + return nsid; } diff --git a/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c b/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c index 96f42d0053..a785f51041 100644 --- a/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c +++ b/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c @@ -136,6 +136,14 @@ spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, return 0; } +int +spdk_nvmf_poll_group_add_ns(struct spdk_nvmf_poll_group *group, + struct spdk_nvmf_subsystem *subsystem, + struct spdk_nvmf_ns *ns) +{ + return 0; +} + int spdk_nvmf_subsystem_bdev_attach(struct spdk_nvmf_subsystem *subsystem) { diff --git a/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c b/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c index a189b5a242..6a4e9e48b3 100644 --- a/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c +++ b/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c @@ -109,6 +109,14 @@ spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, return 0; } +int +spdk_nvmf_poll_group_add_ns(struct spdk_nvmf_poll_group *group, + struct spdk_nvmf_subsystem *subsystem, + struct spdk_nvmf_ns *ns) +{ + return 0; +} + int spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str) {