From: "J.B. Joret" <jb(a)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(a)linux.vnet.ibm.com>
Signed-off-by: Viktor Mihajlovski <mihajlov(a)linux.vnet.ibm.com>
---
src/qemu/qemu_driver.c | 6 +-
src/qemu/qemu_hotplug.c | 149 ++++++++++++++++++++++++++++++++---------------
src/qemu/qemu_hotplug.h | 14 ++---
3 files changed, 111 insertions(+), 58 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5bc62a2..369f05f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5867,7 +5867,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 {
@@ -6000,7 +6000,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);
@@ -6011,7 +6011,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 18c4109..ad2ba8e 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -223,19 +223,26 @@ 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;
+ int i, ret = -1;
const char* type = virDomainDiskBusTypeToString(disk->bus);
qemuDomainObjPrivatePtr priv = vm->privateData;
char *devstr = NULL;
char *drivestr = NULL;
bool releaseaddr = false;
+ if (!disk->info.type) {
+ if (qemuCapsGet(priv->caps, QEMU_CAPS_VIRTIO_CCW))
+ disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
+ else if (qemuCapsGet(priv->caps, 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,
@@ -256,8 +263,14 @@ int qemuDomainAttachPciDiskDevice(virConnectPtr conn,
}
if (qemuCapsGet(priv->caps, 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->caps) < 0)
goto error;
@@ -292,16 +305,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 +332,16 @@ error:
VIR_FREE(devstr);
VIR_FREE(drivestr);
- if (qemuCapsGet(priv->caps, 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 (qemuCapsGet(priv->caps, 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 +424,6 @@ cleanup:
return ret;
}
-
static virDomainControllerDefPtr
qemuDomainFindOrCreateSCSIDiskController(virQEMUDriverPtr driver,
virDomainObjPtr vm,
@@ -763,9 +777,17 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
goto cleanup;
}
- if (qemuCapsGet(priv->caps, QEMU_CAPS_DEVICE) &&
- qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
- goto cleanup;
+ if (qemuCapsGet(priv->caps, 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 (qemuCapsGet(priv->caps, QEMU_CAPS_VIRTIO_S390))
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("virtio-s390 net device cannot be hotplugged."));
+ else if (qemuCapsGet(priv->caps, QEMU_CAPS_DEVICE) &&
+ qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) <
0)
+ goto cleanup;
releaseaddr = true;
@@ -894,11 +916,17 @@ cleanup:
vm->def->nets[vm->def->nnets++] = net;
} else {
if (qemuCapsGet(priv->caps, 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 (qemuCapsGet(priv->caps, 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);
@@ -1998,9 +2026,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;
@@ -2034,11 +2062,20 @@ 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 (qemuCapsGet(priv->caps, 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
@@ -2072,9 +2109,14 @@ int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver,
virDomainAuditDisk(vm, detach->src, NULL, "detach", true);
- if (qemuCapsGet(priv->caps, QEMU_CAPS_DEVICE) &&
- qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
- detach->info.addr.pci.slot) < 0)
+ if (detach->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
+ qemuCapsGet(priv->caps, 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 &&
+ qemuCapsGet(priv->caps, 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);
@@ -2569,19 +2611,27 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
-1);
goto cleanup;
}
+ if (qemuCapsGet(priv->caps, 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) {
@@ -2629,7 +2679,10 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
virDomainAuditNet(vm, detach, NULL, "detach", true);
- if (qemuCapsGet(priv->caps, QEMU_CAPS_DEVICE) &&
+ if (qemuCapsGet(priv->caps, QEMU_CAPS_VIRTIO_CCW)) {
+ if (qemuDomainCCWAddressReleaseAddr(priv->ccwaddrs, &detach->info) <
0)
+ VIR_WARN("Unable to release CCW address on NIC");
+ } else if (qemuCapsGet(priv->caps, 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