Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 2780

kernel-2.6.18-194.11.1.el5.src.rpm

From: James Paradis <jparadis@redhat.com>
Date: Tue, 10 Feb 2009 16:56:51 -0500
Subject: [pci] fix MSI descriptor leak during hot-unplug
Message-id: 764530118.5715091234303011132.JavaMail.root@zmail01.collab.prod.int.phx2.redhat.com
O-Subject: [RHEL5.4 PATCH] Fix PCI MSI descriptor leak
Bugzilla: 484943
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>

https://bugzilla.redhat.com/show_bug.cgi?id=484943

This patch fixes a bug where the kernel can leak PCI MSI descriptors during a surprise hot-unplug.  This happens because pci_disable_msi and pci_disable_msix read device config space before cleaning up, and bail out if it appears as though MSI capability not present.  During a surprise unplug PCI config space for the device no longer exists, and we're parsing garbage.

This fix is a back port of an upstream patch between 2.6.20 and 2.6.21 (866a8c87c4e51046602387953bbef76992107bcb for those playing along at home...)

--jim

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 96bec55..0a497e5 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -984,16 +984,15 @@ void pci_disable_msi(struct pci_dev* dev)
 		return;
 	if (!dev)
 		return;
-
-	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-	if (!pos)
+	if (!dev->msi_enabled)
 		return;
 
-	pci_read_config_word(dev, msi_control_reg(pos), &control);
-	if (!(control & PCI_MSI_FLAGS_ENABLE))
-		return;
-
-	disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	if (pos) {
+		pci_read_config_word(dev, msi_control_reg(pos), &control);
+		if (control & PCI_MSI_FLAGS_ENABLE)
+			disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+	}
 
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[dev->irq];
@@ -1160,16 +1159,15 @@ void pci_disable_msix(struct pci_dev* dev)
 		return;
 	if (!dev)
 		return;
-
-	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-	if (!pos)
+	if (!dev->msix_enabled)
 		return;
 
-	pci_read_config_word(dev, msi_control_reg(pos), &control);
-	if (!(control & PCI_MSIX_FLAGS_ENABLE))
-		return;
-
-	disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+	if (pos) {
+		pci_read_config_word(dev, msi_control_reg(pos), &control);
+		if (control & PCI_MSIX_FLAGS_ENABLE)
+			disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+	}
 
 	temp = dev->irq;
 	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {