summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/be2iscsi
diff options
context:
space:
mode:
authorMike Christie <michael.christie@oracle.com>2022-06-16 17:45:55 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2022-06-21 21:19:23 -0400
commite1c6a7ec14290a0e371b09300685638f9009f2ab (patch)
tree7e931b60b90e714a2b630a816b1fa720f2724024 /drivers/scsi/be2iscsi
parent533ac412fdb4cbc8ce282b1ee1991e03b2717625 (diff)
downloadlinux-e1c6a7ec14290a0e371b09300685638f9009f2ab.tar.bz2
scsi: iscsi: Remove iscsi_get_task back_lock requirement
We currently require that the back_lock is held when calling the functions that manipulate the iscsi_task refcount. The only reason for this is to handle races where we are handling SCSI-ml EH callbacks and the cmd is completing at the same time the normal completion path is running, and we can't return from the EH callback until the driver has stopped accessing the cmd. Holding the back_lock while also accessing the task->state made it simple to check that a cmd is completing and also get/put a refcount at the same time, and at the time we were not as concerned about performance. The problem is that we don't want to take the back_lock from the xmit path for normal I/O since it causes contention with the completion path if the user has chosen to try and split those paths on different CPUs (in this case abusing the CPUs and ignoring caching improves perf for some uses). Begins to remove the back_lock requirement for iscsi_get/put_task by removing the requirement for the get path. Instead of always holding the back_lock we detect if something has done the last put and is about to call iscsi_free_task(). A subsequent commit will then allow iSCSI code to do the last put on a task and only grab the back_lock if the refcount is now zero and it's going to call iscsi_free_task(). Link: https://lore.kernel.org/r/20220616224557.115234-8-michael.christie@oracle.com Reviewed-by: Lee Duncan <lduncan@suse.com> Signed-off-by: Mike Christie <michael.christie@oracle.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/be2iscsi')
-rw-r--r--drivers/scsi/be2iscsi/be_main.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 02026476c39c..50a577ac3bb4 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -231,6 +231,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
+completion_check:
/* check if we raced, task just got cleaned up under us */
spin_lock_bh(&session->back_lock);
if (!abrt_task || !abrt_task->sc) {
@@ -238,7 +239,13 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
return SUCCESS;
}
/* get a task ref till FW processes the req for the ICD used */
- __iscsi_get_task(abrt_task);
+ if (!iscsi_get_task(abrt_task)) {
+ spin_unlock(&session->back_lock);
+ /* We are just about to call iscsi_free_task so wait for it. */
+ udelay(5);
+ goto completion_check;
+ }
+
abrt_io_task = abrt_task->dd_data;
conn = abrt_task->conn;
beiscsi_conn = conn->dd_data;
@@ -323,7 +330,15 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
}
/* get a task ref till FW processes the req for the ICD used */
- __iscsi_get_task(task);
+ if (!iscsi_get_task(task)) {
+ /*
+ * The task has completed in the driver and is
+ * completing in libiscsi. Just ignore it here. When we
+ * call iscsi_eh_device_reset, it will wait for us.
+ */
+ continue;
+ }
+
io_task = task->dd_data;
/* mark WRB invalid which have been not processed by FW yet */
if (is_chip_be2_be3r(phba)) {