From 8287ae781458d340b9f77024e9337e503c044b94 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Wed, 13 Nov 2019 08:34:44 +0900 Subject: [PATCH] lib/scsi: Abort management tasks being queued when removing LUN SCSI management task is for SCSI tasks which is submitted after it, and all such SCSI tasks are aborted by the last patch when we remove LUN dynamically. Hence we can abort all SCSI management tasks being queued when removing LUN. Add simple unit tests too. Signed-off-by: Shuhei Matsumoto Change-Id: I9be3f910ab4bbb99cd399f71dc716a7c40f34fe5 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/474022 Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- lib/scsi/lun.c | 6 +++ test/unit/lib/scsi/lun.c/lun_ut.c | 69 +++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/lib/scsi/lun.c b/lib/scsi/lun.c index feb502882..799aac163 100644 --- a/lib/scsi/lun.c +++ b/lib/scsi/lun.c @@ -119,6 +119,12 @@ _scsi_lun_execute_mgmt_task(struct spdk_scsi_lun *lun, { TAILQ_INSERT_TAIL(&lun->mgmt_tasks, task, scsi_link); + if (lun->removed) { + task->response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN; + scsi_lun_complete_mgmt_task(lun, task); + return; + } + switch (task->function) { case SPDK_SCSI_TASK_FUNC_ABORT_TASK: task->response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED; diff --git a/test/unit/lib/scsi/lun.c/lun_ut.c b/test/unit/lib/scsi/lun.c/lun_ut.c index cd1c049e7..d67d60861 100644 --- a/test/unit/lib/scsi/lun.c/lun_ut.c +++ b/test/unit/lib/scsi/lun.c/lun_ut.c @@ -666,6 +666,73 @@ lun_check_pending_tasks_only_for_specific_initiator(void) scsi_lun_remove(lun); } +static void +abort_pending_mgmt_tasks_when_lun_is_removed(void) +{ + struct spdk_bdev bdev = {}; + struct spdk_scsi_lun *lun; + struct spdk_scsi_task task1, task2, task3; + + lun = spdk_scsi_lun_construct(&bdev, NULL, NULL); + + /* Normal case */ + ut_init_task(&task1); + ut_init_task(&task2); + ut_init_task(&task3); + task1.lun = lun; + task2.lun = lun; + task3.lun = lun; + task1.function = SPDK_SCSI_TASK_FUNC_LUN_RESET; + task2.function = SPDK_SCSI_TASK_FUNC_LUN_RESET; + task3.function = SPDK_SCSI_TASK_FUNC_LUN_RESET; + + CU_ASSERT(g_task_count == 3); + + spdk_scsi_lun_append_mgmt_task(lun, &task1); + spdk_scsi_lun_append_mgmt_task(lun, &task2); + spdk_scsi_lun_append_mgmt_task(lun, &task3); + + CU_ASSERT(!TAILQ_EMPTY(&lun->pending_mgmt_tasks)); + + spdk_scsi_lun_execute_mgmt_task(lun); + + CU_ASSERT(TAILQ_EMPTY(&lun->pending_mgmt_tasks)); + CU_ASSERT(TAILQ_EMPTY(&lun->mgmt_tasks)); + CU_ASSERT(g_task_count == 0); + CU_ASSERT(task1.response == SPDK_SCSI_TASK_MGMT_RESP_SUCCESS); + CU_ASSERT(task2.response == SPDK_SCSI_TASK_MGMT_RESP_SUCCESS); + CU_ASSERT(task3.response == SPDK_SCSI_TASK_MGMT_RESP_SUCCESS); + + /* LUN hotplug case */ + ut_init_task(&task1); + ut_init_task(&task2); + ut_init_task(&task3); + task1.function = SPDK_SCSI_TASK_FUNC_LUN_RESET; + task2.function = SPDK_SCSI_TASK_FUNC_LUN_RESET; + task3.function = SPDK_SCSI_TASK_FUNC_LUN_RESET; + + CU_ASSERT(g_task_count == 3); + + spdk_scsi_lun_append_mgmt_task(lun, &task1); + spdk_scsi_lun_append_mgmt_task(lun, &task2); + spdk_scsi_lun_append_mgmt_task(lun, &task3); + + CU_ASSERT(!TAILQ_EMPTY(&lun->pending_mgmt_tasks)); + + lun->removed = true; + + spdk_scsi_lun_execute_mgmt_task(lun); + + CU_ASSERT(TAILQ_EMPTY(&lun->pending_mgmt_tasks)); + CU_ASSERT(TAILQ_EMPTY(&lun->mgmt_tasks)); + CU_ASSERT(g_task_count == 0); + CU_ASSERT(task1.response == SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN); + CU_ASSERT(task2.response == SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN); + CU_ASSERT(task3.response == SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN); + + scsi_lun_remove(lun); +} + int main(int argc, char **argv) { @@ -710,6 +777,8 @@ main(int argc, char **argv) lun_reset_task_suspend_scsi_task) == NULL || CU_add_test(suite, "check pending tasks only for specific initiator", lun_check_pending_tasks_only_for_specific_initiator) == NULL + || CU_add_test(suite, "abort_pending_mgmt_tasks_when_lun_is_removed", + abort_pending_mgmt_tasks_when_lun_is_removed) == NULL ) { CU_cleanup_registry(); return CU_get_error();