From: Masayoshi Mizuma <m.mizuma@xxxxxxxxxxxxxx> Enable <transient/> disk option for qemuDomainAttachDeviceDiskLive(). The disk hotplug works for virtio or scsi bus. Signed-off-by: Masayoshi Mizuma <m.mizuma@xxxxxxxxxxxxxx> --- src/qemu/qemu_hotplug.c | 135 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 128 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 58d2abb862..138645260f 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1025,6 +1025,111 @@ qemuDomainAttachUSBMassStorageDevice(virQEMUDriverPtr driver, return 0; } +static int +qemuHotplugDiskPrepareOneBlockdev(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virQEMUDriverConfigPtr cfg, + virDomainDiskDefPtr disk, + virStorageSourcePtr transrc, + qemuDomainAsyncJob asyncJob, + bool *created) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + g_autoptr(qemuBlockStorageSourceChainData) data = NULL; + g_autoptr(virStorageSource) terminator = NULL; + + terminator = virStorageSourceNew(); + + if (qemuDomainPrepareStorageSourceBlockdev(disk, transrc, + priv, cfg) < 0) + return -1; + + if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdevTop(transrc, + terminator, + priv->qemuCaps))) + return -1; + + transrc->capacity = disk->src->capacity; + + if (qemuBlockStorageSourceCreate(vm, transrc, disk->src, + NULL, data->srcdata[0], + asyncJob) < 0) + goto error; + + if (qemuBlockStorageSourceDetachOneBlockdev(driver, vm, + asyncJob, transrc) < 0) + goto error; + + *created = true; + + return 0; + + error: + qemuBlockStorageSourceAttachRollback(priv->mon, data->srcdata[0]); + virStorageSourceUnlink(transrc); + + return -1; +} + + +static int +qemuHotplugDiskPrepareOneDiskTransient(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDeviceDefPtr dev, + bool *created) +{ + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + virDomainDiskDefPtr disk = dev->data.disk; + virStorageSourcePtr origsrc = disk->src; + virStorageSourcePtr transrc; + bool supportsCreate; + + transrc = virStorageSourceNew(); + transrc->type = VIR_STORAGE_TYPE_FILE; + transrc->format = VIR_STORAGE_FILE_QCOW2; + transrc->path = g_strdup_printf("%s.TRANSIENT-%s", + disk->src->path, vm->def->name); + + if (virFileExists(transrc->path)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("Overlay file '%s' for transient disk '%s' already exists"), + transrc->path, disk->dst); + return -1; + } + + if (qemuDomainStorageSourceValidateDepth(transrc, 1, disk->dst) < 0) + return -1; + + if (virStorageSourceInitChainElement(transrc, disk->src, false) < 0) + return -1; + + supportsCreate = virStorageSourceSupportsCreate(transrc); + + if (supportsCreate) { + if (qemuDomainStorageFileInit(driver, vm, transrc, NULL) < 0) + return -1; + + if (virStorageSourceCreate(transrc) < 0) { + virReportSystemError(errno, _("failed to create image file '%s'"), + NULLSTR(transrc->path)); + return -1; + } + } + + if (qemuDomainStorageSourceAccessAllow(driver, vm, transrc, + false, true, true) < 0) + return -1; + + if (qemuHotplugDiskPrepareOneBlockdev(driver, vm, cfg, disk, transrc, + QEMU_ASYNC_JOB_NONE, created) < 0) + return -1; + + transrc->backingStore = origsrc; + disk->src = transrc; + + return 0; +} + static int qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriverPtr driver, @@ -1033,7 +1138,9 @@ qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriverPtr driver, { size_t i; virDomainDiskDefPtr disk = dev->data.disk; + virDomainDiskBus bus; int ret = -1; + bool transientDiskCreated = false; if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM || disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { @@ -1042,12 +1149,6 @@ qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriverPtr driver, return -1; } - if (disk->transient) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("transient disk hotplug isn't supported")); - return -1; - } - if (virDomainDiskTranslateSourcePool(disk) < 0) goto cleanup; @@ -1060,6 +1161,21 @@ qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriverPtr driver, if (qemuDomainDetermineDiskChain(driver, vm, disk, NULL, true) < 0) goto cleanup; + if (disk->transient) { + bus = (virDomainDiskBus) disk->bus; + + if ((bus != VIR_DOMAIN_DISK_BUS_VIRTIO) && + (bus != VIR_DOMAIN_DISK_BUS_SCSI)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("transient disk hotplug isn't supported")); + goto cleanup; + } + + if (qemuHotplugDiskPrepareOneDiskTransient(driver, vm, dev, + &transientDiskCreated) < 0) + goto cleanup; + } + for (i = 0; i < vm->def->ndisks; i++) { if (virDomainDiskDefCheckDuplicateInfo(vm->def->disks[i], disk) < 0) goto cleanup; @@ -1099,8 +1215,13 @@ qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriverPtr driver, } cleanup: - if (ret != 0) + if (ret != 0) { ignore_value(qemuRemoveSharedDevice(driver, dev, vm->def->name)); + if (transientDiskCreated) { + VIR_DEBUG("Removing transient disk %s", disk->src->path); + virStorageSourceUnlink(disk->src); + } + } return ret; } -- 2.27.0