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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

--
Libvir-list mailing list
Libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]