If a PCI device reset causes other devices to be reset, allow it so long
as those other devices are note assigned to another active domain.
Note, we need to take the driver lock qemudNodeDeviceReset() because the
check function will iterate over the domain list.
* src/qemu_conf.c: add qemuCheckPciHostDevice() to iterate over active
domains checking whether the affected device is assigned
* src/pci.[ch]: add pciDeviceEquals() helper
---
src/libvirt_private.syms | 1 +
src/pci.c | 15 ++++++++++++
src/pci.h | 7 ++++++
src/qemu_driver.c | 54 ++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 642c2bc..23fa01b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -283,6 +283,7 @@ virNodeDeviceAssignDef;
pciGetDevice;
pciFreeDevice;
pciDettachDevice;
+pciDeviceEquals;
pciReAttachDevice;
pciResetDevice;
diff --git a/src/pci.c b/src/pci.c
index 6a2e860..619853b 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -926,3 +926,18 @@ pciFreeDevice(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
close(dev->fd);
VIR_FREE(dev);
}
+
+int
+pciDeviceEquals(virConnectPtr conn ATTRIBUTE_UNUSED,
+ pciDevice *dev,
+ unsigned domain,
+ unsigned bus,
+ unsigned slot,
+ unsigned function)
+{
+ return
+ dev->domain == domain &&
+ dev->bus == bus &&
+ dev->slot == slot &&
+ dev->function == function;
+}
diff --git a/src/pci.h b/src/pci.h
index 15da057..d5e680c 100644
--- a/src/pci.h
+++ b/src/pci.h
@@ -52,4 +52,11 @@ int pciResetDevice(virConnectPtr conn,
pciDevice *dev,
pciResetCheckFunc check);
+int pciDeviceEquals(virConnectPtr conn,
+ pciDevice *dev,
+ unsigned domain,
+ unsigned bus,
+ unsigned slot,
+ unsigned function);
+
#endif /* __VIR_PCI_H__ */
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index bfa06a5..4b1aeea 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -1330,6 +1330,48 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver
ATTRIBUTE_UNUSED) {
}
static int
+qemuCheckPciHostDevice(virConnectPtr conn,
+ virDomainObjPtr owner_vm,
+ pciDevice *dev)
+{
+ struct qemud_driver *driver = conn->privateData;
+ int ret = 1, i;
+
+ for (i = 0; i < driver->domains.count && ret; i++) {
+ virDomainObjPtr vm = driver->domains.objs[i];
+
+ if (vm == owner_vm)
+ continue;
+
+ virDomainObjLock(vm);
+
+ if (virDomainIsActive(vm)) {
+ int j;
+
+ for (j = 0; j < vm->def->nhostdevs && ret; j++) {
+ virDomainHostdevDefPtr hostdev = vm->def->hostdevs[j];
+
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+ continue;
+ if (hostdev->source.subsys.type !=
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ continue;
+
+ if (pciDeviceEquals(conn, dev,
+ hostdev->source.subsys.u.pci.domain,
+ hostdev->source.subsys.u.pci.bus,
+ hostdev->source.subsys.u.pci.slot,
+ hostdev->source.subsys.u.pci.function))
+ ret = 0;
+ }
+ }
+
+ virDomainObjUnlock(vm);
+ }
+
+ return ret;
+}
+
+static int
qemuPrepareHostDevices(virConnectPtr conn, virDomainObjPtr vm)
{
virDomainDefPtr def = vm->def;
@@ -1390,7 +1432,7 @@ qemuPrepareHostDevices(virConnectPtr conn, virDomainObjPtr vm)
if (!dev)
goto error;
- if (pciResetDevice(conn, vm, dev, NULL) < 0) {
+ if (pciResetDevice(conn, vm, dev, qemuCheckPciHostDevice) < 0) {
pciFreeDevice(conn, dev);
goto error;
}
@@ -1434,7 +1476,7 @@ qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainObjPtr
vm)
continue;
}
- if (pciResetDevice(conn, vm, dev, NULL) < 0) {
+ if (pciResetDevice(conn, vm, dev, qemuCheckPciHostDevice) < 0) {
virErrorPtr err = virGetLastError();
VIR_ERROR(_("Failed to reset PCI device: %s\n"),
err ? err->message : "");
@@ -5250,7 +5292,7 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
return -1;
if (pciDettachDevice(conn, pci) < 0 ||
- pciResetDevice(conn, vm, pci, NULL) < 0) {
+ pciResetDevice(conn, vm, pci, qemuCheckPciHostDevice) < 0) {
pciFreeDevice(conn, pci);
return -1;
}
@@ -7041,6 +7083,7 @@ out:
static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
+ struct qemud_driver *driver = dev->conn->privateData;
pciDevice *pci;
unsigned domain, bus, slot, function;
int ret = -1;
@@ -7052,11 +7095,14 @@ qemudNodeDeviceReset (virNodeDevicePtr dev)
if (!pci)
return -1;
- if (pciResetDevice(dev->conn, NULL, pci, NULL) < 0)
+ qemuDriverLock(driver);
+
+ if (pciResetDevice(dev->conn, NULL, pci, qemuCheckPciHostDevice) < 0)
goto out;
ret = 0;
out:
+ qemuDriverUnlock(driver);
pciFreeDevice(dev->conn, pci);
return ret;
}
--
1.6.2.5