qemu: snapshot: Introduce helpers for creating overlays on <transient/> disks

To implement <transient/> 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 <transient/> and use it to
create a snapshot (without actually modifying metadata or persistent
def).

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Tested-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Tested-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Peter Krempa 2020-09-21 19:39:02 +02:00
parent afc25e8553
commit 117ff49db7
2 changed files with 96 additions and 1 deletions

View File

@ -986,6 +986,7 @@ qemuSnapshotDiskPrepareOne(virDomainObjPtr vm,
qemuSnapshotDiskDataPtr dd, qemuSnapshotDiskDataPtr dd,
virHashTablePtr blockNamedNodeData, virHashTablePtr blockNamedNodeData,
bool reuse, bool reuse,
bool updateConfig,
qemuDomainAsyncJob asyncJob, qemuDomainAsyncJob asyncJob,
virJSONValuePtr actions) virJSONValuePtr actions)
{ {
@ -1008,7 +1009,8 @@ qemuSnapshotDiskPrepareOne(virDomainObjPtr vm,
return -1; return -1;
/* modify disk in persistent definition only when the source is the same */ /* 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)) && (persistdisk = virDomainDiskByTarget(vm->newDef, dd->disk->dst)) &&
virStorageSourceIsSameLocation(dd->disk->src, persistdisk->src)) { virStorageSourceIsSameLocation(dd->disk->src, persistdisk->src)) {
@ -1116,6 +1118,55 @@ qemuSnapshotDiskPrepareActiveExternal(virDomainObjPtr vm,
snapctxt->dd + snapctxt->ndd++, snapctxt->dd + snapctxt->ndd++,
blockNamedNodeData, blockNamedNodeData,
reuse, 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, asyncJob,
snapctxt->actions) < 0) snapctxt->actions) < 0)
return NULL; 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 <transient/>. Note
* that the validation code ensures that <transient> 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 static int
qemuSnapshotCreateActiveExternal(virQEMUDriverPtr driver, qemuSnapshotCreateActiveExternal(virQEMUDriverPtr driver,
virDomainObjPtr vm, virDomainObjPtr vm,

View File

@ -21,6 +21,7 @@
#include "virconftypes.h" #include "virconftypes.h"
#include "datatypes.h" #include "datatypes.h"
#include "qemu_conf.h" #include "qemu_conf.h"
#include "qemu_domainjob.h"
virDomainMomentObjPtr virDomainMomentObjPtr
qemuSnapObjFromName(virDomainObjPtr vm, qemuSnapObjFromName(virDomainObjPtr vm,
@ -53,3 +54,7 @@ int
qemuSnapshotDelete(virDomainObjPtr vm, qemuSnapshotDelete(virDomainObjPtr vm,
virDomainSnapshotPtr snapshot, virDomainSnapshotPtr snapshot,
unsigned int flags); unsigned int flags);
int
qemuSnapshotCreateDisksTransient(virDomainObjPtr vm,
qemuDomainAsyncJob asyncJob);