From 37ccb50c503968d2a4b4ad929f6bee729fcaa40c Mon Sep 17 00:00:00 2001 From: Jim Harris Date: Wed, 1 Mar 2017 22:35:04 -0700 Subject: [PATCH] nvme: allow for deletion of I/O qpairs during their completion context Signed-off-by: Jim Harris Change-Id: Ibc6566e9248cd7004aa5d4374f32b519062ed6d9 --- lib/nvme/nvme_ctrlr.c | 17 +++++++++++++++++ lib/nvme/nvme_internal.h | 8 ++++++++ lib/nvme/nvme_qpair.c | 17 ++++++++++++++++- test/lib/nvme/unit/nvme_qpair_c/nvme_qpair_ut.c | 6 ++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index 4a19387b9..cdecf3eea 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -205,6 +205,17 @@ spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair) ctrlr = qpair->ctrlr; + if (qpair->in_completion_context) { + /* + * There are many cases where it is convenient to delete an io qpair in the context + * of that qpair's completion routine. To handle this properly, set a flag here + * so that the completion routine will perform an actual delete after the context + * unwinds. + */ + qpair->delete_after_completion_context = 1; + return 0; + } + nvme_robust_mutex_lock(&ctrlr->ctrlr_lock); nvme_ctrlr_proc_remove_io_qpair(qpair); @@ -947,6 +958,12 @@ nvme_ctrlr_cleanup_process(struct spdk_nvme_ctrlr_process *proc) TAILQ_FOREACH_SAFE(qpair, &proc->allocated_io_qpairs, per_process_tailq, tmp_qpair) { TAILQ_REMOVE(&proc->allocated_io_qpairs, qpair, per_process_tailq); + /* + * The process may have been killed while some qpairs were in their + * completion context. Clear that flag here to allow these IO + * qpairs to be deleted. + */ + qpair->in_completion_context = 0; spdk_nvme_ctrlr_free_io_qpair(qpair); } diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index 648812542..57d9e6c59 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -250,6 +250,14 @@ struct spdk_nvme_qpair { uint8_t qprio; + /* + * Members for handling IO qpair deletion inside of a completion context. + * These are specifically defined as single bits, so that they do not + * push this data structure out to another cacheline. + */ + uint8_t in_completion_context : 1; + uint8_t delete_after_completion_context: 1; + struct spdk_nvme_ctrlr *ctrlr; /* List entry for spdk_nvme_ctrlr::active_io_qpairs */ diff --git a/lib/nvme/nvme_qpair.c b/lib/nvme/nvme_qpair.c index 52d7a5141..5e06b784b 100644 --- a/lib/nvme/nvme_qpair.c +++ b/lib/nvme/nvme_qpair.c @@ -338,12 +338,24 @@ nvme_qpair_manual_complete_request(struct spdk_nvme_qpair *qpair, int32_t spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions) { + int32_t ret; + if (qpair->ctrlr->is_failed) { nvme_qpair_fail(qpair); return 0; } - return nvme_transport_qpair_process_completions(qpair, max_completions); + qpair->in_completion_context = 1; + ret = nvme_transport_qpair_process_completions(qpair, max_completions); + qpair->in_completion_context = 0; + if (qpair->delete_after_completion_context) { + /* + * A request to delete this qpair was made in the context of this completion + * routine - so it is safe to delete it now. + */ + spdk_nvme_ctrlr_free_io_qpair(qpair); + } + return ret; } int @@ -354,6 +366,9 @@ nvme_qpair_init(struct spdk_nvme_qpair *qpair, uint16_t id, qpair->id = id; qpair->qprio = qprio; + qpair->in_completion_context = 0; + qpair->delete_after_completion_context = 0; + qpair->ctrlr = ctrlr; qpair->trtype = ctrlr->trid.trtype; diff --git a/test/lib/nvme/unit/nvme_qpair_c/nvme_qpair_ut.c b/test/lib/nvme/unit/nvme_qpair_c/nvme_qpair_ut.c index f29c476be..3fef7cb6d 100644 --- a/test/lib/nvme/unit/nvme_qpair_c/nvme_qpair_ut.c +++ b/test/lib/nvme/unit/nvme_qpair_c/nvme_qpair_ut.c @@ -142,6 +142,12 @@ nvme_transport_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t return 0; } +int +spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair) +{ + return 0; +} + static void prepare_submit_request_test(struct spdk_nvme_qpair *qpair, struct spdk_nvme_ctrlr *ctrlr)