Skip to content

Commit 584f53f

Browse files
Xiang Chenmartinkpetersen
authored andcommitted
scsi: hisi_sas: Fix the race between IO completion and timeout for SMP/internal IO
If SMP/internal IO times out, we will possibly free the task immediately. However if the IO actually completes at the same time, the IO completion may refer to task which has been freed. So to solve the issue, flush the tasklet to finish IO completion before free'ing slot/task. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: John Garry <john.garry@huawei.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 1668e3b commit 584f53f

File tree

1 file changed

+46
-9
lines changed

1 file changed

+46
-9
lines changed

drivers/scsi/hisi_sas/hisi_sas_main.c

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -956,8 +956,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
956956

957957
static void hisi_sas_task_done(struct sas_task *task)
958958
{
959-
if (!del_timer(&task->slow_task->timer))
960-
return;
959+
del_timer(&task->slow_task->timer);
961960
complete(&task->slow_task->completion);
962961
}
963962

@@ -966,13 +965,17 @@ static void hisi_sas_tmf_timedout(struct timer_list *t)
966965
struct sas_task_slow *slow = from_timer(slow, t, timer);
967966
struct sas_task *task = slow->task;
968967
unsigned long flags;
968+
bool is_completed = true;
969969

970970
spin_lock_irqsave(&task->task_state_lock, flags);
971-
if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
971+
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
972972
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
973+
is_completed = false;
974+
}
973975
spin_unlock_irqrestore(&task->task_state_lock, flags);
974976

975-
complete(&task->slow_task->completion);
977+
if (!is_completed)
978+
complete(&task->slow_task->completion);
976979
}
977980

978981
#define TASK_TIMEOUT 20
@@ -1023,10 +1026,18 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
10231026
if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
10241027
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
10251028
struct hisi_sas_slot *slot = task->lldd_task;
1029+
struct hisi_sas_cq *cq =
1030+
&hisi_hba->cq[slot->dlvry_queue];
10261031

10271032
dev_err(dev, "abort tmf: TMF task timeout and not done\n");
1028-
if (slot)
1033+
if (slot) {
1034+
/*
1035+
* flush tasklet to avoid free'ing task
1036+
* before using task in IO completion
1037+
*/
1038+
tasklet_kill(&cq->tasklet);
10291039
slot->task = NULL;
1040+
}
10301041

10311042
goto ex_err;
10321043
} else
@@ -1402,6 +1413,17 @@ static int hisi_sas_abort_task(struct sas_task *task)
14021413

14031414
spin_lock_irqsave(&task->task_state_lock, flags);
14041415
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
1416+
struct hisi_sas_slot *slot = task->lldd_task;
1417+
struct hisi_sas_cq *cq;
1418+
1419+
if (slot) {
1420+
/*
1421+
* flush tasklet to avoid free'ing task
1422+
* before using task in IO completion
1423+
*/
1424+
cq = &hisi_hba->cq[slot->dlvry_queue];
1425+
tasklet_kill(&cq->tasklet);
1426+
}
14051427
spin_unlock_irqrestore(&task->task_state_lock, flags);
14061428
rc = TMF_RESP_FUNC_COMPLETE;
14071429
goto out;
@@ -1457,12 +1479,19 @@ static int hisi_sas_abort_task(struct sas_task *task)
14571479
/* SMP */
14581480
struct hisi_sas_slot *slot = task->lldd_task;
14591481
u32 tag = slot->idx;
1482+
struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue];
14601483

14611484
rc = hisi_sas_internal_task_abort(hisi_hba, device,
14621485
HISI_SAS_INT_ABT_CMD, tag);
14631486
if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
1464-
task->lldd_task)
1465-
hisi_sas_do_release_task(hisi_hba, task, slot);
1487+
task->lldd_task) {
1488+
/*
1489+
* flush tasklet to avoid free'ing task
1490+
* before using task in IO completion
1491+
*/
1492+
tasklet_kill(&cq->tasklet);
1493+
slot->task = NULL;
1494+
}
14661495
}
14671496

14681497
out:
@@ -1828,9 +1857,17 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
18281857
if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
18291858
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
18301859
struct hisi_sas_slot *slot = task->lldd_task;
1831-
1832-
if (slot)
1860+
struct hisi_sas_cq *cq =
1861+
&hisi_hba->cq[slot->dlvry_queue];
1862+
1863+
if (slot) {
1864+
/*
1865+
* flush tasklet to avoid free'ing task
1866+
* before using task in IO completion
1867+
*/
1868+
tasklet_kill(&cq->tasklet);
18331869
slot->task = NULL;
1870+
}
18341871
dev_err(dev, "internal task abort: timeout and not done.\n");
18351872
res = -EIO;
18361873
goto exit;

0 commit comments

Comments
 (0)