diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index 45a461ea9..f2bc551f9 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -1071,6 +1071,46 @@ void spdk_nvmf_tgt_add_transport(struct spdk_nvmf_tgt *tgt, spdk_nvmf_tgt_add_transport_done_fn cb_fn, void *cb_arg); +/** + * Function to be called once target pause is complete. + * + * \param cb_arg Callback argument passed to this function. + * \param status 0 if it completed successfully, or negative errno if it failed. + */ +typedef void (*spdk_nvmf_tgt_pause_polling_cb_fn)(void *cb_arg, int status); + +/** + * Pause polling on the given target. + * + * \param tgt The target to pause + * \param cb_fn A callback that will be called once the target is paused + * \param cb_arg A context argument passed to cb_fn. + * + * \return 0 if it completed successfully, or negative errno if it failed. + */ +int spdk_nvmf_tgt_pause_polling(struct spdk_nvmf_tgt *tgt, spdk_nvmf_tgt_pause_polling_cb_fn cb_fn, + void *cb_arg); + +/** + * Function to be called once target resume is complete. + * + * \param cb_arg Callback argument passed to this function. + * \param status 0 if it completed successfully, or negative errno if it failed. + */ +typedef void (*spdk_nvmf_tgt_resume_polling_cb_fn)(void *cb_arg, int status); + +/** + * Resume polling on the given target. + * + * \param tgt The target to resume + * \param cb_fn A callback that will be called once the target is resumed + * \param cb_arg A context argument passed to cb_fn. + * + * \return 0 if it completed successfully, or negative errno if it failed. + */ +int spdk_nvmf_tgt_resume_polling(struct spdk_nvmf_tgt *tgt, + spdk_nvmf_tgt_resume_polling_cb_fn cb_fn, void *cb_arg); + /** * Add listener to transport and begin accepting new connections. * diff --git a/lib/nvmf/nvmf.c b/lib/nvmf/nvmf.c index 579e52d09..0a7c3b957 100644 --- a/lib/nvmf/nvmf.c +++ b/lib/nvmf/nvmf.c @@ -133,6 +133,7 @@ nvmf_tgt_destroy_poll_group(void *io_device, void *ctx_buf) TAILQ_REMOVE(&tgt->poll_groups, group, link); pthread_mutex_unlock(&tgt->mutex); + assert(!(tgt->state == NVMF_TGT_PAUSING || tgt->state == NVMF_TGT_RESUMING)); nvmf_tgt_cleanup_poll_group(group); } @@ -321,6 +322,8 @@ spdk_nvmf_tgt_create(struct spdk_nvmf_target_opts *opts) sizeof(struct spdk_nvmf_poll_group), tgt->name); + tgt->state = NVMF_TGT_RUNNING; + TAILQ_INSERT_HEAD(&g_nvmf_tgts, tgt, link); return tgt; @@ -384,6 +387,8 @@ spdk_nvmf_tgt_destroy(struct spdk_nvmf_tgt *tgt, spdk_nvmf_tgt_destroy_done_fn cb_fn, void *cb_arg) { + assert(!(tgt->state == NVMF_TGT_PAUSING || tgt->state == NVMF_TGT_RESUMING)); + tgt->destroy_cb_fn = cb_fn; tgt->destroy_cb_arg = cb_arg; @@ -795,6 +800,130 @@ spdk_nvmf_tgt_add_transport(struct spdk_nvmf_tgt *tgt, _nvmf_tgt_add_transport_done); } +struct nvmf_tgt_pause_ctx { + struct spdk_nvmf_tgt *tgt; + spdk_nvmf_tgt_pause_polling_cb_fn cb_fn; + void *cb_arg; +}; + +static void +_nvmf_tgt_pause_polling_done(struct spdk_io_channel_iter *i, int status) +{ + struct nvmf_tgt_pause_ctx *ctx = spdk_io_channel_iter_get_ctx(i); + + ctx->tgt->state = NVMF_TGT_PAUSED; + + ctx->cb_fn(ctx->cb_arg, status); + free(ctx); +} + +static void +_nvmf_tgt_pause_polling(struct spdk_io_channel_iter *i) +{ + struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); + struct spdk_nvmf_poll_group *group = spdk_io_channel_get_ctx(ch); + + spdk_poller_unregister(&group->poller); + + spdk_for_each_channel_continue(i, 0); +} + +int +spdk_nvmf_tgt_pause_polling(struct spdk_nvmf_tgt *tgt, spdk_nvmf_tgt_pause_polling_cb_fn cb_fn, + void *cb_arg) +{ + struct nvmf_tgt_pause_ctx *ctx; + + SPDK_DTRACE_PROBE2(nvmf_tgt_pause_polling, tgt, tgt->name); + + switch (tgt->state) { + case NVMF_TGT_PAUSING: + case NVMF_TGT_RESUMING: + return -EBUSY; + case NVMF_TGT_RUNNING: + break; + default: + return -EINVAL; + } + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + return -ENOMEM; + } + + + tgt->state = NVMF_TGT_PAUSING; + + ctx->tgt = tgt; + ctx->cb_fn = cb_fn; + ctx->cb_arg = cb_arg; + + spdk_for_each_channel(tgt, + _nvmf_tgt_pause_polling, + ctx, + _nvmf_tgt_pause_polling_done); + return 0; +} + +static void +_nvmf_tgt_resume_polling_done(struct spdk_io_channel_iter *i, int status) +{ + struct nvmf_tgt_pause_ctx *ctx = spdk_io_channel_iter_get_ctx(i); + + ctx->tgt->state = NVMF_TGT_RUNNING; + + ctx->cb_fn(ctx->cb_arg, status); + free(ctx); +} + +static void +_nvmf_tgt_resume_polling(struct spdk_io_channel_iter *i) +{ + struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); + struct spdk_nvmf_poll_group *group = spdk_io_channel_get_ctx(ch); + + assert(group->poller == NULL); + group->poller = SPDK_POLLER_REGISTER(nvmf_poll_group_poll, group, 0); + + spdk_for_each_channel_continue(i, 0); +} + +int +spdk_nvmf_tgt_resume_polling(struct spdk_nvmf_tgt *tgt, spdk_nvmf_tgt_resume_polling_cb_fn cb_fn, + void *cb_arg) +{ + struct nvmf_tgt_pause_ctx *ctx; + + SPDK_DTRACE_PROBE2(nvmf_tgt_resume_polling, tgt, tgt->name); + + switch (tgt->state) { + case NVMF_TGT_PAUSING: + case NVMF_TGT_RESUMING: + return -EBUSY; + case NVMF_TGT_PAUSED: + break; + default: + return -EINVAL; + } + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + return -ENOMEM; + } + + tgt->state = NVMF_TGT_RESUMING; + + ctx->tgt = tgt; + ctx->cb_fn = cb_fn; + ctx->cb_arg = cb_arg; + + spdk_for_each_channel(tgt, + _nvmf_tgt_resume_polling, + ctx, + _nvmf_tgt_resume_polling_done); + return 0; +} + struct spdk_nvmf_subsystem * spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn) { diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index d033f56f0..092ca4324 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -24,6 +24,14 @@ #define NVMF_MIN_CNTLID 1 #define NVMF_MAX_CNTLID 0xFFEF +enum spdk_nvmf_tgt_state { + NVMF_TGT_IDLE = 0, + NVMF_TGT_RUNNING, + NVMF_TGT_PAUSING, + NVMF_TGT_PAUSED, + NVMF_TGT_RESUMING, +}; + enum spdk_nvmf_subsystem_state { SPDK_NVMF_SUBSYSTEM_INACTIVE = 0, SPDK_NVMF_SUBSYSTEM_ACTIVATING, @@ -46,6 +54,8 @@ struct spdk_nvmf_tgt { enum spdk_nvmf_tgt_discovery_filter discovery_filter; + enum spdk_nvmf_tgt_state state; + /* Array of subsystem pointers of size max_subsystems indexed by sid */ struct spdk_nvmf_subsystem **subsystems; diff --git a/lib/nvmf/spdk_nvmf.map b/lib/nvmf/spdk_nvmf.map index 7aab6ee1c..6b2c3d2c7 100644 --- a/lib/nvmf/spdk_nvmf.map +++ b/lib/nvmf/spdk_nvmf.map @@ -75,6 +75,8 @@ spdk_nvmf_get_transport_type; spdk_nvmf_get_transport_name; spdk_nvmf_tgt_add_transport; + spdk_nvmf_tgt_pause_polling; + spdk_nvmf_tgt_resume_polling; spdk_nvmf_transport_listen; spdk_nvmf_transport_stop_listen; spdk_nvmf_transport_stop_listen_async;