[PATCH] scsi: vmw_pvscsi: only free a requested IRQ

Runyu Xiao posted 1 patch 3 days, 3 hours ago
drivers/scsi/vmw_pvscsi.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
[PATCH] scsi: vmw_pvscsi: only free a requested IRQ
Posted by Runyu Xiao 3 days, 3 hours ago
pvscsi_shutdown_intr() is used by both normal teardown and probe failure
paths. It unconditionally calls free_irq(), even when probe fails before
request_irq() or pci_alloc_irq_vectors() has succeeded. That passes an
unregistered IRQ to free_irq(), which reports an already-free IRQ.

Track successful request_irq() registration and only free the IRQ on that
path. Clear the state after freeing so repeated shutdown paths remain safe.

Reproducer:

  Build an x86_64 kernel with CONFIG_PCI=y, CONFIG_SCSI=y,
  CONFIG_SCSI_LOWLEVEL=y, CONFIG_VMWARE_PVSCSI=m,
  CONFIG_FUNCTION_ERROR_INJECTION=y, CONFIG_FAULT_INJECTION=y,
  CONFIG_FAULT_INJECTION_DEBUG_FS=y, and CONFIG_FAIL_FUNCTION=y. For
  testing, add ALLOW_ERROR_INJECTION(scsi_host_alloc, NULL) to
  drivers/scsi/hosts.c, then boot QEMU with a PVSCSI device:

    qemu-system-x86_64 -machine pc -m 1G -smp 2 -nodefaults \
      -no-reboot -display none -serial file:console.log \
      -kernel arch/x86/boot/bzImage -initrd test.cpio.gz \
      -append 'console=ttyS0 rdinit=/init loglevel=7 panic=1' \
      -device pvscsi,id=scsi0

  In the guest, mount debugfs and inject one NULL return from
  scsi_host_alloc() before loading vmw_pvscsi:

    mount -t debugfs none /sys/kernel/debug
    echo 100 > /sys/kernel/debug/fail_function/probability
    echo 1 > /sys/kernel/debug/fail_function/times
    echo scsi_host_alloc > /sys/kernel/debug/fail_function/inject
    echo 0 > /sys/kernel/debug/fail_function/scsi_host_alloc/retval
    insmod vmw_pvscsi.ko

  On the unfixed kernel, the probe reaches pvscsi_shutdown_intr() before
  request_irq() and prints "Trying to free already-free IRQ 10" followed
  by a warning from __free_irq(). The fixed kernel reaches the same
  failure path without the unmatched free_irq() warning. The injection
  is deliberate and is not expected during ordinary probing.

Fixes: 2e48e3491189 ("scsi: vmw_pvscsi: switch to pci_alloc_irq_vectors")
Cc: stable@vger.kernel.org
Assisted-by: LLM Codex
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 drivers/scsi/vmw_pvscsi.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 151cac9f9..7babef882 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -69,6 +69,7 @@ struct pvscsi_adapter {
 	u8				rev;
 	bool				use_msg;
 	bool				use_req_threshold;
+	bool				irq_requested;
 
 	spinlock_t			hw_lock;
 
@@ -1212,7 +1213,10 @@ static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter)
 
 static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter)
 {
-	free_irq(pci_irq_vector(adapter->dev, 0), adapter);
+	if (adapter->irq_requested) {
+		free_irq(pci_irq_vector(adapter->dev, 0), adapter);
+		adapter->irq_requested = false;
+	}
 	pci_free_irq_vectors(adapter->dev);
 }
 
@@ -1526,6 +1530,7 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		       "vmw_pvscsi: unable to request IRQ: %d\n", error);
 		goto out_reset_adapter;
 	}
+	adapter->irq_requested = true;
 
 	error = scsi_add_host(host, &pdev->dev);
 	if (error) {
-- 
2.34.1