scsi: pm80xx: Fix TMF task completion race condition
[ Upstream commit d712d3fb484b7fa8d1d57e9ca6f134bb9d8c18b1 ]
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 b90cd6f2b9
("scsi: libsas:
fix a race condition when smp task timeout")
Link: https://lore.kernel.org/r/20210707185945.35559-1-ipylypiv@google.com
Reviewed-by: Vishakha Channapattan <vishakhavc@google.com>
Acked-by: Jack Wang <jinpu.wang@ionos.com>
Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Sasha Levin

parent
b353028aed
commit
968ee9176a
@@ -684,8 +684,7 @@ int pm8001_dev_found(struct domain_device *dev)
|
|||||||
|
|
||||||
void pm8001_task_done(struct sas_task *task)
|
void pm8001_task_done(struct sas_task *task)
|
||||||
{
|
{
|
||||||
if (!del_timer(&task->slow_task->timer))
|
del_timer(&task->slow_task->timer);
|
||||||
return;
|
|
||||||
complete(&task->slow_task->completion);
|
complete(&task->slow_task->completion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,9 +692,14 @@ static void pm8001_tmf_timedout(struct timer_list *t)
|
|||||||
{
|
{
|
||||||
struct sas_task_slow *slow = from_timer(slow, t, timer);
|
struct sas_task_slow *slow = from_timer(slow, t, timer);
|
||||||
struct sas_task *task = slow->task;
|
struct sas_task *task = slow->task;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||||
|
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
|
||||||
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
|
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
|
||||||
complete(&task->slow_task->completion);
|
complete(&task->slow_task->completion);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PM8001_TASK_TIMEOUT 20
|
#define PM8001_TASK_TIMEOUT 20
|
||||||
@@ -748,14 +752,11 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
|
|||||||
}
|
}
|
||||||
res = -TMF_RESP_FUNC_FAILED;
|
res = -TMF_RESP_FUNC_FAILED;
|
||||||
/* Even TMF timed out, return direct. */
|
/* Even TMF timed out, return direct. */
|
||||||
if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
|
if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
|
||||||
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
|
pm8001_dbg(pm8001_ha, FAIL, "TMF task[%x]timeout.\n",
|
||||||
pm8001_dbg(pm8001_ha, FAIL,
|
|
||||||
"TMF task[%x]timeout.\n",
|
|
||||||
tmf->tmf);
|
tmf->tmf);
|
||||||
goto ex_err;
|
goto ex_err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
||||||
task->task_status.stat == SAM_STAT_GOOD) {
|
task->task_status.stat == SAM_STAT_GOOD) {
|
||||||
@@ -834,13 +835,10 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
|
|||||||
wait_for_completion(&task->slow_task->completion);
|
wait_for_completion(&task->slow_task->completion);
|
||||||
res = TMF_RESP_FUNC_FAILED;
|
res = TMF_RESP_FUNC_FAILED;
|
||||||
/* Even TMF timed out, return direct. */
|
/* Even TMF timed out, return direct. */
|
||||||
if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
|
if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
|
||||||
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
|
pm8001_dbg(pm8001_ha, FAIL, "TMF task timeout.\n");
|
||||||
pm8001_dbg(pm8001_ha, FAIL,
|
|
||||||
"TMF task timeout.\n");
|
|
||||||
goto ex_err;
|
goto ex_err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
||||||
task->task_status.stat == SAM_STAT_GOOD) {
|
task->task_status.stat == SAM_STAT_GOOD) {
|
||||||
|
Reference in New Issue
Block a user