lib/nvmf: Add an internal API nvmf_subsystem_set_ana_state()

Add an internal API nvmf_subsystem_set_ana_state() to change the
ANA state of the subsystem listener whose trid matches.

ANA optimized state, ANA non-optimized state, and ANA inaccessible
state are supported. ANA change state is not used and ANA persistent
loss state is not supported.

After changing the ANA state of the subsystem listener, on each poll
group, controllers, whose the subsystem listener match, send ANA
change notice.

Initiators query ANA log page anyway if they receive ANA change
notification. False positive notification should be avoided but is
acceptable.

To avoid any concurrency conflict, simply compare ctrlr->listener and
the passed listener.

It may be better to execute nvmf_subsystem_set_ana_state() on the
subsystem thread but currently the RPC thread adds and removes a
listener to and from the subsystem, respectively, and the subsystem
has been suspended while executing nvmf_subsystem_set_ana_state().
Hence we keep this as a future enhancement.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: If1910b79dd33d904114e258ae2c5e868947cdc52
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4079
Community-CI: Broadcom CI
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Anil Veerabhadrappa <anil.veerabhadrappa@broadcom.com>
This commit is contained in:
Shuhei Matsumoto 2020-09-14 01:39:59 +09:00 committed by Tomasz Zawadzki
parent 523f2a85d3
commit 071d80f37b
3 changed files with 107 additions and 0 deletions

View File

@ -96,6 +96,7 @@ struct spdk_nvmf_subsystem_listener {
struct spdk_nvme_transport_id *trid;
struct spdk_nvmf_transport *transport;
enum spdk_nvme_ana_state ana_state;
uint64_t ana_state_change_count;
TAILQ_ENTRY(spdk_nvmf_subsystem_listener) link;
};
@ -337,6 +338,10 @@ struct spdk_nvmf_subsystem_listener *nvmf_subsystem_find_listener(
struct spdk_nvmf_listener *nvmf_transport_find_listener(
struct spdk_nvmf_transport *transport,
const struct spdk_nvme_transport_id *trid);
void nvmf_subsystem_set_ana_state(struct spdk_nvmf_subsystem *subsystem,
const struct spdk_nvme_transport_id *trid,
enum spdk_nvme_ana_state ana_state,
spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn, void *cb_arg);
int nvmf_ctrlr_async_event_ns_notice(struct spdk_nvmf_ctrlr *ctrlr);
int nvmf_ctrlr_async_event_ana_change_notice(struct spdk_nvmf_ctrlr *ctrlr);

View File

@ -2664,3 +2664,103 @@ spdk_nvmf_subsystem_set_ana_reporting(struct spdk_nvmf_subsystem *subsystem,
return 0;
}
struct subsystem_listener_update_ctx {
struct spdk_nvmf_subsystem_listener *listener;
spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn;
void *cb_arg;
};
static void
subsystem_listener_update_done(struct spdk_io_channel_iter *i, int status)
{
struct subsystem_listener_update_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
if (ctx->cb_fn) {
ctx->cb_fn(ctx->cb_arg, status);
}
free(ctx);
}
static void
subsystem_listener_update_on_pg(struct spdk_io_channel_iter *i)
{
struct subsystem_listener_update_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
struct spdk_nvmf_subsystem_listener *listener;
struct spdk_nvmf_poll_group *group;
struct spdk_nvmf_ctrlr *ctrlr;
listener = ctx->listener;
group = spdk_io_channel_get_ctx(spdk_io_channel_iter_get_channel(i));
TAILQ_FOREACH(ctrlr, &listener->subsystem->ctrlrs, link) {
if (ctrlr->admin_qpair->group == group && ctrlr->listener == listener) {
nvmf_ctrlr_async_event_ana_change_notice(ctrlr);
}
}
spdk_for_each_channel_continue(i, 0);
}
void
nvmf_subsystem_set_ana_state(struct spdk_nvmf_subsystem *subsystem,
const struct spdk_nvme_transport_id *trid,
enum spdk_nvme_ana_state ana_state,
spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn, void *cb_arg)
{
struct spdk_nvmf_subsystem_listener *listener;
struct subsystem_listener_update_ctx *ctx;
assert(cb_fn != NULL);
assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED);
if (!subsystem->ana_reporting) {
SPDK_ERRLOG("ANA reporting is disabled\n");
cb_fn(cb_arg, -EINVAL);
return;
}
/* ANA Change state is not used, ANA Persistent Loss state
* is not supported yet.
*/
if (!(ana_state == SPDK_NVME_ANA_OPTIMIZED_STATE ||
ana_state == SPDK_NVME_ANA_NON_OPTIMIZED_STATE ||
ana_state == SPDK_NVME_ANA_INACCESSIBLE_STATE)) {
SPDK_ERRLOG("ANA state %d is not supported\n", ana_state);
cb_fn(cb_arg, -ENOTSUP);
return;
}
listener = nvmf_subsystem_find_listener(subsystem, trid);
if (!listener) {
SPDK_ERRLOG("Unable to find listener.\n");
cb_fn(cb_arg, -EINVAL);
return;
}
if (listener->ana_state == ana_state) {
cb_fn(cb_arg, 0);
return;
}
ctx = calloc(1, sizeof(*ctx));
if (!ctx) {
SPDK_ERRLOG("Unable to allocate context\n");
cb_fn(cb_arg, -ENOMEM);
return;
}
listener->ana_state = ana_state;
listener->ana_state_change_count++;
ctx->listener = listener;
ctx->cb_fn = cb_fn;
ctx->cb_arg = cb_arg;
spdk_for_each_channel(subsystem->tgt,
subsystem_listener_update_on_pg,
ctx,
subsystem_listener_update_done);
}

View File

@ -123,6 +123,8 @@ DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, (const struct spdk_bdev *bdev),
DEFINE_STUB(spdk_bdev_get_num_blocks, uint64_t, (const struct spdk_bdev *bdev), 1024);
DEFINE_STUB(nvmf_ctrlr_async_event_ns_notice, int, (struct spdk_nvmf_ctrlr *ctrlr), 0);
DEFINE_STUB(nvmf_ctrlr_async_event_ana_change_notice, int,
(struct spdk_nvmf_ctrlr *ctrlr), 0);
DEFINE_STUB_V(spdk_nvme_trid_populate_transport, (struct spdk_nvme_transport_id *trid,
enum spdk_nvme_transport_type trtype));
DEFINE_STUB_V(spdk_nvmf_ctrlr_data_init, (struct spdk_nvmf_transport_opts *opts,