⬢ DragonFlyBSD Kernel Audit
DF-4818 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/disk/nvme/nvme_attach.c
+++ b/sys/dev/disk/nvme/nvme_attach.c
@@ -101,6 +101,7 @@
 	int error;
 	int msi_enable;
 	int msix_enable;
+	int msix_setup_ok;
 
 #if 0
 	if (pci_read_config(dev, PCIR_COMMAND, 2) & 0x0400) {
@@ -156,6 +157,7 @@
 			sc->nirqs = ncpus + 1;
 
 		error = pci_setup_msix(dev);
+		msix_setup_ok = (error == 0);
 		cpu = (last_global_cpu + 0) % ncpus;	/* GCC warn */
 		for (i = 0; error == 0 && i < sc->nirqs; ++i) {
 			cpu = (last_global_cpu + i) % ncpus;
@@ -166,6 +168,10 @@
 			sc->irq[i] = bus_alloc_resource_any(dev, SYS_RES_IRQ,
 							    &sc->rid_irq[i],
 							    RF_ACTIVE);
+			if (sc->irq[i] == NULL) {
+				error = ENODEV;
+				break;
+			}
 			/*
 			 * We want this to overwrite queue 0's cpu vector
 			 * when the cpu's rotate through later on.
@@ -197,6 +203,13 @@
 				pci_release_msix_vector(dev, sc->rid_irq[i]);
 				sc->irq[i] = NULL;
 			}
+			/*
+			 * Tear the MSI-X setup down so the fallback (and a
+			 * possible later re-attach) does not trip over a
+			 * half-configured MSI-X state.
+			 */
+			if (msix_setup_ok)
+				pci_teardown_msix(dev);
 			/* leave error intact to fall through to normal */
 		} else {
 			last_global_cpu = (last_global_cpu + sc->nirqs) % ncpus;