]> xenbits.xensource.com Git - libvirt.git/commitdiff
Check active domain hostdevs before allowing PCI reset
authorMark McLoughlin <markmc@redhat.com>
Fri, 14 Aug 2009 07:31:11 +0000 (08:31 +0100)
committerMark McLoughlin <markmc@redhat.com>
Fri, 14 Aug 2009 07:31:11 +0000 (08:31 +0100)
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
src/pci.c
src/pci.h
src/qemu_driver.c

index 642c2bca98453a42985d2586f70584e8e1d94e8f..23fa01b2cf0ae9c1aee7287db54d3d2afb0762b0 100644 (file)
@@ -283,6 +283,7 @@ virNodeDeviceAssignDef;
 pciGetDevice;
 pciFreeDevice;
 pciDettachDevice;
+pciDeviceEquals;
 pciReAttachDevice;
 pciResetDevice;
 
index 6a2e860007e46e8891046f173ebfb34aac4b23eb..619853b2afa60537d7d665ed10b0bd0cdde6cc1e 100644 (file)
--- 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;
+}
index 15da057f167471a7659fb4ce9d48a4fe59516452..d5e680cba74c632a90ea275c315e262e60ce6519 100644 (file)
--- 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__ */
index bfa06a55d0408717433ecb94e7f3716a17918306..4b1aeea4ad9fc35bd85e6af6d6674f52331002df 100644 (file)
@@ -1329,6 +1329,48 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
     return -1;
 }
 
+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)
 {
@@ -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;
 }