c313de
From 84d44b33a64b6fd7f77d021249d23dc054243ddf Mon Sep 17 00:00:00 2001
c313de
Message-Id: <84d44b33a64b6fd7f77d021249d23dc054243ddf@dist-git>
c313de
From: Yi Min Zhao <zyimin@linux.ibm.com>
c313de
Date: Mon, 8 Apr 2019 10:57:29 +0200
c313de
Subject: [PATCH] qemu: Add hotpluging support for PCI devices on S390 guests
c313de
MIME-Version: 1.0
c313de
Content-Type: text/plain; charset=UTF-8
c313de
Content-Transfer-Encoding: 8bit
c313de
c313de
This commit adds hotplug support for PCI devices on S390 guests.
c313de
There's no need to implement hot unplug for zPCI as QEMU implements
c313de
an unplug callback which will unplug both PCI and zPCI device in a
c313de
cascaded way.
c313de
Currently, the following PCI devices are supported:
c313de
  virtio-blk-pci
c313de
  virtio-net-pci
c313de
  virtio-rng-pci
c313de
  virtio-input-host-pci
c313de
  virtio-keyboard-pci
c313de
  virtio-mouse-pci
c313de
  virtio-tablet-pci
c313de
  vfio-pci
c313de
  SCSIVhost device
c313de
c313de
Signed-off-by: Yi Min Zhao <zyimin@linux.ibm.com>
c313de
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
c313de
Reviewed-by: Stefan Zimmermann <stzi@linux.ibm.com>
c313de
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
c313de
Reviewed-by: Ján Tomko <jtomko@redhat.com>
c313de
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
c313de
c313de
(cherry picked from commit 1d1e264f13d14ed05838bae2fcec2ffef26671f2)
c313de
c313de
https://bugzilla.redhat.com/show_bug.cgi?id=1508149
c313de
c313de
Conflicts:
c313de
c313de
  * src/qemu/qemu_hotplug.c
c313de
    + context
c313de
      - missing 83fe11e950bc
c313de
c313de
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
c313de
Message-Id: <20190408085732.28684-13-abologna@redhat.com>
c313de
Reviewed-by: Laine Stump <laine@redhat.com>
c313de
Reviewed-by: Ján Tomko <jtomko@redhat.com>
c313de
---
c313de
 src/qemu/qemu_hotplug.c | 160 +++++++++++++++++++++++++++++++++++++---
c313de
 1 file changed, 151 insertions(+), 9 deletions(-)
c313de
c313de
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
c313de
index 776cd75474..abe2632556 100644
c313de
--- a/src/qemu/qemu_hotplug.c
c313de
+++ b/src/qemu/qemu_hotplug.c
c313de
@@ -154,6 +154,80 @@ qemuHotplugPrepareDiskAccess(virQEMUDriverPtr driver,
c313de
 }
c313de
 
c313de
 
c313de
+static int
c313de
+qemuDomainAttachZPCIDevice(qemuMonitorPtr mon,
c313de
+                           virDomainDeviceInfoPtr info)
c313de
+{
c313de
+    char *devstr_zpci = NULL;
c313de
+    int ret = -1;
c313de
+
c313de
+    if (!(devstr_zpci = qemuBuildZPCIDevStr(info)))
c313de
+        goto cleanup;
c313de
+
c313de
+    if (qemuMonitorAddDevice(mon, devstr_zpci) < 0)
c313de
+        goto cleanup;
c313de
+
c313de
+    ret = 0;
c313de
+
c313de
+ cleanup:
c313de
+    VIR_FREE(devstr_zpci);
c313de
+    return ret;
c313de
+}
c313de
+
c313de
+
c313de
+static int
c313de
+qemuDomainDetachZPCIDevice(qemuMonitorPtr mon,
c313de
+                           virDomainDeviceInfoPtr info)
c313de
+{
c313de
+    char *zpciAlias = NULL;
c313de
+    int ret = -1;
c313de
+
c313de
+    if (virAsprintf(&zpciAlias, "zpci%d", info->addr.pci.zpci.uid) < 0)
c313de
+        goto cleanup;
c313de
+
c313de
+    if (qemuMonitorDelDevice(mon, zpciAlias) < 0)
c313de
+        goto cleanup;
c313de
+
c313de
+    ret = 0;
c313de
+
c313de
+ cleanup:
c313de
+    VIR_FREE(zpciAlias);
c313de
+    return ret;
c313de
+}
c313de
+
c313de
+
c313de
+static int
c313de
+qemuDomainAttachExtensionDevice(qemuMonitorPtr mon,
c313de
+                                virDomainDeviceInfoPtr info)
c313de
+{
c313de
+    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
c313de
+        info->addr.pci.extFlags == VIR_PCI_ADDRESS_EXTENSION_NONE) {
c313de
+        return 0;
c313de
+    }
c313de
+
c313de
+    if (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI)
c313de
+        return qemuDomainAttachZPCIDevice(mon, info);
c313de
+
c313de
+    return 0;
c313de
+}
c313de
+
c313de
+
c313de
+static int
c313de
+qemuDomainDetachExtensionDevice(qemuMonitorPtr mon,
c313de
+                                virDomainDeviceInfoPtr info)
c313de
+{
c313de
+    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
c313de
+        info->addr.pci.extFlags == VIR_PCI_ADDRESS_EXTENSION_NONE) {
c313de
+        return 0;
c313de
+    }
c313de
+
c313de
+    if (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI)
c313de
+        return qemuDomainDetachZPCIDevice(mon, info);
c313de
+
c313de
+    return 0;
c313de
+}
c313de
+
c313de
+
c313de
 static int
c313de
 qemuHotplugWaitForTrayEject(virQEMUDriverPtr driver,
c313de
                             virDomainObjPtr vm,
c313de
@@ -403,9 +477,14 @@ qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
c313de
     if (qemuBlockStorageSourceAttachApply(priv->mon, data) < 0)
c313de
         goto exit_monitor;
c313de
 
c313de
-    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
c313de
+    if (qemuDomainAttachExtensionDevice(priv->mon, &disk->info) < 0)
c313de
         goto exit_monitor;
c313de
 
c313de
+    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &disk->info));
c313de
+        goto exit_monitor;
c313de
+    }
c313de
+
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0) {
c313de
         ret = -2;
c313de
         goto error;
c313de
@@ -519,7 +598,16 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
c313de
         goto cleanup;
c313de
 
c313de
     qemuDomainObjEnterMonitor(driver, vm);
c313de
-    ret = qemuMonitorAddDevice(priv->mon, devstr);
c313de
+
c313de
+    if ((ret = qemuDomainAttachExtensionDevice(priv->mon,
c313de
+                                               &controller->info)) < 0) {
c313de
+        goto exit_monitor;
c313de
+    }
c313de
+
c313de
+    if ((ret = qemuMonitorAddDevice(priv->mon, devstr)) < 0)
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &controller->info));
c313de
+
c313de
+ exit_monitor:
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0) {
c313de
         releaseaddr = false;
c313de
         ret = -1;
c313de
@@ -969,6 +1057,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
c313de
     }
c313de
 
c313de
     if (qemuDomainIsS390CCW(vm->def) &&
c313de
+        net->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
c313de
         virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CCW)) {
c313de
         net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
c313de
         if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
c313de
@@ -1038,7 +1127,15 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
c313de
         goto try_remove;
c313de
 
c313de
     qemuDomainObjEnterMonitor(driver, vm);
c313de
+
c313de
+    if (qemuDomainAttachExtensionDevice(priv->mon, &net->info) < 0) {
c313de
+        ignore_value(qemuDomainObjExitMonitor(driver, vm));
c313de
+        virDomainAuditNet(vm, NULL, net, "attach", false);
c313de
+        goto try_remove;
c313de
+    }
c313de
+
c313de
     if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &net->info));
c313de
         ignore_value(qemuDomainObjExitMonitor(driver, vm));
c313de
         virDomainAuditNet(vm, NULL, net, "attach", false);
c313de
         goto try_remove;
c313de
@@ -1256,8 +1353,16 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
c313de
         goto error;
c313de
 
c313de
     qemuDomainObjEnterMonitor(driver, vm);
c313de
-    ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr,
c313de
-                                     configfd, configfd_name);
c313de
+
c313de
+    if ((ret = qemuDomainAttachExtensionDevice(priv->mon, hostdev->info)) < 0)
c313de
+        goto exit_monitor;
c313de
+
c313de
+    if ((ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr,
c313de
+                                          configfd, configfd_name)) < 0) {
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, hostdev->info));
c313de
+    }
c313de
+
c313de
+ exit_monitor:
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0)
c313de
         goto error;
c313de
 
c313de
@@ -1913,9 +2018,14 @@ qemuDomainAttachRNGDevice(virQEMUDriverPtr driver,
c313de
     if (qemuMonitorAddObject(priv->mon, &props, &objAlias) < 0)
c313de
         goto exit_monitor;
c313de
 
c313de
-    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
c313de
+    if (qemuDomainAttachExtensionDevice(priv->mon, &rng->info) < 0)
c313de
         goto exit_monitor;
c313de
 
c313de
+    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &rng->info));
c313de
+        goto exit_monitor;
c313de
+    }
c313de
+
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0) {
c313de
         releaseaddr = false;
c313de
         goto cleanup;
c313de
@@ -2407,8 +2517,16 @@ qemuDomainAttachSCSIVHostDevice(virQEMUDriverPtr driver,
c313de
 
c313de
     qemuDomainObjEnterMonitor(driver, vm);
c313de
 
c313de
-    ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr, vhostfd, vhostfdName);
c313de
+    if ((ret = qemuDomainAttachExtensionDevice(priv->mon, hostdev->info)) < 0)
c313de
+        goto exit_monitor;
c313de
 
c313de
+    if ((ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr, vhostfd,
c313de
+                                          vhostfdName)) < 0) {
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, hostdev->info));
c313de
+        goto exit_monitor;
c313de
+    }
c313de
+
c313de
+ exit_monitor:
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0 || ret < 0)
c313de
         goto audit;
c313de
 
c313de
@@ -2653,9 +2771,14 @@ qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
c313de
 
c313de
     release_backing = true;
c313de
 
c313de
-    if (qemuMonitorAddDevice(priv->mon, shmstr) < 0)
c313de
+    if (qemuDomainAttachExtensionDevice(priv->mon, &shmem->info) < 0)
c313de
         goto exit_monitor;
c313de
 
c313de
+    if (qemuMonitorAddDevice(priv->mon, shmstr) < 0) {
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &shmem->info));
c313de
+        goto exit_monitor;
c313de
+    }
c313de
+
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0) {
c313de
         release_address = false;
c313de
         goto cleanup;
c313de
@@ -2827,9 +2950,15 @@ qemuDomainAttachInputDevice(virQEMUDriverPtr driver,
c313de
         goto cleanup;
c313de
 
c313de
     qemuDomainObjEnterMonitor(driver, vm);
c313de
-    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
c313de
+
c313de
+    if (qemuDomainAttachExtensionDevice(priv->mon, &input->info) < 0)
c313de
         goto exit_monitor;
c313de
 
c313de
+    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &input->info));
c313de
+        goto exit_monitor;
c313de
+    }
c313de
+
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0) {
c313de
         releaseaddr = false;
c313de
         goto cleanup;
c313de
@@ -2906,9 +3035,15 @@ qemuDomainAttachVsockDevice(virQEMUDriverPtr driver,
c313de
         goto cleanup;
c313de
 
c313de
     qemuDomainObjEnterMonitor(driver, vm);
c313de
-    if (qemuMonitorAddDeviceWithFd(priv->mon, devstr, vsockPriv->vhostfd, fdname) < 0)
c313de
+
c313de
+    if (qemuDomainAttachExtensionDevice(priv->mon, &vsock->info) < 0)
c313de
         goto exit_monitor;
c313de
 
c313de
+    if (qemuMonitorAddDeviceWithFd(priv->mon, devstr, vsockPriv->vhostfd, fdname) < 0) {
c313de
+        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &vsock->info));
c313de
+        goto exit_monitor;
c313de
+    }
c313de
+
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0) {
c313de
         releaseaddr = false;
c313de
         goto cleanup;
c313de
@@ -4932,10 +5067,17 @@ int qemuDomainDetachControllerDevice(virQEMUDriverPtr driver,
c313de
         qemuDomainMarkDeviceForRemoval(vm, &detach->info);
c313de
 
c313de
     qemuDomainObjEnterMonitor(driver, vm);
c313de
+    if (detach->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
c313de
+        qemuDomainDetachExtensionDevice(priv->mon, &detach->info)) {
c313de
+        goto exit_monitor;
c313de
+    }
c313de
+
c313de
     if (qemuMonitorDelDevice(priv->mon, detach->info.alias)) {
c313de
         ignore_value(qemuDomainObjExitMonitor(driver, vm));
c313de
         goto cleanup;
c313de
     }
c313de
+
c313de
+ exit_monitor:
c313de
     if (qemuDomainObjExitMonitor(driver, vm) < 0)
c313de
         goto cleanup;
c313de
 
c313de
-- 
c313de
2.22.0
c313de