[PATCH 01/10] qemu_hotplug: Add transient disk hotplug support

Masayoshi Mizuma msys.mizuma at gmail.com
Thu Mar 25 00:54:05 UTC 2021


From: Masayoshi Mizuma <m.mizuma at 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 at 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




More information about the libvir-list mailing list