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

2020-09-18 Thread Peter Krempa
On Thu, Sep 17, 2020 at 09:30:44 -0400, Masayoshi Mizuma wrote:
> From: Masayoshi Mizuma 
> 
> Here is the implementation of transient option for qcow2 and raw format
> disk. This gets available  directive in domain xml file
> like as:
> 
> 
>   
>   
>   
>   
> 
> 
> 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 .
> The filename of the new qcow2 image is original-source-file.TRANSIENT.
> 
> Signed-off-by: Masayoshi Mizuma 
> ---
>  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;

This shouldn't be necessary if you factor out stuff out of
qemuSnapshotCreateDiskActive. I'll send a prerequisite patch doing the
refactor as I've requested last time.

> +
> +snapdef->parent.name = g_strdup_printf("transient");
> +
> +snapdef->ndisks = vm->def->ndisks;
> +if (VIR_ALLOC_N(snapdef->disks, snapdef->ndisks) < 0)
> +retur

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

2020-09-17 Thread Masayoshi Mizuma
From: Masayoshi Mizuma 

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


  
  
  
  


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 .
The filename of the new qcow2 image is original-source-file.TRANSIENT.

Signed-off-by: Masayoshi Mizuma 
---
 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)))
+re