[libvirt] [PATCH v10 16/19] backup: qemu: Implement metadata tracking for checkpoint APIs

Daniel P. Berrangé berrange at redhat.com
Wed Jul 24 16:27:07 UTC 2019


On Wed, Jul 24, 2019 at 12:56:06AM -0500, Eric Blake wrote:
> A lot of this work heavily copies from the existing snapshot
> APIs.  The interaction with qemu during create/delete still
> needs to be implemented, but this takes care of all the libvirt
> metadata (saving and restoring XML, and tracking the relations
> between multiple checkpoints).
> 
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
>  src/qemu/qemu_domain.h |  15 +
>  src/qemu/qemu_domain.c | 131 +++++++++
>  src/qemu/qemu_driver.c | 606 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 752 insertions(+)


> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index e7f28aa2b8..44ac7eb73e 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c


> +/* Discard one checkpoint (or its metadata), without reparenting any children.  */
> +int
> +qemuDomainCheckpointDiscard(virQEMUDriverPtr driver,
> +                            virDomainObjPtr vm,
> +                            virDomainMomentObjPtr chk,
> +                            bool update_parent,
> +                            bool metadata_only)
> +{
> +    char *chkFile = NULL;
> +    int ret = -1;
> +    virDomainMomentObjPtr parentchk = NULL;
> +    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> +
> +    if (!metadata_only) {
> +        if (!virDomainObjIsActive(vm)) {
> +            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                           _("cannot remove checkpoint from inactive domain"));
> +            goto cleanup;
> +        } else {
> +            /* TODO: Implement QMP sequence to merge bitmaps */
> +            // qemuDomainObjPrivatePtr priv;
> +            // priv = vm->privateData;
> +            // qemuDomainObjEnterMonitor(driver, vm);
> +            // /* we continue on even in the face of error */
> +            // qemuMonitorDeleteCheckpoint(priv->mon, chk->def->name);
> +            // ignore_value(qemuDomainObjExitMonitor(driver, vm));

Shouldn't we have a virReportError + goto cleamnup here until
this is actually implemented for real ?

> +        }
> +    }
> +
> +    if (virAsprintf(&chkFile, "%s/%s/%s.xml", cfg->checkpointDir,
> +                    vm->def->name, chk->def->name) < 0)
> +        goto cleanup;
> +
> +    if (chk == virDomainCheckpointGetCurrent(vm->checkpoints)) {
> +        virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
> +        if (update_parent && chk->def->parent_name) {
> +            parentchk = virDomainCheckpointFindByName(vm->checkpoints,
> +                                                      chk->def->parent_name);
> +            if (!parentchk) {
> +                VIR_WARN("missing parent checkpoint matching name '%s'",
> +                         chk->def->parent_name);
> +            } else {
> +                virDomainCheckpointSetCurrent(vm->checkpoints, parentchk);
> +                if (qemuDomainCheckpointWriteMetadata(vm, parentchk, driver->caps,
> +                                                      driver->xmlopt,
> +                                                      cfg->checkpointDir) < 0) {
> +                    VIR_WARN("failed to set parent checkpoint '%s' as current",
> +                             chk->def->parent_name);
> +                    virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
> +                }
> +            }
> +        }
> +    }
> +
> +    if (unlink(chkFile) < 0)
> +        VIR_WARN("Failed to unlink %s", chkFile);
> +    if (update_parent)
> +        virDomainMomentDropParent(chk);
> +    virDomainCheckpointObjListRemove(vm->checkpoints, chk);
> +
> +    ret = 0;
> +
> + cleanup:
> +    VIR_FREE(chkFile);
> +    virObjectUnref(cfg);
> +    return ret;
> +}

> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index fae2bd3b08..a75a16492b 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c




> +static virDomainCheckpointPtr
> +qemuDomainCheckpointCreateXML(virDomainPtr domain,
> +                              const char *xmlDesc,
> +                              unsigned int flags)
> +{
> +    virQEMUDriverPtr driver = domain->conn->privateData;
> +    virDomainObjPtr vm = NULL;
> +    char *xml = NULL;
> +    virDomainMomentObjPtr chk = NULL;
> +    virDomainCheckpointPtr checkpoint = NULL;
> +    bool update_current = true;
> +    bool redefine = flags & VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE;
> +    unsigned int parse_flags = 0;
> +    virDomainMomentObjPtr other = NULL;
> +    virQEMUDriverConfigPtr cfg = NULL;
> +    virCapsPtr caps = NULL;
> +    VIR_AUTOUNREF(virDomainCheckpointDefPtr) def = NULL;
> +
> +    virCheckFlags(VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE, NULL);
> +    /* TODO: VIR_DOMAIN_CHECKPOINT_CREATE_QUIESCE */
> +
> +    if (redefine) {
> +        parse_flags |= VIR_DOMAIN_CHECKPOINT_PARSE_REDEFINE;
> +        update_current = false;
> +    }
> +
> +    if (!(vm = qemuDomObjFromDomain(domain)))
> +        goto cleanup;
> +
> +    if (virDomainSnapshotObjListNum(vm->snapshots, NULL, 0) > 0) {
> +        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                       _("cannot create checkpoint while snapshot exists"));
> +        goto cleanup;
> +    }
> +
> +    cfg = virQEMUDriverGetConfig(driver);
> +
> +    if (virDomainCheckpointCreateXMLEnsureACL(domain->conn, vm->def, flags) < 0)
> +        goto cleanup;
> +
> +    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
> +        goto cleanup;
> +
> +    if (qemuProcessAutoDestroyActive(driver, vm)) {
> +        virReportError(VIR_ERR_OPERATION_INVALID,
> +                       "%s", _("domain is marked for auto destroy"));
> +        goto cleanup;
> +    }
> +
> +    if (!virDomainObjIsActive(vm)) {
> +        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                       _("cannot create checkpoint for inactive domain"));
> +        goto cleanup;
> +    }
> +
> +    if (!(def = virDomainCheckpointDefParseString(xmlDesc, caps, driver->xmlopt,
> +                                                  parse_flags)))
> +        goto cleanup;
> +    /* Unlike snapshots, the RNG schema already ensured a sane filename. */
> +
> +    /* We are going to modify the domain below. */
> +    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
> +        goto cleanup;
> +
> +    if (redefine) {
> +        if (virDomainCheckpointRedefinePrep(domain, vm, &def, &chk,
> +                                            driver->xmlopt,
> +                                            &update_current) < 0)
> +            goto endjob;
> +    } else if (qemuDomainCheckpointPrepare(driver, caps, vm, def) < 0) {
> +        goto endjob;
> +    }
> +
> +    if (!chk) {
> +        if (!(chk = virDomainCheckpointAssignDef(vm->checkpoints, def)))
> +            goto endjob;
> +
> +        def = NULL;
> +    }
> +
> +    other = virDomainCheckpointGetCurrent(vm->checkpoints);
> +    if (other) {
> +        if (!redefine &&
> +            VIR_STRDUP(chk->def->parent_name, other->def->name) < 0)
> +            goto endjob;
> +        if (update_current) {
> +            virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
> +            if (qemuDomainCheckpointWriteMetadata(vm, other,
> +                                                  driver->caps, driver->xmlopt,
> +                                                  cfg->checkpointDir) < 0)
> +                goto endjob;
> +        }
> +    }
> +
> +    /* actually do the checkpoint */
> +    if (redefine) {
> +        /* XXX Should we validate that the redefined checkpoint even
> +         * makes sense, such as checking that qemu-img recognizes the
> +         * checkpoint bitmap name in at least one of the domain's disks?  */
> +    } else {
> +        /* TODO: issue QMP transaction command */
> +    }


If we want to merge this now, is there something we should be doing in
these XXX/TODO branches ?  Is the code doing anything useful with both
of those if/else branches being no-ops ?


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|




More information about the libvir-list mailing list