From 7ea544b46a99ec6ed7a7520a63d7f8f658ef8293 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Mon, 25 Sep 2017 15:27:01 -0700 Subject: [PATCH] nvmf: move poll groups to public API The end goal is to have the application create one poll group per core. Then each poll group will have a single CQ per network device and an I/O channel per back-end storage device to poll. This is just the first step toward that, which is to wire up the creation of the per-core poll groups in the application. Note that the app poll groups don't do anything yet. We'll need additional library API changes to make the library use the existing poll groups, rather than creating a new poll group per subsystem as we do right now. Change-Id: I2d4e2a5e5aa354d37714750f1d5b1d1e4ab9edce Signed-off-by: Daniel Verkamp Reviewed-on: https://review.gerrithub.io/381887 Reviewed-by: Ben Walker Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris --- app/nvmf_tgt/nvmf_tgt.c | 81 +++++++++++++++++++++++++++++++++++++++- include/spdk/nvmf.h | 16 ++++++++ lib/nvmf/nvmf_internal.h | 4 -- 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/app/nvmf_tgt/nvmf_tgt.c b/app/nvmf_tgt/nvmf_tgt.c index 1551759df..c8bac339a 100644 --- a/app/nvmf_tgt/nvmf_tgt.c +++ b/app/nvmf_tgt/nvmf_tgt.c @@ -39,9 +39,19 @@ #include "spdk/event.h" #include "spdk/log.h" #include "spdk/nvme.h" +#include "spdk/util.h" + +struct nvmf_tgt_poll_group { + struct spdk_nvmf_poll_group *group; + struct spdk_poller *poller; +}; struct spdk_nvmf_tgt *g_tgt = NULL; +static struct nvmf_tgt_poll_group *g_poll_groups = NULL; +static size_t g_num_poll_groups = 0; +static size_t g_active_poll_groups = 0; + static struct spdk_poller *g_acceptor_poller = NULL; static TAILQ_HEAD(, nvmf_tgt_subsystem) g_subsystems = TAILQ_HEAD_INITIALIZER(g_subsystems); @@ -96,10 +106,41 @@ shutdown_subsystems(void) } } +static void +nvmf_tgt_poll_group_stopped_event(void *arg1, void *arg2) +{ + uint32_t core; + + g_active_poll_groups--; + + if (g_active_poll_groups == 0) { + /* All of the poll group pollers are stopped, so we can now delete the poll groups safely. */ + SPDK_ENV_FOREACH_CORE(core) { + struct nvmf_tgt_poll_group *app_poll_group = &g_poll_groups[core]; + + spdk_nvmf_poll_group_destroy(app_poll_group->group); + } + + shutdown_subsystems(); + } +} + static void acceptor_poller_unregistered_event(void *arg1, void *arg2) { - shutdown_subsystems(); + struct nvmf_tgt_poll_group *app_poll_group; + struct spdk_event *event; + uint32_t core; + + /* Stop poll group pollers on all cores */ + SPDK_ENV_FOREACH_CORE(core) { + app_poll_group = &g_poll_groups[core]; + event = spdk_event_allocate(spdk_env_get_current_core(), + nvmf_tgt_poll_group_stopped_event, + NULL, NULL); + + spdk_poller_unregister(&app_poll_group->poller, event); + } } static void @@ -231,9 +272,18 @@ acceptor_poll(void *arg) spdk_nvmf_tgt_accept(tgt); } +static void +nvmf_tgt_poll_group_poll(void *arg) +{ + struct nvmf_tgt_poll_group *app_poll_group = arg; + + spdk_nvmf_poll_group_poll(app_poll_group->group); +} + static void spdk_nvmf_startup(void *arg1, void *arg2) { + uint32_t core; int rc; rc = spdk_nvmf_parse_conf(); @@ -247,6 +297,35 @@ spdk_nvmf_startup(void *arg1, void *arg2) goto initialize_error; } + /* Find the maximum core number */ + SPDK_ENV_FOREACH_CORE(core) { + g_num_poll_groups = spdk_max(g_num_poll_groups, core + 1); + } + + assert(g_num_poll_groups > 0); + + g_poll_groups = calloc(g_num_poll_groups, sizeof(*g_poll_groups)); + if (g_poll_groups == NULL) { + goto initialize_error; + } + + /* Create a poll group on each core in the app core mask. */ + g_active_poll_groups = 0; + SPDK_ENV_FOREACH_CORE(core) { + struct nvmf_tgt_poll_group *app_poll_group = &g_poll_groups[core]; + + app_poll_group->group = spdk_nvmf_poll_group_create(g_tgt); + if (app_poll_group->group == NULL) { + SPDK_ERRLOG("Failed to create poll group for core %u\n", core); + goto initialize_error; + } + + spdk_poller_register(&app_poll_group->poller, + nvmf_tgt_poll_group_poll, app_poll_group, + core, 0); + g_active_poll_groups++; + } + spdk_poller_register(&g_acceptor_poller, acceptor_poll, g_tgt, g_spdk_nvmf_tgt_conf.acceptor_lcore, g_spdk_nvmf_tgt_conf.acceptor_poll_rate); diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index 17b9efc60..95e8b25d0 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -99,6 +99,22 @@ struct spdk_bdev; struct spdk_nvmf_request; struct spdk_nvmf_host; struct spdk_nvmf_listener; +struct spdk_nvmf_poll_group; + +/** + * Create a poll group. + */ +struct spdk_nvmf_poll_group *spdk_nvmf_poll_group_create(struct spdk_nvmf_tgt *tgt); + +/** + * Destroy a poll group. + */ +void spdk_nvmf_poll_group_destroy(struct spdk_nvmf_poll_group *group); + +/** + * Check a poll group for work completions. + */ +int spdk_nvmf_poll_group_poll(struct spdk_nvmf_poll_group *group); /* * The NVMf subsystem, as indicated in the specification, is a collection diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index 524e96d63..219a7ea57 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -197,14 +197,10 @@ struct spdk_nvmf_subsystem { struct spdk_nvmf_transport *spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, enum spdk_nvme_transport_type); -struct spdk_nvmf_poll_group *spdk_nvmf_poll_group_create( - struct spdk_nvmf_tgt *tgt); -void spdk_nvmf_poll_group_destroy(struct spdk_nvmf_poll_group *group); int spdk_nvmf_poll_group_add(struct spdk_nvmf_poll_group *group, struct spdk_nvmf_qpair *qpair); int spdk_nvmf_poll_group_remove(struct spdk_nvmf_poll_group *group, struct spdk_nvmf_qpair *qpair); -int spdk_nvmf_poll_group_poll(struct spdk_nvmf_poll_group *group); void spdk_nvmf_request_exec(struct spdk_nvmf_request *req); int spdk_nvmf_request_complete(struct spdk_nvmf_request *req);