[libvirt] [PATCHv3 2/3] S390: Add hotplug support for s390 virtio devices

Viktor Mihajlovski mihajlov at linux.vnet.ibm.com
Mon Feb 11 22:55:45 UTC 2013


From: "J.B. Joret" <jb at linux.vnet.ibm.com>

We didn't yet expose the virtio device attach and detach functionality
for s390 domains as the device hotplug was very limited with the old
virtio-s390 bus. With the CCW bus there's full hotplug support for
virtio devices in QEMU, so we are adding this to libvirt too.

Since the virtio hotplug isn't limited to PCI anymore, we change the
function names from xxxPCIyyy to xxxVirtioyyy, where we handle all
three virtio bus types.

Signed-off-by: J.B. Joret <jb at linux.vnet.ibm.com>
Signed-off-by: Viktor Mihajlovski <mihajlov at linux.vnet.ibm.com>
---
V2 Changes
 - rebase, mainly addressing the rename of qemuCapsXXX to virQEMUCapsXXX 

V3 Changes
 - check whether machine type is s390-ccw

 src/qemu/qemu_driver.c  |    6 +-
 src/qemu/qemu_hotplug.c |  154 ++++++++++++++++++++++++++++++++---------------
 src/qemu/qemu_hotplug.h |   14 ++---
 3 files changed, 117 insertions(+), 57 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a4fc0c9..dbc6fce 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5859,7 +5859,7 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
             ret = qemuDomainAttachUsbMassstorageDevice(conn, driver, vm,
                                                        disk);
         } else if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
-            ret = qemuDomainAttachPciDiskDevice(conn, driver, vm, disk);
+            ret = qemuDomainAttachVirtioDiskDevice(conn, driver, vm, disk);
         } else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
             ret = qemuDomainAttachSCSIDisk(conn, driver, vm, disk);
         } else {
@@ -5992,7 +5992,7 @@ qemuDomainDetachDeviceDiskLive(virQEMUDriverPtr driver,
     case VIR_DOMAIN_DISK_DEVICE_DISK:
     case VIR_DOMAIN_DISK_DEVICE_LUN:
         if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
-            ret = qemuDomainDetachPciDiskDevice(driver, vm, dev);
+            ret = qemuDomainDetachVirtioDiskDevice(driver, vm, dev);
         else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                  disk->bus == VIR_DOMAIN_DISK_BUS_USB)
             ret = qemuDomainDetachDiskDevice(driver, vm, dev);
@@ -6003,7 +6003,7 @@ qemuDomainDetachDeviceDiskLive(virQEMUDriverPtr driver,
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("disk device type '%s' cannot be detached"),
-                       virDomainDiskDeviceTypeToString(disk->type));
+                       virDomainDiskDeviceTypeToString(disk->device));
         break;
     }
 
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 0c28a6a..d09a5fb 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -224,11 +224,10 @@ cleanup:
     return ret;
 }
 
-
-int qemuDomainAttachPciDiskDevice(virConnectPtr conn,
-                                  virQEMUDriverPtr driver,
-                                  virDomainObjPtr vm,
-                                  virDomainDiskDefPtr disk)
+int qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
+                                     virQEMUDriverPtr driver,
+                                     virDomainObjPtr vm,
+                                     virDomainDiskDefPtr disk)
 {
     int i, ret = -1;
     const char* type = virDomainDiskBusTypeToString(disk->bus);
@@ -238,6 +237,15 @@ int qemuDomainAttachPciDiskDevice(virConnectPtr conn,
     bool releaseaddr = false;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
 
+    if (!disk->info.type) {
+        if (STREQLEN(vm->def->os.machine, "s390-ccw", 8) &&
+            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW))
+            disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
+        else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390))
+            disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390;
+        else disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+    }
+
     for (i = 0 ; i < vm->def->ndisks ; i++) {
         if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
             virReportError(VIR_ERR_OPERATION_FAILED,
@@ -258,8 +266,14 @@ int qemuDomainAttachPciDiskDevice(virConnectPtr conn,
     }
 
     if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
-        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
-            goto error;
+        if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+            if (qemuDomainCCWAddressAssign(&disk->info, priv->ccwaddrs,
+                                           !disk->info.addr.ccw.assigned) < 0)
+                goto error;
+        } else if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+            if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
+                goto error;
+        }
         releaseaddr = true;
         if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
             goto error;
@@ -294,16 +308,14 @@ int qemuDomainAttachPciDiskDevice(virConnectPtr conn,
                 }
             }
         }
-    } else {
+    } else if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI){
         virDevicePCIAddress guestAddr = disk->info.addr.pci;
         ret = qemuMonitorAddPCIDisk(priv->mon,
                                     disk->src,
                                     type,
                                     &guestAddr);
-        if (ret == 0) {
-            disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+        if (ret == 0)
             memcpy(&disk->info.addr.pci, &guestAddr, sizeof(guestAddr));
-        }
     }
     qemuDomainObjExitMonitorWithDriver(driver, vm);
 
@@ -321,12 +333,16 @@ cleanup:
     return ret;
 
 error:
-    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
-        (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
-        releaseaddr &&
-        qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
-                                        disk->info.addr.pci.slot) < 0)
-        VIR_WARN("Unable to release PCI address on %s", disk->src);
+    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && releaseaddr) {
+        if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
+            qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
+                                            disk->info.addr.pci.slot) < 0)
+            VIR_WARN("Unable to release PCI address on %s", disk->src);
+        else if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
+                 qemuDomainCCWAddressReleaseAddr(priv->ccwaddrs,
+                                                 &disk->info) < 0)
+            VIR_WARN("Unable to release CCW address on %s", disk->src);
+    }
 
     if (virSecurityManagerRestoreImageLabel(driver->securityManager,
                                             vm->def, disk) < 0)
@@ -409,7 +425,6 @@ cleanup:
     return ret;
 }
 
-
 static virDomainControllerDefPtr
 qemuDomainFindOrCreateSCSIDiskController(virQEMUDriverPtr driver,
                                          virDomainObjPtr vm,
@@ -765,9 +780,18 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
             goto cleanup;
     }
 
-    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
-        qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
-        goto cleanup;
+    if (STREQLEN(vm->def->os.machine, "s390-ccw", 8) &&
+        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
+        net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
+        if (qemuDomainCCWAddressAssign(&net->info, priv->ccwaddrs,
+                                       !net->info.addr.ccw.assigned) < 0)
+            goto cleanup;
+    } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390))
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                        _("virtio-s390 net device cannot be hotplugged."));
+    else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
+             qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
+             goto cleanup;
 
     releaseaddr = true;
 
@@ -896,11 +920,18 @@ cleanup:
         vm->def->nets[vm->def->nnets++] = net;
     } else {
         if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
-            (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
+            net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
             releaseaddr &&
             qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
-                                            net->info.addr.pci.slot) < 0)
+                                            net->info.addr.pci.slot) < 0) {
             VIR_WARN("Unable to release PCI address on NIC");
+        } else if (STREQLEN(vm->def->os.machine, "s390-ccw", 8) &&
+                   virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW) &&
+                   net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
+                   releaseaddr &&
+                   qemuDomainCCWAddressReleaseAddr(priv->ccwaddrs,
+                                                   &net->info) < 0)
+            VIR_WARN("Unable to release CCW address on NIC");
 
         if (iface_connected) {
             virDomainConfNWFilterTeardown(net);
@@ -2008,9 +2039,9 @@ static bool qemuIsMultiFunctionDevice(virDomainDefPtr def,
 }
 
 
-int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver,
-                                  virDomainObjPtr vm,
-                                  virDomainDeviceDefPtr dev)
+int qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver,
+                                     virDomainObjPtr vm,
+                                     virDomainDeviceDefPtr dev)
 {
     int i, ret = -1;
     virDomainDiskDefPtr detach = NULL;
@@ -2044,11 +2075,21 @@ int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver,
         }
     }
 
-    if (!virDomainDeviceAddressIsValid(&detach->info,
-                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
-        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                       _("device cannot be detached without a PCI address"));
-        goto cleanup;
+    if (STREQLEN(vm->def->os.machine, "s390-ccw", 8) &&
+        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
+        if (!virDomainDeviceAddressIsValid(&detach->info,
+                                           VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("device cannot be detached without a valid CCW address"));
+            goto cleanup;
+        }
+    } else {
+        if (!virDomainDeviceAddressIsValid(&detach->info,
+                                           VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("device cannot be detached without a valid PCI address"));
+            goto cleanup;
+        }
     }
 
     /* build the actual drive id string as the disk->info.alias doesn't
@@ -2082,9 +2123,15 @@ int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver,
 
     virDomainAuditDisk(vm, detach->src, NULL, "detach", true);
 
-    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
-        qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
-                                        detach->info.addr.pci.slot) < 0)
+    if (detach->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
+        STREQLEN(vm->def->os.machine, "s390-ccw", 8) &&
+        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW) &&
+        qemuDomainCCWAddressReleaseAddr(priv->ccwaddrs, &detach->info) < 0) {
+        VIR_WARN("Unable to release CCW address on %s", dev->data.disk->src);
+    } else if (detach->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
+               virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
+               qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
+                                               detach->info.addr.pci.slot) < 0)
         VIR_WARN("Unable to release PCI address on %s", dev->data.disk->src);
 
     virDomainDiskRemove(vm->def, i);
@@ -2587,19 +2634,28 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
                                              -1);
         goto cleanup;
     }
+    if (STREQLEN(vm->def->os.machine, "s390-ccw", 8) &&
+        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
+        if (!virDomainDeviceAddressIsValid(&detach->info,
+                                           VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                            "%s", _("device cannot be detached without a CCW address"));
+            goto cleanup;
+        }
+    } else {
+        if (!virDomainDeviceAddressIsValid(&detach->info,
+                                           VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                            "%s", _("device cannot be detached without a PCI address"));
+            goto cleanup;
+        }
 
-    if (!virDomainDeviceAddressIsValid(&detach->info,
-                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       "%s", _("device cannot be detached without a PCI address"));
-        goto cleanup;
-    }
-
-    if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       _("cannot hot unplug multifunction PCI device :%s"),
-                       dev->data.disk->dst);
-        goto cleanup;
+        if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                            _("cannot hot unplug multifunction PCI device :%s"),
+                            dev->data.disk->dst);
+            goto cleanup;
+        }
     }
 
     if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
@@ -2647,7 +2703,11 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
 
     virDomainAuditNet(vm, detach, NULL, "detach", true);
 
-    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
+    if (STREQLEN(vm->def->os.machine, "s390-ccw", 8) &&
+        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
+        if (qemuDomainCCWAddressReleaseAddr(priv->ccwaddrs, &detach->info) < 0)
+            VIR_WARN("Unable to release CCW address on NIC");
+    } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
         qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
                                         detach->info.addr.pci.slot) < 0)
         VIR_WARN("Unable to release PCI address on NIC");
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 8f01d23..5c946db 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -35,10 +35,10 @@ int qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
 int qemuDomainCheckEjectableMedia(virQEMUDriverPtr driver,
                                   virDomainObjPtr vm,
                                   enum qemuDomainAsyncJob asyncJob);
-int qemuDomainAttachPciDiskDevice(virConnectPtr conn,
-                                  virQEMUDriverPtr driver,
-                                  virDomainObjPtr vm,
-                                  virDomainDiskDefPtr disk);
+int qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
+                                     virQEMUDriverPtr driver,
+                                     virDomainObjPtr vm,
+                                     virDomainDiskDefPtr disk);
 int qemuDomainAttachPciControllerDevice(virQEMUDriverPtr driver,
                                         virDomainObjPtr vm,
                                         virDomainControllerDefPtr controller);
@@ -82,9 +82,9 @@ int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver,
                                  virDomainObjPtr vm,
                                  virDomainNetDefPtr dev,
                                  int linkstate);
-int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver,
-                                  virDomainObjPtr vm,
-                                  virDomainDeviceDefPtr dev);
+int qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver,
+                                     virDomainObjPtr vm,
+                                     virDomainDeviceDefPtr dev);
 int qemuDomainDetachDiskDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainDeviceDefPtr dev);
-- 
1.7.9.5




More information about the libvir-list mailing list