From 35cf3a401c95479c0e6414768161cdc014f105ca Mon Sep 17 00:00:00 2001 From: Anatoliy Glagolev Date: Tue, 26 Sep 2023 15:03:30 -0600 Subject: [PATCH] lun_reset cancelling lun tasks only The existing implementation of iscsi_task_mgmt_lun_reset_async cancels all tasks in ready-to-send and wait-for-completion queues. If the ISCSI context has in-flight tasks for a different LUNs or tasks that are not LUN-specific (such as NOPIN, NOPOUT), those tasks are not supposed to be affected by the LUN reset. Also, the tasks for the LUN being reset may have in-flight responses not affected by a concurrent LUN reset; they have to be handled accordingly. This change cancels only the tasks for the LUN being reset if they are in the ready-to-send queue ('outqueue'). The tasks in the wait-for- completion queue should be cancelled on LUN reset completion. For example: iscsi_task_mgmt_lun_reset_async(iscsi, lun, lun_reset_cb, ctxt); .... .... void lun_reset_cb(struct iscsi_context * iscsi, int status, void * command_data, void * private_data) { // 'response' field per ISCSI spec rfc7143 section 11.6.1 uint8_t iscsi_response = *(uint8_t *)command_data; if (iscsi_response == 0) { // The LUN has been reset. No further replies are expected // for in-flight tasks for that LUN. Explicitly cancelling // the tasks in wait-for-completion queue. for (.. scsi_task-s in flight ..) { iscsi_scsi_cancel_task(iscsi, task); } } ... } --- include/iscsi-private.h | 1 + lib/pdu.c | 33 +++++++++++++++++++++++++++++++++ lib/task_mgmt.c | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 82a328fe..c9cab57b 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -293,6 +293,7 @@ void iscsi_pdu_set_ritt(struct iscsi_pdu *pdu, uint32_t ritt); void iscsi_pdu_set_datasn(struct iscsi_pdu *pdu, uint32_t datasn); void iscsi_pdu_set_bufferoffset(struct iscsi_pdu *pdu, uint32_t bufferoffset); void iscsi_cancel_pdus(struct iscsi_context *iscsi); +void iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun); int iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, const unsigned char *dptr, int dsize); int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); diff --git a/lib/pdu.c b/lib/pdu.c index 702febed..ba208869 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -799,3 +799,36 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi) iscsi->drv->free_pdu(iscsi, pdu); } } + +void +iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun) +{ + struct iscsi_pdu *pdu; + struct iscsi_pdu *next_pdu; + uint32_t cmdsn_gap = 0; + struct scsi_task * task = NULL; + + for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) { + next_pdu = pdu->next; + task = iscsi_scsi_get_task_from_pdu(pdu); + + if (cmdsn_gap > 0) { + iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn - cmdsn_gap); + } + if (task == NULL || task->lun != lun) { + continue; + } + if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) && + (pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) { + iscsi->cmdsn--; + cmdsn_gap++; + } + ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu); + iscsi_set_error(iscsi, "command cancelled"); + if (pdu->callback) { + pdu->callback(iscsi, SCSI_STATUS_CANCELLED, + NULL, pdu->private_data); + } + iscsi->drv->free_pdu(iscsi, pdu); + } +} diff --git a/lib/task_mgmt.c b/lib/task_mgmt.c index b0ad2515..f3e68249 100644 --- a/lib/task_mgmt.c +++ b/lib/task_mgmt.c @@ -130,7 +130,7 @@ iscsi_task_mgmt_lun_reset_async(struct iscsi_context *iscsi, uint32_t lun, iscsi_command_cb cb, void *private_data) { - iscsi_scsi_cancel_all_tasks(iscsi); + iscsi_cancel_lun_pdus(iscsi, lun); return iscsi_task_mgmt_async(iscsi, lun, ISCSI_TM_LUN_RESET,