render / rpms / libvirt

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