[PATCH v2 21/21] qemu_hotplug.c: use enhanced multifunction unplug if available

Daniel Henrique Barboza danielhb413 at gmail.com
Thu Jan 30 16:44:33 UTC 2020


QEMU 4.2.0 introduced an enhanced version of the PCI multifunction
hotunplug for the PSeries guest [1] where a single device_del
of the function 0 will detach all the functions of the slot.
The idea is to make this option similar to the behavior we
already have on x86.

This means that the unplug code in qemuDomainDetachMultifunctionDevice()
can be simplified if the domain is running with QEMU 4.2.0 or
newer.

[1] https://github.com/qemu/qemu/commit/02a1536eee333123c7735cd36484da53b860fbb7

Signed-off-by: Daniel Henrique Barboza <danielhb413 at gmail.com>
---
 src/qemu/qemu_hotplug.c | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 00bd5499fe..567b9aba03 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -6033,6 +6033,7 @@ qemuDomainDetachMultifunctionDevice(virDomainObjPtr vm,
     int slotaggridx = 0;
     virDomainHostdevSubsysPCIPtr pcisrc = NULL;
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    int pSeriesEnhancedUnplugVersion;
 
     qsort(devlist->devs, devlist->count, sizeof(*devlist->devs),
           qemuiHostdevPCIMultifunctionDevicesListSort);
@@ -6108,15 +6109,16 @@ qemuDomainDetachMultifunctionDevice(virDomainObjPtr vm,
 
     qemuDomainObjEnterMonitor(driver, vm);
 
-    /* must plug non-zero first, zero at last */
-    for (i = devlist->count; i > 0;  i--) {
-        hostdev = devlist->devs[i -1]->data.hostdev;
-        subsys = &hostdev->source.subsys;
-        pcisrc = &subsys->u.pci;
-        virDomainHostdevFind(vm->def, hostdev, &detach);
+    /* QEMU 4.2.0 introduced a new Pseries hotunplug mechanic, where
+     * the whole slot can be unplugged by hotunplugging function zero
+     * (see QEMU commit 02a1536eee for details). This makes it similar
+     * to what x86 does, as long as we hotunplug function zero first
+     * in all cases. */
+    pSeriesEnhancedUnplugVersion = 4 * 1000000 + 2 * 1000;
 
-        if (detach->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_UNASSIGNED)
-            continue;
+    if (virQEMUCapsGetVersion(priv->qemuCaps) >= pSeriesEnhancedUnplugVersion) {
+        hostdev = devlist->devs[0]->data.hostdev;
+        virDomainHostdevFind(vm->def, hostdev, &detach);
 
         if (qemuMonitorDelDevice(priv->mon, detach->info->alias) < 0) {
             ignore_value(qemuDomainObjExitMonitor(driver, vm));
@@ -6124,8 +6126,25 @@ qemuDomainDetachMultifunctionDevice(virDomainObjPtr vm,
                 virDomainAuditHostdev(vm, detach, "detach", false);
             goto reset;
         }
-        if (ARCH_IS_X86(vm->def->os.arch))
-            break; /* deleting any one is enough! */
+    } else {
+        /* We're running in an older QEMU, so we must plug non-zero first,
+         * zero at last. */
+        for (i = devlist->count; i > 0;  i--) {
+            hostdev = devlist->devs[i -1]->data.hostdev;
+            virDomainHostdevFind(vm->def, hostdev, &detach);
+
+            if (detach->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_UNASSIGNED)
+                continue;
+
+            if (qemuMonitorDelDevice(priv->mon, detach->info->alias) < 0) {
+                ignore_value(qemuDomainObjExitMonitor(driver, vm));
+                if (virDomainObjIsActive(vm))
+                    virDomainAuditHostdev(vm, detach, "detach", false);
+                goto reset;
+            }
+            if (ARCH_IS_X86(vm->def->os.arch))
+                break; /* deleting any one is enough! */
+        }
     }
 
     if (qemuDomainObjExitMonitor(driver, vm) < 0)
-- 
2.24.1





More information about the libvir-list mailing list