[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[PATCH v3 5/6] qemu: Introduce to handle transient disk



From: Masayoshi Mizuma <m mizuma jp fujitsu com>

Here is the implementation of transient option for qcow2 and raw format
disk. This gets available <transient/> directive in domain xml file
like as:

    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/guest.qcow2'/>
      <target dev='vda' bus='virtio'/>
      <transient/>
    </disk>

When the qemu command line options are built, a new qcow2 image is
created with backing qcow2 by using blockdev-snapshot command.
The backing image is the qcow2 file which is set as <source>.
The filename of the new qcow2 image is original-source-file.TRANSIENT.

Signed-off-by: Masayoshi Mizuma <m mizuma jp fujitsu com>
---
 src/qemu/qemu_snapshot.c  | 103 +++++++++++++++++++++++++++++++++++---
 src/qemu/qemu_snapshot.h  |   5 ++
 src/util/virstoragefile.c |   2 +
 src/util/virstoragefile.h |   4 ++
 4 files changed, 107 insertions(+), 7 deletions(-)

diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
index 1e8ea80b22..67fdc488e0 100644
--- a/src/qemu/qemu_snapshot.c
+++ b/src/qemu/qemu_snapshot.c
@@ -1158,7 +1158,8 @@ qemuSnapshotCreateDiskActive(virQEMUDriverPtr driver,
                              virHashTablePtr blockNamedNodeData,
                              unsigned int flags,
                              virQEMUDriverConfigPtr cfg,
-                             qemuDomainAsyncJob asyncJob)
+                             qemuDomainAsyncJob asyncJob,
+                             bool domSave)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
     g_autoptr(virJSONValue) actions = NULL;
@@ -1201,17 +1202,26 @@ qemuSnapshotCreateDiskActive(virQEMUDriverPtr driver,
 
         virDomainAuditDisk(vm, dd->disk->src, dd->src, "snapshot", rc >= 0);
 
-        if (rc == 0)
+        if (rc == 0) {
             qemuSnapshotDiskUpdateSource(driver, vm, dd, blockdev);
+
+            if (dd->disk->transient) {
+                /* Mark the transient working is completed to make sure we can */
+                /* remove the transient disk when the guest is shutdown. */
+                dd->disk->src->transientEstablished = true;
+            }
+        }
     }
 
     if (rc < 0)
         goto cleanup;
 
-    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0 ||
-        (vm->newDef && virDomainDefSave(vm->newDef, driver->xmlopt,
-                                        cfg->configDir) < 0))
-        goto cleanup;
+    if (domSave) {
+        if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0 ||
+            (vm->newDef && virDomainDefSave(vm->newDef, driver->xmlopt,
+                                            cfg->configDir) < 0))
+            goto cleanup;
+    }
 
     ret = 0;
 
@@ -1349,7 +1359,7 @@ qemuSnapshotCreateActiveExternal(virQEMUDriverPtr driver,
 
     if ((ret = qemuSnapshotCreateDiskActive(driver, vm, snap,
                                             blockNamedNodeData, flags, cfg,
-                                            QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
+                                            QEMU_ASYNC_JOB_SNAPSHOT, true)) < 0)
         goto cleanup;
 
     /* the snapshot is complete now */
@@ -2264,3 +2274,82 @@ qemuSnapshotDelete(virDomainObjPtr vm,
  cleanup:
     return ret;
 }
+
+
+static int
+qemuSnapshotSetupTransientDisk(virDomainSnapshotDiskDefPtr def,
+                               virStorageSourcePtr src)
+{
+    g_autoptr(virStorageSource) trans = NULL;
+
+    if (!(trans = virStorageSourceNew()))
+        return -1;
+
+    trans->path = g_strdup_printf("%s.TRANSIENT", src->path);
+    if (virFileExists(trans->path)) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("Transient disk '%s' for '%s' exists"),
+                       trans->path, src->path);
+        return -1;
+    }
+
+    trans->type = VIR_STORAGE_TYPE_FILE;
+    trans->format = VIR_STORAGE_FILE_QCOW2;
+
+    def->src = g_steal_pointer(&trans);
+
+    return 0;
+}
+
+
+int
+qemuSnapshotCreateTransientDisk(virQEMUDriverPtr driver,
+                                virDomainObjPtr vm,
+                                int asyncJob)
+{
+    int rc;
+    size_t i;
+    virDomainMomentObjPtr snap = NULL;
+    g_autoptr(virDomainSnapshotDef) snapdef = NULL;
+    g_autoptr(virHashTable) blockNamedNodeData = NULL;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(priv->driver);
+
+    if (!(snapdef = virDomainSnapshotDefNew()))
+        return -1;
+
+    snapdef->parent.name = g_strdup_printf("transient");
+
+    snapdef->ndisks = vm->def->ndisks;
+    if (VIR_ALLOC_N(snapdef->disks, snapdef->ndisks) < 0)
+        return -1;
+
+    for (i = 0; i < vm->def->ndisks; i++) {
+        virDomainDiskDefPtr disk = vm->def->disks[i];
+        virDomainSnapshotDiskDefPtr snapdisk = &(snapdef->disks[i]);
+
+        if (disk->transient) {
+            if ((rc = qemuSnapshotSetupTransientDisk(snapdisk, disk->src)) < 0)
+                return -1;
+
+        } else {
+            snapdisk->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
+        }
+    }
+
+    if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, snapdef)))
+        return -1;
+
+    if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, asyncJob)))
+        goto cleanup;
+
+    /* The last argument domSave is false here because transient disk config */
+    /* is volatile so we don't need to save it. */
+    rc = qemuSnapshotCreateDiskActive(driver, vm, snap, blockNamedNodeData,
+                                      0, cfg, asyncJob, false);
+
+ cleanup:
+    virDomainSnapshotObjListRemove(vm->snapshots, snap);
+
+    return rc;
+}
diff --git a/src/qemu/qemu_snapshot.h b/src/qemu/qemu_snapshot.h
index 8b3ebe87b1..d57ef4b8a4 100644
--- a/src/qemu/qemu_snapshot.h
+++ b/src/qemu/qemu_snapshot.h
@@ -53,3 +53,8 @@ int
 qemuSnapshotDelete(virDomainObjPtr vm,
                    virDomainSnapshotPtr snapshot,
                    unsigned int flags);
+
+int
+qemuSnapshotCreateTransientDisk(virQEMUDriverPtr driver,
+                                virDomainObjPtr vm,
+                                int asyncJob);
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
index 97a346db28..636f27ef09 100644
--- a/src/util/virstoragefile.c
+++ b/src/util/virstoragefile.c
@@ -2456,6 +2456,8 @@ virStorageSourceCopy(const virStorageSource *src,
     def->ssh_host_key_check_disabled = src->ssh_host_key_check_disabled;
     def->ssh_user = g_strdup(src->ssh_user);
 
+    def->transientEstablished = src->transientEstablished;
+
     return g_steal_pointer(&def);
 }
 
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index 87763cf389..0dc275c11e 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -384,6 +384,10 @@ struct _virStorageSource {
     /* these must not be used apart from formatting the output JSON in the qemu driver */
     char *ssh_user;
     bool ssh_host_key_check_disabled;
+
+    /* set to true if the storage source is setup as a transient disk. */
+    /* The changes to the disk are dropped after the guest machine is shutdown. */
+    bool transientEstablished;
 };
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSource, virObjectUnref);
-- 
2.27.0


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]