summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;