From 117ff49db71f3ae7add0a20300d8cec6fc730a9a Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Mon, 21 Sep 2020 19:39:02 +0200 Subject: [PATCH] qemu: snapshot: Introduce helpers for creating overlays on disks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To implement disks we'll need to install an overlay on top of the original disk image which will be discarded after the VM is turned off. This was initially implemented by qemu but libvirt never picked up this option as the overlays were created by qemu without libvirt involvment which didn't work with SELinux. With blockdev the qemu feature became unsupported so we need to do this via the snapshot code anyways. The helpers introduced in this patch prepare a fake snapshot disk definition for a disk which is configured as and use it to create a snapshot (without actually modifying metadata or persistent def). Signed-off-by: Peter Krempa Tested-by: Masayoshi Mizuma Reviewed-by: Ján Tomko Tested-by: Ján Tomko --- src/qemu/qemu_snapshot.c | 92 +++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_snapshot.h | 5 +++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index ca051071aa..c2953c179b 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -986,6 +986,7 @@ qemuSnapshotDiskPrepareOne(virDomainObjPtr vm, qemuSnapshotDiskDataPtr dd, virHashTablePtr blockNamedNodeData, bool reuse, + bool updateConfig, qemuDomainAsyncJob asyncJob, virJSONValuePtr actions) { @@ -1008,7 +1009,8 @@ qemuSnapshotDiskPrepareOne(virDomainObjPtr vm, return -1; /* modify disk in persistent definition only when the source is the same */ - if (vm->newDef && + if (updateConfig && + vm->newDef && (persistdisk = virDomainDiskByTarget(vm->newDef, dd->disk->dst)) && virStorageSourceIsSameLocation(dd->disk->src, persistdisk->src)) { @@ -1116,6 +1118,55 @@ qemuSnapshotDiskPrepareActiveExternal(virDomainObjPtr vm, snapctxt->dd + snapctxt->ndd++, blockNamedNodeData, reuse, + true, + asyncJob, + snapctxt->actions) < 0) + return NULL; + } + + return g_steal_pointer(&snapctxt); +} + + +static qemuSnapshotDiskContextPtr +qemuSnapshotDiskPrepareDisksTransient(virDomainObjPtr vm, + virQEMUDriverConfigPtr cfg, + virHashTablePtr blockNamedNodeData, + qemuDomainAsyncJob asyncJob) +{ + g_autoptr(qemuSnapshotDiskContext) snapctxt = NULL; + size_t i; + + snapctxt = qemuSnapshotDiskContextNew(vm->def->ndisks, vm, asyncJob); + + for (i = 0; i < vm->def->ndisks; i++) { + virDomainDiskDefPtr domdisk = vm->def->disks[i]; + g_autoptr(virDomainSnapshotDiskDef) snapdisk = g_new0(virDomainSnapshotDiskDef, 1); + + if (!domdisk->transient) + continue; + + /* validation code makes sure that we do this only for local disks + * with a file source */ + snapdisk->name = g_strdup(domdisk->dst); + snapdisk->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL; + snapdisk->src = virStorageSourceNew(); + snapdisk->src->type = VIR_STORAGE_TYPE_FILE; + snapdisk->src->format = VIR_STORAGE_FILE_QCOW2; + snapdisk->src->path = g_strdup_printf("%s.TRANSIENT", domdisk->src->path); + + if (virFileExists(snapdisk->src->path)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("Overlay file '%s' for transient disk '%s' already exists"), + snapdisk->src->path, domdisk->dst); + return NULL; + } + + if (qemuSnapshotDiskPrepareOne(vm, cfg, domdisk, snapdisk, + snapctxt->dd + snapctxt->ndd++, + blockNamedNodeData, + false, + false, asyncJob, snapctxt->actions) < 0) return NULL; @@ -1253,6 +1304,45 @@ qemuSnapshotCreateActiveExternalDisks(virDomainObjPtr vm, } +/** + * qemuSnapshotCreateDisksTransient: + * @vm: domain object + * @asyncJob: qemu async job type + * + * Creates overlays on top of disks which are configured as . Note + * that the validation code ensures that disks have appropriate + * configuration. + */ +int +qemuSnapshotCreateDisksTransient(virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + virQEMUDriverPtr driver = priv->driver; + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + g_autoptr(qemuSnapshotDiskContext) snapctxt = NULL; + g_autoptr(virHashTable) blockNamedNodeData = NULL; + + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV)) { + if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, asyncJob))) + return -1; + + if (!(snapctxt = qemuSnapshotDiskPrepareDisksTransient(vm, cfg, + blockNamedNodeData, + asyncJob))) + return -1; + + if (qemuSnapshotDiskCreate(snapctxt, cfg) < 0) + return -1; + } + + /* the overlays are established, so they can be deleted on shutdown */ + priv->inhibitDiskTransientDelete = false; + + return 0; +} + + static int qemuSnapshotCreateActiveExternal(virQEMUDriverPtr driver, virDomainObjPtr vm, diff --git a/src/qemu/qemu_snapshot.h b/src/qemu/qemu_snapshot.h index 8b3ebe87b1..cf9bfec542 100644 --- a/src/qemu/qemu_snapshot.h +++ b/src/qemu/qemu_snapshot.h @@ -21,6 +21,7 @@ #include "virconftypes.h" #include "datatypes.h" #include "qemu_conf.h" +#include "qemu_domainjob.h" virDomainMomentObjPtr qemuSnapObjFromName(virDomainObjPtr vm, @@ -53,3 +54,7 @@ int qemuSnapshotDelete(virDomainObjPtr vm, virDomainSnapshotPtr snapshot, unsigned int flags); + +int +qemuSnapshotCreateDisksTransient(virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob);