From d0e3f624f0541bc190175356f72a9305b235edc5 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Thu, 29 Nov 2018 10:23:07 +0900 Subject: [PATCH] scsi: LUN reset waits for completion of all prior tasks IO submissions to backends have to complete first in LUN reset. Previous patch makes the waiting time limited. LUN reset don't use timeout for now because even if LUN reset reports timeout, error handling of the initiator will be escalated and the initiator will issue stronger command and will wait eventually until all outstanding tasks completed. Besides, not using timeout in LUN reset will make implementation simple. If timeout becomes necessary, I'll do it in the separate patch later. Change-Id: Ie9e4502068c19b1727ea65dc773ddf08cedec7c4 Signed-off-by: Shuhei Matsumoto Reviewed-on: https://review.gerrithub.io/434766 Tested-by: SPDK CI Jenkins Chandler-Test-Pool: SPDK Automated Test System Reviewed-by: Ben Walker Reviewed-by: Jim Harris --- lib/scsi/lun.c | 36 +++++++++++++++++++++++-------- lib/scsi/scsi_internal.h | 2 ++ test/unit/lib/scsi/lun.c/lun_ut.c | 10 +++++++++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/lib/scsi/lun.c b/lib/scsi/lun.c index fbd36b202..9342228f1 100644 --- a/lib/scsi/lun.c +++ b/lib/scsi/lun.c @@ -61,19 +61,37 @@ spdk_scsi_lun_complete_mgmt_task(struct spdk_scsi_lun *lun, struct spdk_scsi_tas spdk_scsi_lun_execute_mgmt_task(lun); } -/* This will be called in the callback to the bdev reset function. */ +static bool +spdk_scsi_lun_has_outstanding_tasks(struct spdk_scsi_lun *lun) +{ + return !TAILQ_EMPTY(&lun->tasks); +} + +/* Reset task have to wait until all prior outstanding tasks complete. */ +static int +spdk_scsi_lun_reset_check_outstanding_tasks(void *arg) +{ + struct spdk_scsi_task *task = (struct spdk_scsi_task *)arg; + struct spdk_scsi_lun *lun = task->lun; + + if (spdk_scsi_lun_has_outstanding_tasks(lun)) { + return 0; + } + spdk_poller_unregister(&lun->reset_poller); + + spdk_scsi_lun_complete_mgmt_task(lun, task); + return 1; +} + void spdk_scsi_lun_complete_reset_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task) { if (task->status == SPDK_SCSI_STATUS_GOOD) { - /* - * The backend LUN device was just reset. If there are active tasks - * in the backend, it means that LUN reset fails, and we set failure - * status to LUN reset task. - */ - if (spdk_scsi_lun_has_pending_tasks(lun)) { - SPDK_ERRLOG("lun->tasks should be empty after reset\n"); - task->response = SPDK_SCSI_TASK_MGMT_RESP_TARGET_FAILURE; + if (spdk_scsi_lun_has_outstanding_tasks(lun)) { + lun->reset_poller = + spdk_poller_register(spdk_scsi_lun_reset_check_outstanding_tasks, + task, 10); + return; } } diff --git a/lib/scsi/scsi_internal.h b/lib/scsi/scsi_internal.h index 4beb705b7..5a7839eaf 100644 --- a/lib/scsi/scsi_internal.h +++ b/lib/scsi/scsi_internal.h @@ -127,6 +127,8 @@ struct spdk_scsi_lun { /** pending management tasks */ TAILQ_HEAD(pending_mgmt_tasks, spdk_scsi_task) pending_mgmt_tasks; + /** poller to check completion of tasks prior to reset */ + struct spdk_poller *reset_poller; }; struct spdk_lun_db_entry { diff --git a/test/unit/lib/scsi/lun.c/lun_ut.c b/test/unit/lib/scsi/lun.c/lun_ut.c index b0e5bb907..e9fda85ae 100644 --- a/test/unit/lib/scsi/lun.c/lun_ut.c +++ b/test/unit/lib/scsi/lun.c/lun_ut.c @@ -77,6 +77,16 @@ void _spdk_trace_record(uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id, { } +uint64_t spdk_get_ticks(void) +{ + return 0; +} + +uint64_t spdk_get_ticks_hz(void) +{ + return 0; +} + static void spdk_lun_ut_cpl_task(struct spdk_scsi_task *task) {