DORMANTno replies

[PATCH net] net: vmxnet3: unwind partial IRQ setup

From: Runyu Xiao <hidden>
Date: 2026-09-22 11:07:39
Also in: lkml, stable
Subsystem: networking drivers, the rest, vmware vmxnet3 ethernet driver · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Ronak Doshi

Track which interrupt vectors successfully acquired an IRQ handler and
release that subset when a later request fails. This prevents activation
error paths from leaving handlers registered while queue resources are
being torn down.

Reproducer:

  Build an x86_64 kernel with CONFIG_PCI=y, CONFIG_PCI_MSI=y,
  CONFIG_NET=y, CONFIG_NETDEVICES=y, and CONFIG_VMXNET3=m. For testing,
  add a test-only wrapper around vmxnet3_request_irqs() that lets the
  first request_irq() succeed and returns -EBUSY for the second request.
  Boot QEMU with a vmxnet3 device, for example:

    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' \
      -netdev user,id=n0 -device vmxnet3,netdev=n0

  In the guest, load the driver and open the interface:

    insmod vmxnet3.ko
    ip link set dev eth0 up
    cat /proc/interrupts

  The injected second request makes the open fail with -EBUSY. On the
  unfixed kernel, the first handler remains registered and
  /proc/interrupts contains an eth0-rxtx-0 entry. On the fixed kernel,
  the same failure leaves no vmxnet3 IRQ entry. The injection is
  deliberate to exercise the partial-registration path and is not a
  claim that ordinary interface activation fails this way.

Fixes: d1a890fa37f2 ("net: VMware virtual Ethernet NIC driver: vmxnet3")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Runyu Xiao <redacted>
---
 drivers/net/vmxnet3/vmxnet3_drv.c | 38 ++++++++++++++++++++++++-------
 drivers/net/vmxnet3/vmxnet3_int.h |  1 +
 2 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index f8df83f99..05373ba4d 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -53,6 +53,9 @@ static int enable_mq = 1;
 static void
 vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, const u8 *mac);
 
+static void
+vmxnet3_free_irqs(struct vmxnet3_adapter *adapter);
+
 /*
  *    Enable/Disable the given intr
  */
@@ -2585,8 +2588,11 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
 					"Failed to request irq for MSIX, %s, "
 					"error %d\n",
 					adapter->tx_queue[i].name, err);
+				vmxnet3_free_irqs(adapter);
 				return err;
 			}
+			if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE)
+				intr->irq_requested[vector] = true;
 
 			/* Handle the case where only 1 MSIx was allocated for
 			 * all tx queues */
@@ -2620,8 +2626,10 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
 					   "Failed to request irq for MSIX, "
 					   "%s, error %d\n",
 					   adapter->rx_queue[i].name, err);
+				vmxnet3_free_irqs(adapter);
 				return err;
 			}
+			intr->irq_requested[vector] = true;
 
 			adapter->rx_queue[i].comp_ring.intr_idx = vector++;
 		}
@@ -2631,6 +2639,8 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
 		err = request_irq(intr->msix_entries[vector].vector,
 				  vmxnet3_msix_event, 0,
 				  intr->event_msi_vector_name, adapter->netdev);
+		if (!err)
+			intr->irq_requested[vector] = true;
 		intr->event_intr_idx = vector;
 
 	} else if (intr->type == VMXNET3_IT_MSI) {
@@ -2646,11 +2656,14 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
 #ifdef CONFIG_PCI_MSI
 	}
 #endif
+	if (intr->type != VMXNET3_IT_MSIX && !err)
+		intr->irq_requested[0] = true;
 	intr->num_intrs = vector + 1;
 	if (err) {
 		netdev_err(adapter->netdev,
 			   "Failed to request irq (intr type:%d), error %d\n",
 			   intr->type, err);
+		vmxnet3_free_irqs(adapter);
 	} else {
 		/* Number of rx queues will not change after this */
 		for (i = 0; i < adapter->num_rx_queues; i++) {
@@ -2693,29 +2706,38 @@ vmxnet3_free_irqs(struct vmxnet3_adapter *adapter)
 
 		if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE) {
 			for (i = 0; i < adapter->num_tx_queues; i++) {
-				free_irq(intr->msix_entries[vector++].vector,
-					 &(adapter->tx_queue[i]));
+				if (intr->irq_requested[vector])
+					free_irq(intr->msix_entries[vector].vector,
+						 &adapter->tx_queue[i]);
+				intr->irq_requested[vector++] = false;
 				if (adapter->share_intr == VMXNET3_INTR_TXSHARE)
 					break;
 			}
 		}
 
 		for (i = 0; i < adapter->num_rx_queues; i++) {
-			free_irq(intr->msix_entries[vector++].vector,
-				 &(adapter->rx_queue[i]));
+			if (intr->irq_requested[vector])
+				free_irq(intr->msix_entries[vector].vector,
+					 &adapter->rx_queue[i]);
+			intr->irq_requested[vector++] = false;
 		}
 
-		free_irq(intr->msix_entries[vector].vector,
-			 adapter->netdev);
+		if (intr->irq_requested[vector])
+			free_irq(intr->msix_entries[vector].vector, adapter->netdev);
+		intr->irq_requested[vector] = false;
 		BUG_ON(vector >= intr->num_intrs);
 		break;
 	}
 #endif
 	case VMXNET3_IT_MSI:
-		free_irq(adapter->pdev->irq, adapter->netdev);
+		if (intr->irq_requested[0])
+			free_irq(adapter->pdev->irq, adapter->netdev);
+		intr->irq_requested[0] = false;
 		break;
 	case VMXNET3_IT_INTX:
-		free_irq(adapter->pdev->irq, adapter->netdev);
+		if (intr->irq_requested[0])
+			free_irq(adapter->pdev->irq, adapter->netdev);
+		intr->irq_requested[0] = false;
 		break;
 	default:
 		BUG();
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 9f24d66db..93c545eb6 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -362,6 +362,7 @@ struct vmxnet3_intr {
 	enum vmxnet3_intr_type       type;	/* MSI-X, MSI, or INTx? */
 	u8  num_intrs;			/* # of intr vectors */
 	u8  event_intr_idx;		/* idx of the intr vector for event */
+	bool irq_requested[VMXNET3_LINUX_MAX_MSIX_VECT];
 	u8  mod_levels[VMXNET3_LINUX_MAX_MSIX_VECT]; /* moderation level */
 	char	event_msi_vector_name[IFNAMSIZ+17];
 #ifdef CONFIG_PCI_MSI
-- 
2.34.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help