[libvirt] [PATCH v2 11/11] qemu: Implement bulk snapshot operations
John Ferlan
jferlan at redhat.com
Wed Feb 27 17:27:42 UTC 2019
On 2/23/19 4:24 PM, Eric Blake wrote:
> Implement the new flags for bulk snapshot dump and redefine. This
> borrows from ideas in the test driver, but is further complicated
> by the fact that qemu must write snapshot XML to disk, and thus must
> do additional validation after the initial parse to ensure the user
> didn't attempt to rename a snapshot with "../" or similar.
>
> Of note: all prior callers of qemuDomainSnapshotDiscardAllMetadata()
> were at points where it did not matter if vm->current_snapshot and
> the metaroot in vm->snapshots were left pointing to stale memory,
> because we were about to delete the entire vm object; but now it is
> important to reset things properly so that the domain still shows
> as having no snapshots on failure.
>
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
> src/qemu/qemu_domain.h | 2 +-
> src/qemu/qemu_domain.c | 35 +++++++++++++++++------
> src/qemu/qemu_driver.c | 64 ++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 89 insertions(+), 12 deletions(-)
>
NB: I couldn't get this one to git am -3 apply - I didn't chase the
conflict though.
> diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
> index 7c6b50184c..37c9813ec5 100644
> --- a/src/qemu/qemu_domain.h
> +++ b/src/qemu/qemu_domain.h
> @@ -683,7 +683,7 @@ int qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
> virDomainSnapshotObjPtr snapshot,
> virCapsPtr caps,
> virDomainXMLOptionPtr xmlopt,
> - char *snapshotDir);
> + const char *snapshotDir);
Theoretically separable.
>
> int qemuDomainSnapshotForEachQcow2(virQEMUDriverPtr driver,
> virDomainObjPtr vm,
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index cb1665c8f9..cf8b6e8eaf 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -7704,6 +7704,7 @@ qemuDomainDefCopy(virQEMUDriverPtr driver,
>
> static int
> qemuDomainDefFormatBufInternal(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> virDomainDefPtr def,
> virCPUDefPtr origCPU,
> unsigned int flags,
> @@ -7713,8 +7714,10 @@ qemuDomainDefFormatBufInternal(virQEMUDriverPtr driver,
> virDomainDefPtr copy = NULL;
> virCapsPtr caps = NULL;
> virQEMUCapsPtr qemuCaps = NULL;
> + bool snapshots = flags & VIR_DOMAIN_XML_SNAPSHOTS;
>
> - virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS | VIR_DOMAIN_XML_UPDATE_CPU, -1);
> + virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS | VIR_DOMAIN_XML_UPDATE_CPU |
> + VIR_DOMAIN_XML_SNAPSHOTS, -1);
>
> if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
> goto cleanup;
> @@ -7881,7 +7884,14 @@ qemuDomainDefFormatBufInternal(virQEMUDriverPtr driver,
> }
>
> format:
> - ret = virDomainDefFormatInternal(def, caps, NULL, NULL,
> + if (snapshots && !vm) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("snapshots XML requested but not provided"));
Error msg is a bit odd - the error is that a snapshot listing was
desired, but consumer didn't pass the @vm object.
> + goto cleanup;
> + }
> + ret = virDomainDefFormatInternal(def, caps,
> + snapshots ? vm->snapshots : NULL,
> + snapshots ? vm->current_snapshot : NULL,
> virDomainDefFormatConvertXMLFlags(flags),
> buf, driver->xmlopt);
Perhaps this one should [be | have been] turned into a
virDomainDefFormatFull (or whatever new name is chosen if one is
chosen). I think it shows the hazards of exposing *Internal to many
consumers.
>
> @@ -7899,19 +7909,21 @@ qemuDomainDefFormatBuf(virQEMUDriverPtr driver,
> unsigned int flags,
> virBufferPtr buf)
> {
> - return qemuDomainDefFormatBufInternal(driver, def, NULL, flags, buf);
> + return qemuDomainDefFormatBufInternal(driver, NULL, def, NULL, flags, buf);
> }
>
>
> static char *
> qemuDomainDefFormatXMLInternal(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> virDomainDefPtr def,
> virCPUDefPtr origCPU,
> unsigned int flags)
> {
> virBuffer buf = VIR_BUFFER_INITIALIZER;
>
> - if (qemuDomainDefFormatBufInternal(driver, def, origCPU, flags, &buf) < 0)
> + if (qemuDomainDefFormatBufInternal(driver, vm, def, origCPU, flags,
> + &buf) < 0)
Existing; however, considering earlier comment about snapshot list being
filled into the buffer until error, but the *ListFormat not clearing the
buffer on error, I think another patch should be added here to do the
virBufferFreeAndReset(&buf); before return NULL.
> return NULL;
>
> return virBufferContentAndReset(&buf);
> @@ -7923,7 +7935,7 @@ qemuDomainDefFormatXML(virQEMUDriverPtr driver,
> virDomainDefPtr def,
> unsigned int flags)
> {
> - return qemuDomainDefFormatXMLInternal(driver, def, NULL, flags);
> + return qemuDomainDefFormatXMLInternal(driver, NULL, def, NULL, flags);
> }
>
>
> @@ -7942,7 +7954,7 @@ char *qemuDomainFormatXML(virQEMUDriverPtr driver,
> origCPU = priv->origCPU;
> }
>
> - return qemuDomainDefFormatXMLInternal(driver, def, origCPU, flags);
> + return qemuDomainDefFormatXMLInternal(driver, vm, def, origCPU, flags);
> }
>
> char *
> @@ -7959,7 +7971,7 @@ qemuDomainDefFormatLive(virQEMUDriverPtr driver,
> if (compatible)
> flags |= VIR_DOMAIN_XML_MIGRATABLE;
>
> - return qemuDomainDefFormatXMLInternal(driver, def, origCPU, flags);
> + return qemuDomainDefFormatXMLInternal(driver, NULL, def, origCPU, flags);
> }
>
>
> @@ -8386,7 +8398,7 @@ qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
> virDomainSnapshotObjPtr snapshot,
> virCapsPtr caps,
> virDomainXMLOptionPtr xmlopt,
> - char *snapshotDir)
> + const char *snapshotDir)
> {
> char *newxml = NULL;
> int ret = -1;
> @@ -8605,6 +8617,7 @@ qemuDomainSnapshotDiscardAllMetadata(virQEMUDriverPtr driver,
> virDomainObjPtr vm)
> {
> virQEMUSnapRemove rem;
> + virDomainSnapshotObjPtr snap;
>
> rem.driver = driver;
> rem.vm = vm;
> @@ -8612,6 +8625,12 @@ qemuDomainSnapshotDiscardAllMetadata(virQEMUDriverPtr driver,
> rem.err = 0;
> virDomainSnapshotForEach(vm->snapshots, qemuDomainSnapshotDiscardAll,
> &rem);
> + if (rem.current)
> + vm->current_snapshot = NULL;
> + /* Update the metaroot to match that all children were dropped */
> + snap = virDomainSnapshotFindByName(vm->snapshots, NULL);
> + snap->nchildren = 0;
> + snap->first_child = NULL;
>
> return rem.err;
> }
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index b3f4dc6f5c..4df9e18e4c 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -7337,8 +7337,8 @@ static char
> virDomainObjPtr vm;
> char *ret = NULL;
>
> - virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS | VIR_DOMAIN_XML_UPDATE_CPU,
> - NULL);
> + virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS | VIR_DOMAIN_XML_UPDATE_CPU |
> + VIR_DOMAIN_XML_SNAPSHOTS, NULL);
>
> if (!(vm = qemuDomObjFromDomain(dom)))
> goto cleanup;
> @@ -15733,6 +15733,31 @@ qemuDomainSnapshotValidate(virDomainSnapshotDefPtr def, int state,
> return 0;
> }
>
> +/* Struct and hash-iterator callback used when bulk redefining snapshots */
> +struct qemuDomainSnapshotBulk {
> + virDomainObjPtr vm;
> + virQEMUDriverPtr driver;
> + const char *snapshotDir;
> + unsigned int flags;
> +};
> +
> +static int
> +qemuDomainSnapshotBulkRedefine(void *payload, const void *name ATTRIBUTE_UNUSED,
one arg each line
> + void *opaque)
> +{
> + virDomainSnapshotObjPtr snap = payload;
> + struct qemuDomainSnapshotBulk *data = opaque;
> +
> + if (qemuDomainSnapshotValidate(snap->def, snap->def->state,
> + data->flags) < 0)
> + return -1;
> + if (qemuDomainSnapshotWriteMetadata(data->vm, snap, data->driver->caps,
> + data->driver->xmlopt,
> + data->snapshotDir) < 0)
> + return -1;
> + return 0;
> +}
> +
> static virDomainSnapshotPtr
> qemuDomainSnapshotCreateXML(virDomainPtr domain,
> const char *xmlDesc,
> @@ -15762,7 +15787,8 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
> VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
> VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
> VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
> - VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
> + VIR_DOMAIN_SNAPSHOT_CREATE_LIVE |
> + VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE_LIST, NULL);
>
> VIR_REQUIRE_FLAG_RET(VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE,
> VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY,
> @@ -15794,6 +15820,38 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
> goto cleanup;
> }
>
> + if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE_LIST) {
> + struct qemuDomainSnapshotBulk bulk = {
> + .vm = vm,
> + .driver = driver,
> + .snapshotDir = cfg->snapshotDir,
> + .flags = flags,
> + };
> +
> + if (virDomainSnapshotDefParseList(xmlDesc, vm->def->uuid,
> + vm->snapshots, &vm->current_snapshot,
> + caps, driver->xmlopt,
> + parse_flags) < 0)
> + goto cleanup;
> + /* Validate and save the snapshots to disk. Since we don't get
> + * here unless there were no snapshots beforehand, just delete
> + * everything if anything failed, ignoring further errors. */
> + if (virDomainSnapshotForEach(vm->snapshots,
> + qemuDomainSnapshotBulkRedefine,
> + &bulk) < 0) {
> + virErrorPtr orig_err = virSaveLastError();
> +
> + qemuDomainSnapshotDiscardAllMetadata(driver, vm);
> + virSetError(orig_err);
> + virFreeError(orig_err);
> + goto cleanup;
> + }
> + /* Return is arbitrary, so use the first root */
> + snap = virDomainSnapshotFindByName(vm->snapshots, NULL);
Similar to test driver - this isn't used during cleanup.
John
> + snapshot = virGetDomainSnapshot(domain, snap->first_child->def->name);
> + goto cleanup;
> + }
> +
> if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
> virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> _("cannot halt after transient domain snapshot"));
>
More information about the libvir-list
mailing list