nvmf: pause/resume polling for the target
There is a way to pause/resume spdk pollers, however there is no way to achieve that using public API for the given target which has a hook behaving similar to pollers. Exposing such functionality can be used for pausing and restoring target pollers during reset, e.g. new commands should not be fetched to assure that all internal resources can be cleared/reinitialized safety. Pausing target poller during the reset will assure that, without need for destroying transport or adding condition statements in IO path. Similar use case might be hitless upgrade. Depending on implementation there might be need that no new command can be submitted when secondary processes are being switched to upgraded versions. Pausing target pollers should be useful in this case. Signed-off-by: Kamuda Szymon <szymon.kamuda@intel.com> Change-Id: I419816552c710c43e02197ebcc20a967fb23b3bd Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15911 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
3359bf34d6
commit
cb2f0a2cf5
@ -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.
|
||||
*
|
||||
|
129
lib/nvmf/nvmf.c
129
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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user