From 5efa3d61ff48731fcd2499f9d1e61a28f80a7c20 Mon Sep 17 00:00:00 2001 From: Ben Walker Date: Wed, 7 Oct 2020 08:48:47 -0700 Subject: [PATCH] nvmf: Add spdk_nvmf_subsystem_disconnect_host This will disconnect all connections to a subsystem from a given host identified by HOSTNQN. Change-Id: Ibc9cea1f08a58a05dbac3a0bb47df8d8a58e7c10 Signed-off-by: Ben Walker Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4556 Tested-by: SPDK CI Jenkins Reviewed-by: Aleksey Marchuk Reviewed-by: Shuhei Matsumoto Reviewed-by: Changpeng Liu --- include/spdk/nvmf.h | 19 +++++++++++ lib/nvmf/spdk_nvmf.map | 1 + lib/nvmf/subsystem.c | 73 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index d43f5bab0..9edc9680f 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -484,6 +484,25 @@ int spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, */ int spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn); +/** + * Disconnect all connections originating from the provided hostnqn + * + * To disconnect and block all new connections from a host, first call + * spdk_nvmf_subsystem_remove_host() to remove it from the list of allowed hosts, then + * call spdk_nvmf_subsystem_disconnect_host() to close any remaining connections. + * + * \param subsystem Subsystem to operate on + * \param hostnqn The NQN for the host + * \param cb_fn The function to call on completion. + * \param cb_arg The argument to pass to the cb_fn. + * + * \return int. 0 when the asynchronous process starts successfully or a negated errno on failure. + */ +int spdk_nvmf_subsystem_disconnect_host(struct spdk_nvmf_subsystem *subsystem, + const char *hostnqn, + spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn, + void *cb_arg); + /** * Set whether a subsystem should allow any host or only hosts in the allowed list. * diff --git a/lib/nvmf/spdk_nvmf.map b/lib/nvmf/spdk_nvmf.map index b1ac64108..7be8231e9 100644 --- a/lib/nvmf/spdk_nvmf.map +++ b/lib/nvmf/spdk_nvmf.map @@ -31,6 +31,7 @@ spdk_nvmf_subsystem_get_next; spdk_nvmf_subsystem_add_host; spdk_nvmf_subsystem_remove_host; + spdk_nvmf_subsystem_disconnect_host; spdk_nvmf_subsystem_set_allow_any_host; spdk_nvmf_subsystem_get_allow_any_host; spdk_nvmf_subsystem_host_allowed; diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 46494d7fe..43114b3e8 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -760,6 +760,79 @@ spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const cha return 0; } +struct nvmf_subsystem_disconnect_host_ctx { + struct spdk_nvmf_subsystem *subsystem; + char *hostnqn; + spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn; + void *cb_arg; +}; + +static void +nvmf_subsystem_disconnect_host_fini(struct spdk_io_channel_iter *i, int status) +{ + struct nvmf_subsystem_disconnect_host_ctx *ctx; + + ctx = spdk_io_channel_iter_get_ctx(i); + + if (ctx->cb_fn) { + ctx->cb_fn(ctx->cb_arg, status); + } + free(ctx->hostnqn); + free(ctx); +} + +static void +nvmf_subsystem_disconnect_qpairs_by_host(struct spdk_io_channel_iter *i) +{ + struct nvmf_subsystem_disconnect_host_ctx *ctx; + struct spdk_nvmf_poll_group *group; + struct spdk_io_channel *ch; + struct spdk_nvmf_qpair *qpair, *tmp_qpair; + struct spdk_nvmf_ctrlr *ctrlr; + + ctx = spdk_io_channel_iter_get_ctx(i); + ch = spdk_io_channel_iter_get_channel(i); + group = spdk_io_channel_get_ctx(ch); + + TAILQ_FOREACH_SAFE(qpair, &group->qpairs, link, tmp_qpair) { + ctrlr = qpair->ctrlr; + + if (ctrlr == NULL || ctrlr->subsys != ctx->subsystem) { + continue; + } + + if (strncmp(ctrlr->hostnqn, ctx->hostnqn, sizeof(ctrlr->hostnqn)) == 0) { + /* Right now this does not wait for the queue pairs to actually disconnect. */ + spdk_nvmf_qpair_disconnect(qpair, NULL, NULL); + } + } + spdk_for_each_channel_continue(i, 0); +} + +int +spdk_nvmf_subsystem_disconnect_host(struct spdk_nvmf_subsystem *subsystem, + const char *hostnqn, + spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn, + void *cb_arg) +{ + struct nvmf_subsystem_disconnect_host_ctx *ctx; + + ctx = calloc(1, sizeof(struct nvmf_subsystem_disconnect_host_ctx)); + if (ctx == NULL) { + return -ENOMEM; + } + + ctx->subsystem = subsystem; + ctx->hostnqn = strdup(hostnqn); + ctx->cb_fn = cb_fn; + ctx->cb_arg = cb_arg; + + spdk_for_each_channel(subsystem->tgt, nvmf_subsystem_disconnect_qpairs_by_host, ctx, + nvmf_subsystem_disconnect_host_fini); + + return 0; +} + int spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host) {