Re: [PATCH] scsi: pm80xx: Fix tmf task completion race condition
From: Jinpu Wang <jinpu.wang@ionos.com>
Date: 2021-07-27 05:20:01
On Wed, Jul 7, 2021 at 8:59 PM Igor Pylypiv [off-list ref] wrote:
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.
Similar race condition was fixed in commit b90cd6f2b905
("scsi: libsas: fix a race condition when smp task timeout")
Reviewed-by: Vishakha Channapattan <redacted>
Signed-off-by: Igor Pylypiv <redacted>Looks good to me, thx, sorry for late reply, somehow I missed it. Acked-by: Jack Wang <jinpu.wang@ionos.com>
quoted hunk ↗ jump to hunk
--- drivers/scsi/pm8001/pm8001_sas.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-)diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 6f33d821e545..1d35587c28e0 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c@@ -682,8 +682,7 @@ int pm8001_dev_found(struct domain_device *dev) void pm8001_task_done(struct sas_task *task) { - if (!del_timer(&task->slow_task->timer)) - return; + del_timer(&task->slow_task->timer); complete(&task->slow_task->completion); }@@ -691,9 +690,14 @@ static void pm8001_tmf_timedout(struct timer_list *t) { struct sas_task_slow *slow = from_timer(slow, t, timer); struct sas_task *task = slow->task; + unsigned long flags; - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - complete(&task->slow_task->completion); + 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; + complete(&task->slow_task->completion); + } + spin_unlock_irqrestore(&task->task_state_lock, flags); } #define PM8001_TASK_TIMEOUT 20@@ -746,13 +750,10 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev, } res = -TMF_RESP_FUNC_FAILED; /* Even TMF timed out, return direct. */ - 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", - tmf->tmf); - goto ex_err; - } + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + pm8001_dbg(pm8001_ha, FAIL, "TMF task[%x]timeout.\n", + tmf->tmf); + goto ex_err; } if (task->task_status.resp == SAS_TASK_COMPLETE &&@@ -832,12 +833,9 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, wait_for_completion(&task->slow_task->completion); res = TMF_RESP_FUNC_FAILED; /* Even TMF timed out, return direct. */ - 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"); - goto ex_err; - } + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + pm8001_dbg(pm8001_ha, FAIL, "TMF task timeout.\n"); + goto ex_err; } if (task->task_status.resp == SAS_TASK_COMPLETE && --2.32.0.93.g670b81a890-goog