[PATCH 09/10] WIP: qemu_hotplug: make transient disk sharable

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


From: Masayoshi Mizuma <m.mizuma at jp.fujitsu.com>

Enable <transient/> and <shareable/> disk option for virtio and scsi
bus. When both options are set to the disk, qemu runs with 'blockdev'
options for the original disk which is marked as readonly, and without
the 'device' option. Then an overlay disk is created and attached to
the guest.

Signed-off-by: Masayoshi Mizuma <m.mizuma at jp.fujitsu.com>
---
 src/qemu/qemu_command.c  | 11 +++++
 src/qemu/qemu_hotplug.c  | 86 +++++++++++++++++++++++++++++++++++++++-
 src/qemu/qemu_hotplug.h  |  3 ++
 src/qemu/qemu_process.c  | 21 +++++++++-
 src/qemu/qemu_snapshot.c |  9 +++--
 5 files changed, 125 insertions(+), 5 deletions(-)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 1b4fa77867..b48e06d3da 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2142,6 +2142,11 @@ qemuBuildDiskCommandLine(virCommandPtr cmd,
 {
     g_autofree char *optstr = NULL;
 
+    /* The disk which has transient and sharable disk option
+     * doesn't need write lock, so mark readonly */
+    if (disk->transient && disk->src->shared)
+        disk->src->readonly = true;
+
     if (qemuBuildDiskSourceCommandLine(cmd, disk, qemuCaps) < 0)
         return -1;
 
@@ -2159,6 +2164,12 @@ qemuBuildDiskCommandLine(virCommandPtr cmd,
     if (qemuCommandAddExtDevice(cmd, &disk->info) < 0)
         return -1;
 
+    if (disk->transient && disk->src->shared) {
+        VIR_DEBUG("%s has transient and shareable disk option, so it's hot-added later.",
+                  disk->src->path);
+        return 0;
+    }
+
     virCommandAddArg(cmd, "-device");
 
     if (!(optstr = qemuBuildDiskDeviceStr(def, disk, bootindex,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 366ebeaa7c..99fc5fca5f 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -4502,7 +4502,7 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
         qemuHotplugRemoveManagedPR(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
         goto cleanup;
 
-    if (disk->transient) {
+    if (disk->transient && (asyncJob != QEMU_ASYNC_JOB_START)) {
         VIR_DEBUG("Removing transient overlay '%s' of disk '%s'",
                   disk->src->path, disk->dst);
         if (qemuDomainStorageFileInit(driver, vm, disk->src, NULL) >= 0) {
@@ -4519,6 +4519,90 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
 }
 
 
+/* XXX:
+ * Fix memory leaks when failures happen
+ */
+static int
+qemuHotplugDiskPrepareDisksTransient(virDomainObjPtr vm,
+                                     virQEMUDriverConfigPtr cfg G_GNUC_UNUSED,
+                                     qemuDomainAsyncJob asyncJob)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virQEMUDriverPtr driver = priv->driver;
+    size_t i;
+
+    for (i = 0; i < vm->def->ndisks; i++) {
+        virDomainDiskDefPtr domdisk = vm->def->disks[i];
+        virDomainDiskDefPtr newdisk;
+        virDomainDeviceDefPtr dev;
+
+        if (!domdisk->transient)
+            continue;
+
+        if (domdisk->transient && !domdisk->src->shared) {
+            VIR_DEBUG("Transient disk for %s is already built with blockdev-snapshot",
+                       domdisk->src->path);
+            continue;
+        }
+
+        if (!(newdisk = virDomainDiskDefNew(driver->xmlopt)))
+            return -1;
+
+        memcpy(&newdisk->info, &domdisk->info, sizeof(virDomainDeviceInfo));
+        newdisk->info.alias = NULL;
+        newdisk->info.romfile = NULL;
+        newdisk->bus = domdisk->bus;
+        newdisk->dst = g_strdup(domdisk->dst);
+        newdisk->transient = true;
+
+        if (!(dev = g_new0(virDomainDeviceDef, 1)))
+            return -1;
+
+        dev->type = VIR_DOMAIN_DEVICE_DISK;
+
+        if (!(newdisk->src = virStorageSourceCopy(domdisk->src, false)))
+             return -1;
+
+        if (qemuDomainRemoveDiskDevice(driver, vm, domdisk, asyncJob) < 0)
+            return -1;
+
+        newdisk->src->readonly = false;
+
+        dev->data.disk = newdisk;
+
+        VIR_DEBUG("Attaching transient disk %s", dev->data.disk->dst);
+        if (qemuDomainAttachDeviceDiskLiveInternal(driver, vm, dev, asyncJob) < 0) {
+            VIR_DEBUG("Failed to attach disk %s", dev->data.disk->dst);
+            return -1;
+        }
+
+        VIR_FREE(dev);
+    }
+
+    return 0;
+}
+
+
+int
+qemuHotplugCreateDisksTransient(virDomainObjPtr vm,
+                                qemuDomainAsyncJob asyncJob)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virQEMUDriverPtr driver = priv->driver;
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+
+    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV) &&
+        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_PCIE_ROOT_PORT_HOTPLUG)) {
+
+        VIR_DEBUG("prepare transient disks with disk hotplug");
+        if (qemuHotplugDiskPrepareDisksTransient(vm, cfg, asyncJob) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
 static int
 qemuDomainRemoveControllerDevice(virDomainObjPtr vm,
                                  virDomainControllerDefPtr controller)
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 6287c5b5e8..baef2dba42 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -160,3 +160,6 @@ int qemuHotplugAttachDBusVMState(virQEMUDriverPtr driver,
 int qemuHotplugRemoveDBusVMState(virQEMUDriverPtr driver,
                                  virDomainObjPtr vm,
                                  qemuDomainAsyncJob asyncJob);
+
+int qemuHotplugCreateDisksTransient(virDomainObjPtr vm,
+                                    qemuDomainAsyncJob asyncJob);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 4ba634dfc5..5724a88b7f 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -6863,6 +6863,25 @@ qemuProcessEnablePerf(virDomainObjPtr vm)
 }
 
 
+static int
+qemuProcessCreateDisksTransient(virDomainObjPtr vm,
+                                qemuDomainAsyncJob asyncJob)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+
+    if (qemuSnapshotCreateDisksTransient(vm, asyncJob) < 0)
+        return -1;
+
+    if (qemuHotplugCreateDisksTransient(vm, asyncJob) < 0)
+        return -1;
+
+    /* the overlays are established, so they can be deleted on shutdown */
+    priv->inhibitDiskTransientDelete = false;
+
+    return 0;
+}
+
+
 /**
  * qemuProcessLaunch:
  *
@@ -7216,7 +7235,7 @@ qemuProcessLaunch(virConnectPtr conn,
         goto cleanup;
 
     VIR_DEBUG("Setting up transient disk");
-    if (qemuSnapshotCreateDisksTransient(vm, asyncJob) < 0)
+    if (qemuProcessCreateDisksTransient(vm, asyncJob) < 0)
         goto cleanup;
 
     ret = 0;
diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
index a5cc0d47f2..764eba7b3d 100644
--- a/src/qemu/qemu_snapshot.c
+++ b/src/qemu/qemu_snapshot.c
@@ -1188,6 +1188,12 @@ qemuSnapshotDiskPrepareDisksTransient(virDomainObjPtr vm,
         if (!domdisk->transient)
             continue;
 
+        if (domdisk->transient && domdisk->src->shared) {
+            VIR_DEBUG("%s has shareable disk option, so it's hot-added later.",
+                      domdisk->src->path);
+            continue;
+        }
+
         /* validation code makes sure that we do this only for local disks
          * with a file source */
         snapdisk->name = g_strdup(domdisk->dst);
@@ -1379,9 +1385,6 @@ qemuSnapshotCreateDisksTransient(virDomainObjPtr vm,
             return -1;
     }
 
-    /* the overlays are established, so they can be deleted on shutdown */
-    priv->inhibitDiskTransientDelete = false;
-
     return 0;
 }
 
-- 
2.27.0




More information about the libvir-list mailing list