lib/nvmf:add spdk_nvmf_transport_stop_listen_async API.

This API differs from spdk_nvmf_tranpsort_stop_listen in
that it also disconnects the qpairs associated with
that listener.

Change-Id: Iadfc6d2debc0ef8f1a8cd5db4f20168aeae8264d
Signed-off-by: Seth Howell <seth.howell@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/3279
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Seth Howell 2020-07-09 14:57:37 -07:00 committed by Tomasz Zawadzki
parent 8bff48f63c
commit 49ee92a61f
4 changed files with 104 additions and 2 deletions

View File

@ -117,7 +117,9 @@ struct spdk_nvmf_transport_poll_group_stat {
};
/**
* Function to be called once the listener is associated with a subsystem.
* Function to be called once asynchronous listen add and remove
* operations are completed. See spdk_nvmf_subsystem_add_listener()
* and spdk_nvmf_transport_stop_listen_async().
*
* \param ctx Context argument passed to this function.
* \param status 0 if it completed successfully, or negative errno if it failed.
@ -994,6 +996,26 @@ int
spdk_nvmf_transport_stop_listen(struct spdk_nvmf_transport *transport,
const struct spdk_nvme_transport_id *trid);
/**
* Stop accepting new connections at the provided address.
*
* This is a counterpart to spdk_nvmf_tgt_listen(). It differs
* from spdk_nvmf_transport_stop_listen() in that it also destroys all
* qpairs that are connected to the specified listener. Because
* this function disconnects the qpairs, it has to be asynchronous.
*
* \param transport The transport associated with the listen address.
* \param trid The address to stop listening at.
* \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_transport_stop_listen_async(struct spdk_nvmf_transport *transport,
const struct spdk_nvme_transport_id *trid,
spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn,
void *cb_arg);
/**
* \brief Get current transport poll group statistics.
*

View File

@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
SO_VER := 5
SO_MINOR := 0
SO_MINOR := 1
C_SRCS = ctrlr.c ctrlr_discovery.c ctrlr_bdev.c \
subsystem.c nvmf.c nvmf_rpc.c transport.c tcp.c

View File

@ -75,6 +75,7 @@
spdk_nvmf_tgt_add_transport;
spdk_nvmf_transport_listen;
spdk_nvmf_transport_stop_listen;
spdk_nvmf_transport_stop_listen_async;
spdk_nvmf_transport_poll_group_get_stat;
spdk_nvmf_transport_poll_group_free_stat;
spdk_nvmf_rdma_init_hooks;

View File

@ -254,6 +254,85 @@ spdk_nvmf_transport_stop_listen(struct spdk_nvmf_transport *transport,
return 0;
}
struct nvmf_stop_listen_ctx {
struct spdk_nvmf_transport *transport;
struct spdk_nvme_transport_id trid;
spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn;
void *cb_arg;
};
static void
nvmf_stop_listen_fini(struct spdk_io_channel_iter *i, int status)
{
struct nvmf_stop_listen_ctx *ctx;
struct spdk_nvmf_transport *transport;
int rc = status;
ctx = spdk_io_channel_iter_get_ctx(i);
transport = ctx->transport;
assert(transport != NULL);
rc = spdk_nvmf_transport_stop_listen(transport, &ctx->trid);
if (rc) {
SPDK_ERRLOG("Failed to stop listening on address '%s'\n", ctx->trid.traddr);
}
if (ctx->cb_fn) {
ctx->cb_fn(ctx->cb_arg, rc);
}
free(ctx);
}
static void
nvmf_stop_listen_disconnect_qpairs(struct spdk_io_channel_iter *i)
{
struct nvmf_stop_listen_ctx *ctx;
struct spdk_nvmf_poll_group *group;
struct spdk_io_channel *ch;
struct spdk_nvmf_qpair *qpair, *tmp_qpair;
struct spdk_nvme_transport_id tmp_trid;
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) {
/* skip qpairs that don't match the TRID. */
if (spdk_nvmf_qpair_get_listen_trid(qpair, &tmp_trid)) {
continue;
}
if (!spdk_nvme_transport_id_compare(&ctx->trid, &tmp_trid)) {
spdk_nvmf_qpair_disconnect(qpair, NULL, NULL);
}
}
spdk_for_each_channel_continue(i, 0);
}
int
spdk_nvmf_transport_stop_listen_async(struct spdk_nvmf_transport *transport,
const struct spdk_nvme_transport_id *trid,
spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn,
void *cb_arg)
{
struct nvmf_stop_listen_ctx *ctx;
ctx = calloc(1, sizeof(struct nvmf_stop_listen_ctx));
if (ctx == NULL) {
return -ENOMEM;
}
ctx->trid = *trid;
ctx->transport = transport;
ctx->cb_fn = cb_fn;
ctx->cb_arg = cb_arg;
spdk_for_each_channel(transport->tgt, nvmf_stop_listen_disconnect_qpairs, ctx,
nvmf_stop_listen_fini);
return 0;
}
uint32_t
nvmf_transport_accept(struct spdk_nvmf_transport *transport)
{