[PATCH] scsi: mptfusion: avoid freeing an unregistered IRQ

Runyu Xiao posted 1 patch 3 days, 4 hours ago
drivers/message/fusion/mptbase.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
[PATCH] scsi: mptfusion: avoid freeing an unregistered IRQ
Posted by Runyu Xiao 3 days, 4 hours ago
mpt_do_ioc_recovery() can successfully request an IRQ during IOC bringup
and fail later. The recovery cleanup frees the IRQ but leaves pci_irq
pointing at the released IRQ. A later adapter disposal can then attempt to
free it again.

mpt_suspend() also unconditionally calls free_irq() when the bringup path
did not register an IRQ and left pci_irq at -1. Guard the suspend cleanup
and clear pci_irq after recovery cleanup so the field reflects whether the
handler is registered.

Reproducer:
Build both kernels with a test-only hook that makes the first
SendIocInit() call during resume recovery return -EIO after the IRQ has
been registered. Boot an x86_64 guest in QEMU with an mptsas1068 device:

    -device mptsas1068,id=scsi0

As root in the guest, run:

    printf mem > /sys/power/state
    printf mem > /sys/power/state
    dmesg | grep 'Trying to free already-free IRQ'

The unfixed kernel reports the warning during the second suspend, while
the fixed kernel completes both suspend/resume cycles without it. The
failure injection is test-only and does not claim that SendIocInit()
fails spontaneously during normal operation.

Fixes: 9bf0a28c9a24 ("[SCSI] kdump: mpt fusion driver initialization failure fix")
Fixes: 4d4109d0eb69 ("[SCSI] mpt fusion: Power Management fixes for MPT SAS PCI-E controllers")
Cc: stable@vger.kernel.org

Assisted-by: LLM Codex
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 drivers/message/fusion/mptbase.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 3a431ffd3e2eb..79e0cb8fa5c56 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -2160,10 +2160,12 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
 	/* Clear any lingering interrupt */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
-	free_irq(ioc->pci_irq, ioc);
-	if (ioc->msi_enable)
-		pci_disable_msi(ioc->pcidev);
-	ioc->pci_irq = -1;
+	if (ioc->pci_irq != -1) {
+		free_irq(ioc->pci_irq, ioc);
+		if (ioc->msi_enable)
+			pci_disable_msi(ioc->pcidev);
+		ioc->pci_irq = -1;
+	}
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
 	pci_release_selected_regions(pdev, ioc->bars);
@@ -2615,6 +2617,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
  out:
 	if ((ret != 0) && irq_allocated) {
 		free_irq(ioc->pci_irq, ioc);
+		ioc->pci_irq = -1;
 		if (ioc->msi_enable)
 			pci_disable_msi(ioc->pcidev);
 	}
-- 
2.34.1