diff --git a/lib/nvmf/nvmf.c b/lib/nvmf/nvmf.c index 7aedb03096..912b486fe5 100644 --- a/lib/nvmf/nvmf.c +++ b/lib/nvmf/nvmf.c @@ -56,6 +56,9 @@ SPDK_LOG_REGISTER_COMPONENT("nvmf", SPDK_LOG_NVMF) #define SPDK_NVMF_DEFAULT_MAX_SUBSYSTEMS 1024 #define SPDK_NVMF_DEFAULT_IO_UNIT_SIZE 131072 +typedef void (*nvmf_qpair_disconnect_cpl)(void *ctx, int status); + +/* supplied to a single call to nvmf_qpair_disconnect */ struct nvmf_qpair_disconnect_ctx { struct spdk_nvmf_qpair *qpair; struct spdk_nvmf_ctrlr *ctrlr; @@ -64,6 +67,17 @@ struct nvmf_qpair_disconnect_ctx { void *ctx; }; +/* + * There are several times when we need to iterate through the list of all qpairs and selectively delete them. + * In order to do this sequentially without overlap, we must provide a context to recover the next qpair from + * to enable calling nvmf_qpair_disconnect on the next desired qpair. + */ +struct nvmf_qpair_disconnect_many_ctx { + struct spdk_nvmf_subsystem *subsystem; + struct spdk_nvmf_poll_group *group; + nvmf_qpair_disconnect_cpl cb_fn; +}; + void spdk_nvmf_tgt_opts_init(struct spdk_nvmf_tgt_opts *opts) { @@ -859,27 +873,17 @@ spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group, return 0; } -int -spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, - struct spdk_nvmf_subsystem *subsystem) +static void +_nvmf_poll_group_remove_subsystem_cb(void *ctx, int status) { - struct spdk_nvmf_qpair *qpair, *tmp; struct spdk_nvmf_subsystem_poll_group *sgroup; - int rc = 0; uint32_t nsid; - TAILQ_FOREACH_SAFE(qpair, &group->qpairs, link, tmp) { - if (qpair->ctrlr->subsys == subsystem) { - rc += spdk_nvmf_qpair_disconnect(qpair, NULL, NULL); - } + if (status) { + return; } - if (rc != 0) { - return -1; - } - - sgroup = &group->sgroups[subsystem->id]; - sgroup->state = SPDK_NVMF_SUBSYSTEM_INACTIVE; + sgroup = ctx; for (nsid = 0; nsid < sgroup->num_channels; nsid++) { if (sgroup->channels[nsid]) { @@ -891,6 +895,81 @@ spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, sgroup->num_channels = 0; free(sgroup->channels); sgroup->channels = NULL; +} + +static void +_nvmf_subsystem_disconnect_next_qpair(void *ctx) +{ + struct spdk_nvmf_qpair *qpair; + struct nvmf_qpair_disconnect_many_ctx *qpair_ctx = ctx; + struct spdk_nvmf_subsystem *subsystem; + struct spdk_nvmf_poll_group *group; + struct spdk_nvmf_subsystem_poll_group *sgroup; + int rc = 0; + + group = qpair_ctx->group; + subsystem = qpair_ctx->subsystem; + + TAILQ_FOREACH(qpair, &group->qpairs, link) { + if (qpair->ctrlr->subsys == subsystem) { + break; + } + } + + if (qpair) { + rc = spdk_nvmf_qpair_disconnect(qpair, _nvmf_subsystem_disconnect_next_qpair, qpair_ctx); + } + + if (!qpair || rc != 0) { + if (qpair_ctx->cb_fn) { + sgroup = &group->sgroups[subsystem->id]; + qpair_ctx->cb_fn(sgroup, rc); + } + free(qpair_ctx); + return; + } + return; +} + +int +spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, + struct spdk_nvmf_subsystem *subsystem) +{ + struct spdk_nvmf_qpair *qpair; + struct spdk_nvmf_subsystem_poll_group *sgroup; + struct nvmf_qpair_disconnect_many_ctx *ctx; + int rc = 0; + + ctx = calloc(1, sizeof(struct nvmf_qpair_disconnect_many_ctx)); + + if (!ctx) { + return -ENOMEM; + } + + ctx->cb_fn = _nvmf_poll_group_remove_subsystem_cb; + ctx->group = group; + ctx->subsystem = subsystem; + + sgroup = &group->sgroups[subsystem->id]; + sgroup->state = SPDK_NVMF_SUBSYSTEM_INACTIVE; + + TAILQ_FOREACH(qpair, &group->qpairs, link) { + if (qpair->ctrlr->subsys == subsystem) { + break; + } + } + + if (qpair) { + rc = spdk_nvmf_qpair_disconnect(qpair, _nvmf_subsystem_disconnect_next_qpair, ctx); + } else { + free(ctx); + _nvmf_poll_group_remove_subsystem_cb(sgroup, 0); + } + + if (rc != 0) { + free(ctx); + return rc; + } return 0; }