aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Christie2021-05-25 13:18:10 -0500
committerMartin K. Petersen2021-06-02 01:28:22 -0400
commit99b0603313eecb9b0b99fd2e60bae1e03e6b038b (patch)
tree5fcba3b60c010b8b7d5f7757b35a2c8d2505465e
parent7ce9fc5ecde0d8bd64c29baee6c5e3ce7074ec9a (diff)
scsi: iscsi: Hold task ref during TMF timeout handling
For aborts, qedi needs to cleanup the FW then send the TMF from a worker thread. While it's doing these the cmd could complete normally and the TMF could time out. libiscsi would then complete the iscsi_task which will call into the driver to cleanup the driver level resources while it still might be accessing them for the cleanup/abort. This has iscsi_eh_abort keep the iscsi_task ref if the TMF times out, so qedi does not have to worry about if the task is being freed while in use and does not need to get its own ref. Link: https://lore.kernel.org/r/20210525181821.7617-18-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>
-rw-r--r--drivers/scsi/libiscsi.c15
-rw-r--r--include/scsi/libiscsi.h1
2 files changed, 15 insertions, 1 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 8222db4f8fef..e57d6355e7c7 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -573,6 +573,11 @@ static bool cleanup_queued_task(struct iscsi_task *task)
__iscsi_put_task(task);
}
+ if (conn->session->running_aborted_task == task) {
+ conn->session->running_aborted_task = NULL;
+ __iscsi_put_task(task);
+ }
+
if (conn->task == task) {
conn->task = NULL;
__iscsi_put_task(task);
@@ -2334,6 +2339,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
iscsi_start_tx(conn);
goto success_unlocked;
case TMF_TIMEDOUT:
+ session->running_aborted_task = task;
spin_unlock_bh(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto failed_unlocked;
@@ -2367,7 +2373,14 @@ failed:
failed_unlocked:
ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc,
task ? task->itt : 0);
- iscsi_put_task(task);
+ /*
+ * The driver might be accessing the task so hold the ref. The conn
+ * stop cleanup will drop the ref after ep_disconnect so we know the
+ * driver's no longer touching the task.
+ */
+ if (!session->running_aborted_task)
+ iscsi_put_task(task);
+
iscsi_put_conn(conn->cls_conn);
mutex_unlock(&session->eh_mutex);
return FAILED;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 9d7908265afe..4ee233e5a6ff 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -276,6 +276,7 @@ struct iscsi_session {
struct iscsi_tm tmhdr;
struct timer_list tmf_timer;
int tmf_state; /* see TMF_INITIAL, etc.*/
+ struct iscsi_task *running_aborted_task;
/* iSCSI session-wide sequencing */
uint32_t cmdsn;