Skip to content

Commit 71fb36b

Browse files
Xingui Yangmartinkpetersen
authored andcommitted
scsi: hisi_sas: Grab sas_dev lock when traversing the members of sas_dev.list
When freeing slots in function slot_complete_v3_hw(), it is possible that sas_dev.list is being traversed elsewhere, and it may trigger a NULL pointer exception, such as follows: ==>cq thread ==>scsi_eh_6 ==>scsi_error_handler() ==>sas_eh_handle_sas_errors() ==>sas_scsi_find_task() ==>lldd_abort_task() ==>slot_complete_v3_hw() ==>hisi_sas_abort_task() ==>hisi_sas_slot_task_free() ==>dereg_device_v3_hw() ==>list_del_init() ==>list_for_each_entry_safe() [ 7165.434918] sas: Enter sas_scsi_recover_host busy: 32 failed: 32 [ 7165.434926] sas: trying to find task 0x00000000769b5ba5 [ 7165.434927] sas: sas_scsi_find_task: aborting task 0x00000000769b5ba5 [ 7165.434940] hisi_sas_v3_hw 0000:b4:02.0: slot complete: task(00000000769b5ba5) aborted [ 7165.434964] hisi_sas_v3_hw 0000:b4:02.0: slot complete: task(00000000c9f7aa07) ignored [ 7165.434965] hisi_sas_v3_hw 0000:b4:02.0: slot complete: task(00000000e2a1cf01) ignored [ 7165.434968] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 [ 7165.434972] hisi_sas_v3_hw 0000:b4:02.0: slot complete: task(0000000022d52d93) ignored [ 7165.434975] hisi_sas_v3_hw 0000:b4:02.0: slot complete: task(0000000066a7516c) ignored [ 7165.434976] Mem abort info: [ 7165.434982] ESR = 0x96000004 [ 7165.434991] Exception class = DABT (current EL), IL = 32 bits [ 7165.434992] SET = 0, FnV = 0 [ 7165.434993] EA = 0, S1PTW = 0 [ 7165.434994] Data abort info: [ 7165.434994] ISV = 0, ISS = 0x00000004 [ 7165.434995] CM = 0, WnR = 0 [ 7165.434997] user pgtable: 4k pages, 48-bit VAs, pgdp = 00000000f29543f2 [ 7165.434998] [0000000000000000] pgd=0000000000000000 [ 7165.435003] Internal error: Oops: 96000004 [#1] SMP [ 7165.439863] Process scsi_eh_6 (pid: 4109, stack limit = 0x00000000c43818d5) [ 7165.468862] pstate: 00c00009 (nzcv daif +PAN +UAO) [ 7165.473637] pc : dereg_device_v3_hw+0x68/0xa8 [hisi_sas_v3_hw] [ 7165.479443] lr : dereg_device_v3_hw+0x2c/0xa8 [hisi_sas_v3_hw] [ 7165.485247] sp : ffff00001d623bc0 [ 7165.488546] x29: ffff00001d623bc0 x28: ffffa027d03b9508 [ 7165.493835] x27: ffff80278ed50af0 x26: ffffa027dd31e0a8 [ 7165.499123] x25: ffffa027d9b27f88 x24: ffffa027d9b209f8 [ 7165.504411] x23: ffffa027c45b0d60 x22: ffff80278ec07c00 [ 7165.509700] x21: 0000000000000008 x20: ffffa027d9b209f8 [ 7165.514988] x19: ffffa027d9b27f88 x18: ffffffffffffffff [ 7165.520276] x17: 0000000000000000 x16: 0000000000000000 [ 7165.525564] x15: ffff0000091d9708 x14: ffff0000093b7dc8 [ 7165.530852] x13: ffff0000093b7a23 x12: 6e7265746e692067 [ 7165.536140] x11: 0000000000000000 x10: 0000000000000bb0 [ 7165.541429] x9 : ffff00001d6238f0 x8 : ffffa027d877af00 [ 7165.546718] x7 : ffffa027d6329600 x6 : ffff7e809f58ca00 [ 7165.552006] x5 : 0000000000001f8a x4 : 000000000000088e [ 7165.557295] x3 : ffffa027d9b27fa8 x2 : 0000000000000000 [ 7165.562583] x1 : 0000000000000000 x0 : 000000003000188e [ 7165.567872] Call trace: [ 7165.570309] dereg_device_v3_hw+0x68/0xa8 [hisi_sas_v3_hw] [ 7165.575775] hisi_sas_abort_task+0x248/0x358 [hisi_sas_main] [ 7165.581415] sas_eh_handle_sas_errors+0x258/0x8e0 [libsas] [ 7165.586876] sas_scsi_recover_host+0x134/0x458 [libsas] [ 7165.592082] scsi_error_handler+0xb4/0x488 [ 7165.596163] kthread+0x134/0x138 [ 7165.599380] ret_from_fork+0x10/0x18 [ 7165.602940] Code: d5033e9f b9000040 aa0103e2 eb03003f (f9400021) [ 7165.609004] kernel fault(0x1) notification starting on CPU 75 [ 7165.700728] ---[ end trace fc042cbbea224efc ]--- [ 7165.705326] Kernel panic - not syncing: Fatal exception To fix the issue, grab sas_dev lock when traversing the members of sas_dev.list in dereg_device_v3_hw() and hisi_sas_release_tasks() to avoid concurrency of adding and deleting member. When function hisi_sas_release_tasks() calls hisi_sas_do_release_task() to free slot, the lock cannot be grabbed again in hisi_sas_slot_task_free(), then a bool parameter need_lock is added. Signed-off-by: Xingui Yang <yangxingui@huawei.com> Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Link: https://lore.kernel.org/r/1679283265-115066-2-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 0c2fb17 commit 71fb36b

5 files changed

Lines changed: 23 additions & 13 deletions

File tree

drivers/scsi/hisi_sas/hisi_sas.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,8 @@ extern void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy,
656656
extern void hisi_sas_phy_bcast(struct hisi_sas_phy *phy);
657657
extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
658658
struct sas_task *task,
659-
struct hisi_sas_slot *slot);
659+
struct hisi_sas_slot *slot,
660+
bool need_lock);
660661
extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
661662
extern void hisi_sas_rst_work_handler(struct work_struct *work);
662663
extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);

drivers/scsi/hisi_sas/hisi_sas_main.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba,
205205
}
206206

207207
void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
208-
struct hisi_sas_slot *slot)
208+
struct hisi_sas_slot *slot, bool need_lock)
209209
{
210210
int device_id = slot->device_id;
211211
struct hisi_sas_device *sas_dev = &hisi_hba->devices[device_id];
@@ -239,9 +239,13 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
239239
}
240240
}
241241

242-
spin_lock(&sas_dev->lock);
243-
list_del_init(&slot->entry);
244-
spin_unlock(&sas_dev->lock);
242+
if (need_lock) {
243+
spin_lock(&sas_dev->lock);
244+
list_del_init(&slot->entry);
245+
spin_unlock(&sas_dev->lock);
246+
} else {
247+
list_del_init(&slot->entry);
248+
}
245249

246250
memset(slot, 0, offsetof(struct hisi_sas_slot, buf));
247251

@@ -1081,7 +1085,7 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
10811085
}
10821086

10831087
static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task *task,
1084-
struct hisi_sas_slot *slot)
1088+
struct hisi_sas_slot *slot, bool need_lock)
10851089
{
10861090
if (task) {
10871091
unsigned long flags;
@@ -1098,7 +1102,7 @@ static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task
10981102
spin_unlock_irqrestore(&task->task_state_lock, flags);
10991103
}
11001104

1101-
hisi_sas_slot_task_free(hisi_hba, task, slot);
1105+
hisi_sas_slot_task_free(hisi_hba, task, slot, need_lock);
11021106
}
11031107

11041108
static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
@@ -1107,8 +1111,11 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
11071111
struct hisi_sas_slot *slot, *slot2;
11081112
struct hisi_sas_device *sas_dev = device->lldd_dev;
11091113

1114+
spin_lock(&sas_dev->lock);
11101115
list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry)
1111-
hisi_sas_do_release_task(hisi_hba, slot->task, slot);
1116+
hisi_sas_do_release_task(hisi_hba, slot->task, slot, false);
1117+
1118+
spin_unlock(&sas_dev->lock);
11121119
}
11131120

11141121
void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
@@ -1634,7 +1641,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
16341641
*/
16351642
if (rc == TMF_RESP_FUNC_COMPLETE && rc2 != TMF_RESP_FUNC_SUCC) {
16361643
if (task->lldd_task)
1637-
hisi_sas_do_release_task(hisi_hba, task, slot);
1644+
hisi_sas_do_release_task(hisi_hba, task, slot, true);
16381645
}
16391646
} else if (task->task_proto & SAS_PROTOCOL_SATA ||
16401647
task->task_proto & SAS_PROTOCOL_STP) {
@@ -1654,7 +1661,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
16541661
*/
16551662
if ((sas_dev->dev_status == HISI_SAS_DEV_NCQ_ERR) &&
16561663
qc && qc->scsicmd) {
1657-
hisi_sas_do_release_task(hisi_hba, task, slot);
1664+
hisi_sas_do_release_task(hisi_hba, task, slot, true);
16581665
rc = TMF_RESP_FUNC_COMPLETE;
16591666
} else {
16601667
rc = hisi_sas_softreset_ata_disk(device);

drivers/scsi/hisi_sas/hisi_sas_v1_hw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1306,7 +1306,7 @@ static void slot_complete_v1_hw(struct hisi_hba *hisi_hba,
13061306
}
13071307

13081308
out:
1309-
hisi_sas_slot_task_free(hisi_hba, task, slot);
1309+
hisi_sas_slot_task_free(hisi_hba, task, slot, true);
13101310

13111311
if (task->task_done)
13121312
task->task_done(task);

drivers/scsi/hisi_sas/hisi_sas_v2_hw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2462,7 +2462,7 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba,
24622462
}
24632463
task->task_state_flags |= SAS_TASK_STATE_DONE;
24642464
spin_unlock_irqrestore(&task->task_state_lock, flags);
2465-
hisi_sas_slot_task_free(hisi_hba, task, slot);
2465+
hisi_sas_slot_task_free(hisi_hba, task, slot, true);
24662466

24672467
if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
24682468
spin_lock_irqsave(&device->done_lock, flags);

drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -888,13 +888,15 @@ static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,
888888

889889
cfg_abt_set_query_iptt = hisi_sas_read32(hisi_hba,
890890
CFG_ABT_SET_QUERY_IPTT);
891+
spin_lock(&sas_dev->lock);
891892
list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry) {
892893
cfg_abt_set_query_iptt &= ~CFG_SET_ABORTED_IPTT_MSK;
893894
cfg_abt_set_query_iptt |= (1 << CFG_SET_ABORTED_EN_OFF) |
894895
(slot->idx << CFG_SET_ABORTED_IPTT_OFF);
895896
hisi_sas_write32(hisi_hba, CFG_ABT_SET_QUERY_IPTT,
896897
cfg_abt_set_query_iptt);
897898
}
899+
spin_unlock(&sas_dev->lock);
898900
cfg_abt_set_query_iptt &= ~(1 << CFG_SET_ABORTED_EN_OFF);
899901
hisi_sas_write32(hisi_hba, CFG_ABT_SET_QUERY_IPTT,
900902
cfg_abt_set_query_iptt);
@@ -2379,7 +2381,7 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
23792381
}
23802382
task->task_state_flags |= SAS_TASK_STATE_DONE;
23812383
spin_unlock_irqrestore(&task->task_state_lock, flags);
2382-
hisi_sas_slot_task_free(hisi_hba, task, slot);
2384+
hisi_sas_slot_task_free(hisi_hba, task, slot, true);
23832385

23842386
if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
23852387
spin_lock_irqsave(&device->done_lock, flags);

0 commit comments

Comments
 (0)