diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index d10a07b33..a05e2ee13 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -528,6 +528,13 @@ spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair) return 0; } + if (qpair->poll_group && qpair->poll_group->in_completion_context) { + /* Same as above, but in a poll group. */ + qpair->poll_group->num_qpairs_to_delete++; + qpair->delete_after_completion_context = 1; + return 0; + } + if (qpair->poll_group) { spdk_nvme_poll_group_remove(qpair->poll_group->group, qpair); } diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index 2d76a83c6..5f6bafd53 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -433,6 +433,8 @@ struct spdk_nvme_transport_poll_group { STAILQ_HEAD(, spdk_nvme_qpair) connected_qpairs; STAILQ_HEAD(, spdk_nvme_qpair) disconnected_qpairs; STAILQ_ENTRY(spdk_nvme_transport_poll_group) link; + bool in_completion_context; + uint64_t num_qpairs_to_delete; }; struct spdk_nvme_ns { diff --git a/lib/nvme/nvme_transport.c b/lib/nvme/nvme_transport.c index 884655976..b06204537 100644 --- a/lib/nvme/nvme_transport.c +++ b/lib/nvme/nvme_transport.c @@ -453,8 +453,39 @@ int64_t nvme_transport_poll_group_process_completions(struct spdk_nvme_transport_poll_group *tgroup, uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb) { - return tgroup->transport->ops.poll_group_process_completions(tgroup, completions_per_qpair, + struct spdk_nvme_qpair *qpair; + int64_t rc; + + tgroup->in_completion_context = true; + rc = tgroup->transport->ops.poll_group_process_completions(tgroup, completions_per_qpair, disconnected_qpair_cb); + tgroup->in_completion_context = false; + + if (spdk_unlikely(tgroup->num_qpairs_to_delete > 0)) { + /* deleted qpairs are more likely to be in the disconnected qpairs list. */ + STAILQ_FOREACH(qpair, &tgroup->disconnected_qpairs, poll_group_stailq) { + if (spdk_unlikely(qpair->delete_after_completion_context)) { + spdk_nvme_ctrlr_free_io_qpair(qpair); + if (--tgroup->num_qpairs_to_delete == 0) { + return rc; + } + } + } + + STAILQ_FOREACH(qpair, &tgroup->connected_qpairs, poll_group_stailq) { + if (spdk_unlikely(qpair->delete_after_completion_context)) { + spdk_nvme_ctrlr_free_io_qpair(qpair); + if (--tgroup->num_qpairs_to_delete == 0) { + return rc; + } + } + } + /* Just in case. */ + SPDK_DEBUGLOG(SPDK_LOG_NVME, "Mismatch between qpairs to delete and poll group number.\n"); + tgroup->num_qpairs_to_delete = 0; + } + + return rc; } int