[libvirt] [PATCH 8/8] Check active domain hostdevs before allowing PCI reset

Mark McLoughlin markmc at redhat.com
Thu Aug 13 16:44:37 UTC 2009


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




More information about the libvir-list mailing list