[libvirt] [PATCH] Fix the ACS checking in the PCI code.

Chris Lalancette clalance at redhat.com
Wed Jul 28 21:07:30 UTC 2010

The code in libvirt that does ACS checking has a pretty
serious bug that was essentially rendering the check useless.
When trying to assign a device, we have to check that all
bridges upstream of this device support ACS.  That means
that we have to find the parent of the current device,
check for ACS, then find the parent of that device, check
for ACS, etc.

However, the code to find the parent of the device had a
much too relaxed check.  It would iterate through all PCI
devices on the system, looking for a device that had a range
of busses that included the current device's bus.

That's not correct, though.  Depending on how we iterated
through the list of PCI devices, we could first find the
*topmost* bridge in the system; since it necessarily had
a range of busses including the current device's bus, we
would only ever check the topmost bridge, and not check
any of the intermediate bridges.

This patch is simple in that it looks for the PCI device
whose secondary device *exactly* equals the bus of the
device we are looking for.  That means that one, and only one
bridge will be found, and it will be the correct device.

Note that this also caused a fairly serious bug in the
secondary bus reset code, where we could erroneously
reset the topmost bus instead of the inner bus.

This patch was tested by me on a 4-port NIC with a
bridge without ACS (where assignment failed), a 4-port
NIC with a bridge with ACS (where assignment succeeded),
and a 2-port NIC with no bridges (where assignment

Signed-off-by: Chris Lalancette <clalance at redhat.com>
 src/util/pci.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/util/pci.c b/src/util/pci.c
index 26d55b8..df30e04 100644
--- a/src/util/pci.c
+++ b/src/util/pci.c
@@ -513,7 +513,7 @@ static int
 pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
     uint16_t device_class;
-    uint8_t header_type, secondary, subordinate;
+    uint8_t header_type, secondary;
     if (dev->domain != check->domain)
         return 0;
@@ -529,12 +529,11 @@ pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
         return 0;
     secondary   = pciRead8(check, PCI_SECONDARY_BUS);
-    subordinate = pciRead8(check, PCI_SUBORDINATE_BUS);
     VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name);
     /* No, it's superman! */
-    return (dev->bus >= secondary && dev->bus <= subordinate);
+    return (dev->bus == secondary);
 static pciDevice *

More information about the libvir-list mailing list