When doing a PCI secondary bus reset, we must be sure that there are no
active devices on the same bus segment. The active device tracking is
designed to only track host devices that are active in use by guests.
This ignores host devices that are actively in use by the host. So the
current logic will reset host devices. Hilarity ensues.
Switch this logic around and allow sbus reset when we are assigning all
devices behind a bridge to the same guest at guest startup or as a result
of a single attach-device command.
Cc: Alex Williamson <alex.williamson(a)redhat.com>
Cc: Don Dutile <ddutile(a)redhat.com>
Cc: Chris Lalancette <clalance(a)redhat.com>
Cc: Mark McLoughlin <markmc(a)redhat.com>
Signed-off-by: Chris Wright <chrisw(a)redhat.com>
---
src/qemu/qemu_driver.c | 8 ++++----
src/util/pci.c | 20 +++++++++++---------
src/util/pci.h | 3 ++-
src/xen/xen_driver.c | 2 +-
4 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 20946e6..8f64247 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2934,7 +2934,7 @@ qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
* reset them */
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
pciDevice *dev = pciDeviceListGet(pcidevs, i);
- if (pciResetDevice(dev, driver->activePciHostdevs) < 0)
+ if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0)
goto cleanup;
}
@@ -3080,7 +3080,7 @@ qemuDomainReAttachHostdevDevices(struct qemud_driver *driver,
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
pciDevice *dev = pciDeviceListGet(pcidevs, i);
- if (pciResetDevice(dev, driver->activePciHostdevs) < 0) {
+ if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0) {
virErrorPtr err = virGetLastError();
VIR_ERROR(_("Failed to reset PCI device: %s"),
err ? err->message : _("unknown error"));
@@ -8820,7 +8820,7 @@ static int qemudDomainDetachHostPciDevice(struct qemud_driver
*driver,
else {
pciDeviceSetManaged(pci, detach->managed);
pciDeviceListDel(driver->activePciHostdevs, pci);
- if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
+ if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
ret = -1;
qemudReattachManagedDevice(pci, driver);
pciFreeDevice(pci);
@@ -11445,7 +11445,7 @@ qemudNodeDeviceReset (virNodeDevicePtr dev)
qemuDriverLock(driver);
- if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
+ if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
goto out;
ret = 0;
diff --git a/src/util/pci.c b/src/util/pci.c
index 6d0ca24..94bffae 100644
--- a/src/util/pci.c
+++ b/src/util/pci.c
@@ -440,11 +440,11 @@ pciDetectPowerManagementReset(pciDevice *dev)
return 0;
}
-/* Any active devices other than the one supplied on the same domain/bus ? */
+/* Any active devices on the same domain/bus ? */
static int
pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data)
{
- pciDeviceList *activeDevs = data;
+ pciDeviceList *inactiveDevs = data;
/* Different domain, different bus, or simply identical device */
if (dev->domain != check->domain ||
@@ -453,7 +453,8 @@ pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data)
dev->function == check->function))
return 0;
- if (activeDevs && !pciDeviceListFind(activeDevs, check))
+ /* same bus, but inactive, i.e. about to be assigned to guest */
+ if (inactiveDevs && pciDeviceListFind(inactiveDevs, check))
return 0;
return 1;
@@ -461,11 +462,11 @@ pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void
*data)
static pciDevice *
pciBusContainsActiveDevices(pciDevice *dev,
- pciDeviceList *activeDevs)
+ pciDeviceList *inactiveDevs)
{
pciDevice *active = NULL;
if (pciIterDevices(pciSharesBusWithActive,
- dev, &active, activeDevs) < 0)
+ dev, &active, inactiveDevs) < 0)
return NULL;
return active;
}
@@ -512,7 +513,7 @@ pciGetParentDevice(pciDevice *dev)
*/
static int
pciTrySecondaryBusReset(pciDevice *dev,
- pciDeviceList *activeDevs)
+ pciDeviceList *inactiveDevs)
{
pciDevice *parent, *conflict;
uint8_t config_space[PCI_CONF_LEN];
@@ -524,7 +525,7 @@ pciTrySecondaryBusReset(pciDevice *dev,
* In future, we could allow it so long as those devices
* are not in use by the host or other guests.
*/
- if ((conflict = pciBusContainsActiveDevices(dev, activeDevs))) {
+ if ((conflict = pciBusContainsActiveDevices(dev, inactiveDevs))) {
pciReportError(VIR_ERR_NO_SUPPORT,
_("Active %s devices on bus with %s, not doing bus
reset"),
conflict->name, dev->name);
@@ -642,7 +643,8 @@ pciInitDevice(pciDevice *dev)
int
pciResetDevice(pciDevice *dev,
- pciDeviceList *activeDevs)
+ pciDeviceList *activeDevs,
+ pciDeviceList *inactiveDevs)
{
int ret = -1;
@@ -670,7 +672,7 @@ pciResetDevice(pciDevice *dev,
/* Bus reset is not an option with the root bus */
if (ret < 0 && dev->bus != 0)
- ret = pciTrySecondaryBusReset(dev, activeDevs);
+ ret = pciTrySecondaryBusReset(dev, inactiveDevs);
if (ret < 0) {
virErrorPtr err = virGetLastError();
diff --git a/src/util/pci.h b/src/util/pci.h
index 9aef81f..b767930 100644
--- a/src/util/pci.h
+++ b/src/util/pci.h
@@ -35,7 +35,8 @@ void pciFreeDevice (pciDevice *dev);
int pciDettachDevice (pciDevice *dev, pciDeviceList *activeDevs);
int pciReAttachDevice (pciDevice *dev, pciDeviceList *activeDevs);
int pciResetDevice (pciDevice *dev,
- pciDeviceList *activeDevs);
+ pciDeviceList *activeDevs,
+ pciDeviceList *inactiveDevs);
void pciDeviceSetManaged(pciDevice *dev,
unsigned managed);
unsigned pciDeviceGetManaged(pciDevice *dev);
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index 3dd673b..5ebeb71 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -1892,7 +1892,7 @@ xenUnifiedNodeDeviceReset (virNodeDevicePtr dev)
if (!pci)
return -1;
- if (pciResetDevice(pci, NULL) < 0)
+ if (pciResetDevice(pci, NULL, NULL) < 0)
goto out;
ret = 0;
--
1.7.1.1