Skip to content

Commit d712d3f

Browse files
ipylypivmartinkpetersen
authored andcommitted
scsi: pm80xx: Fix TMF task completion race condition
The TMF timeout timer may trigger at the same time when the response from a controller is being handled. When this happens the SAS task may get freed before the response processing is finished. Fix this by calling complete() only when SAS_TASK_STATE_DONE is not set. A similar race condition was fixed in commit b90cd6f ("scsi: libsas: fix a race condition when smp task timeout") Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Vishakha Channapattan <[email protected]> Acked-by: Jack Wang <[email protected]> Signed-off-by: Igor Pylypiv <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent a47fa41 commit d712d3f

File tree

1 file changed

+15
-17
lines changed

1 file changed

+15
-17
lines changed

drivers/scsi/pm8001/pm8001_sas.c

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -684,18 +684,22 @@ int pm8001_dev_found(struct domain_device *dev)
684684

685685
void pm8001_task_done(struct sas_task *task)
686686
{
687-
if (!del_timer(&task->slow_task->timer))
688-
return;
687+
del_timer(&task->slow_task->timer);
689688
complete(&task->slow_task->completion);
690689
}
691690

692691
static void pm8001_tmf_timedout(struct timer_list *t)
693692
{
694693
struct sas_task_slow *slow = from_timer(slow, t, timer);
695694
struct sas_task *task = slow->task;
695+
unsigned long flags;
696696

697-
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
698-
complete(&task->slow_task->completion);
697+
spin_lock_irqsave(&task->task_state_lock, flags);
698+
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
699+
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
700+
complete(&task->slow_task->completion);
701+
}
702+
spin_unlock_irqrestore(&task->task_state_lock, flags);
699703
}
700704

701705
#define PM8001_TASK_TIMEOUT 20
@@ -748,13 +752,10 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
748752
}
749753
res = -TMF_RESP_FUNC_FAILED;
750754
/* Even TMF timed out, return direct. */
751-
if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
752-
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
753-
pm8001_dbg(pm8001_ha, FAIL,
754-
"TMF task[%x]timeout.\n",
755-
tmf->tmf);
756-
goto ex_err;
757-
}
755+
if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
756+
pm8001_dbg(pm8001_ha, FAIL, "TMF task[%x]timeout.\n",
757+
tmf->tmf);
758+
goto ex_err;
758759
}
759760

760761
if (task->task_status.resp == SAS_TASK_COMPLETE &&
@@ -834,12 +835,9 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
834835
wait_for_completion(&task->slow_task->completion);
835836
res = TMF_RESP_FUNC_FAILED;
836837
/* Even TMF timed out, return direct. */
837-
if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
838-
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
839-
pm8001_dbg(pm8001_ha, FAIL,
840-
"TMF task timeout.\n");
841-
goto ex_err;
842-
}
838+
if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
839+
pm8001_dbg(pm8001_ha, FAIL, "TMF task timeout.\n");
840+
goto ex_err;
843841
}
844842

845843
if (task->task_status.resp == SAS_TASK_COMPLETE &&

0 commit comments

Comments
 (0)