[PATCH v1] scsi: arcmsr: Flush message work after stopping IRQs
From: Yibo Tan
Date: Tue Sep 15 2026 - 12:19:42 EST
The adapter message interrupt handlers schedule
arcmsr_do_message_isr_bh. The work item is embedded in the adapter control
block, which is released with the SCSI host.
The probe error path, hot-disconnect path and normal remove path all
flush this work before arcmsr_free_irq(). An interrupt can therefore
queue it again after the flush. The normal remove path can also call the
interrupt handler while it waits for outstanding commands. The SCSI
host can then be freed while the new work is still pending.
KASAN reported a use-after-free in arcmsr_message_isr_bh_fn() in two
unload tests. Moving the flush after arcmsr_free_irq() made unload wait
for the work to finish, and both tests completed without a kernel
diagnostic.
Move the existing flush after arcmsr_free_irq() in all three paths. This
matches arcmsr_shutdown(): remove and synchronize the IRQ handlers, wait
for the work to finish, and then free the SCSI host.
Fixes: 36b83ded062a ("[SCSI] arcmsr: Support HW reset for EH and polling scheme for scsi device")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Codex:GPT-5
Signed-off-by: Yibo Tan <lhfff@xxxxxxxxxx>
---
drivers/scsi/arcmsr/arcmsr_hba.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 8aa948f06cac..1a497de2a762 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1164,10 +1164,10 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (set_date_time)
timer_delete_sync(&acb->refresh_timer);
timer_delete_sync(&acb->eternal_timer);
- flush_work(&acb->arcmsr_do_message_isr_bh);
arcmsr_stop_adapter_bgrb(acb);
arcmsr_flush_adapter_cache(acb);
arcmsr_free_irq(pdev, acb);
+ flush_work(&acb->arcmsr_do_message_isr_bh);
scsi_host_remove:
scsi_remove_host(host);
free_ccb_pool:
@@ -1685,12 +1685,12 @@ static void arcmsr_free_pcidev(struct AdapterControlBlock *acb)
host = acb->host;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
- flush_work(&acb->arcmsr_do_message_isr_bh);
timer_delete_sync(&acb->eternal_timer);
if (set_date_time)
timer_delete_sync(&acb->refresh_timer);
pdev = acb->pdev;
arcmsr_free_irq(pdev, acb);
+ flush_work(&acb->arcmsr_do_message_isr_bh);
arcmsr_free_ccb_pool(acb);
if (acb->adapter_type == ACB_ADAPTER_TYPE_F)
arcmsr_free_io_queue(acb);
@@ -1718,7 +1718,6 @@ static void arcmsr_remove(struct pci_dev *pdev)
}
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
- flush_work(&acb->arcmsr_do_message_isr_bh);
timer_delete_sync(&acb->eternal_timer);
if (set_date_time)
timer_delete_sync(&acb->refresh_timer);
@@ -1750,6 +1749,7 @@ static void arcmsr_remove(struct pci_dev *pdev)
}
}
arcmsr_free_irq(pdev, acb);
+ flush_work(&acb->arcmsr_do_message_isr_bh);
arcmsr_free_ccb_pool(acb);
if (acb->adapter_type == ACB_ADAPTER_TYPE_F)
arcmsr_free_io_queue(acb);
--
2.39.5