From: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
Enable <transient/> disk option for qemuDomainAttachDeviceDiskLive().
The disk hotplug works for virtio or scsi bus.
Signed-off-by: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
---
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