[libvirt] [PATCH v2 6/9] backup: Introduce virDomainCheckpoint APIs

Peter Krempa pkrempa at redhat.com
Fri Oct 12 12:18:20 UTC 2018


On Fri, Oct 12, 2018 at 00:10:08 -0500, Eric Blake wrote:
> Introduce a bunch of new public APIs related to backup checkpoints.
> Checkpoints are modeled heavily after virDomainSnapshotPtr (both
> represent a point in time of the guest), although a snapshot exists
> with the intent of rolling back to that state, while a checkpoint
> exists to make it possible to create an incremental backup at a later
> time.
> 
> The full list of new API:
>         virDomainCheckpointCreateXML;
>         virDomainCheckpointCurrent;
>         virDomainCheckpointDelete;
>         virDomainCheckpointFree;
>         virDomainCheckpointGetConnect;
>         virDomainCheckpointGetDomain;
>         virDomainCheckpointGetParent;
>         virDomainCheckpointGetXMLDesc;
>         virDomainCheckpointHasMetadata;
>         virDomainCheckpointIsCurrent;
>         virDomainCheckpointListChildren;
>         virDomainCheckpointLookupByName;
>         virDomainCheckpointRef;
>         virDomainHasCurrentCheckpoint;
>         virDomainListCheckpoints;
>         virDomainCheckpointGetName;
> 
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
>  include/libvirt/libvirt-domain-checkpoint.h | 156 +++++
>  include/libvirt/libvirt.h                   |   5 +-
>  src/driver-hypervisor.h                     |  60 +-
>  docs/Makefile.am                            |   3 +
>  docs/apibuild.py                            |   2 +
>  docs/docs.html.in                           |   1 +
>  libvirt.spec.in                             |   1 +
>  mingw-libvirt.spec.in                       |   2 +
>  po/POTFILES                                 |   1 +
>  src/Makefile.am                             |   2 +
>  src/libvirt-domain-checkpoint.c             | 723 ++++++++++++++++++++
>  src/libvirt_public.syms                     |  20 +
>  12 files changed, 972 insertions(+), 4 deletions(-)
>  create mode 100644 include/libvirt/libvirt-domain-checkpoint.h
>  create mode 100644 src/libvirt-domain-checkpoint.c
> 
> diff --git a/include/libvirt/libvirt-domain-checkpoint.h b/include/libvirt/libvirt-domain-checkpoint.h
> new file mode 100644
> index 0000000000..cfca8f4b7f
> --- /dev/null
> +++ b/include/libvirt/libvirt-domain-checkpoint.h
> @@ -0,0 +1,156 @@
> +/*
> + * libvirt-domain-checkpoint.h
> + * Summary: APIs for management of domain checkpoints
> + * Description: Provides APIs for the management of domain checkpoints
> + * Author: Eric Blake <eblake at redhat.com>
> + *
> + * Copyright (C) 2006-2018 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library.  If not, see
> + * <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __VIR_LIBVIRT_DOMAIN_CHECKPOINT_H__
> +# define __VIR_LIBVIRT_DOMAIN_CHECKPOINT_H__
> +
> +# ifndef __VIR_LIBVIRT_H_INCLUDES__
> +#  error "Don't include this file directly, only use libvirt/libvirt.h"
> +# endif
> +
> +/**
> + * virDomainCheckpoint:
> + *
> + * A virDomainCheckpoint is a private structure representing a checkpoint of
> + * a domain.  A checkpoint is useful for tracking which portions of the
> + * domain disks have been altered since a point in time, but by itself does
> + * not allow reverting back to that point in time.
> + */
> +typedef struct _virDomainCheckpoint virDomainCheckpoint;
> +
> +/**
> + * virDomainCheckpointPtr:
> + *
> + * A virDomainCheckpointPtr is pointer to a virDomainCheckpoint
> + * private structure, and is the type used to reference a domain
> + * checkpoint in the API.
> + */
> +typedef virDomainCheckpoint *virDomainCheckpointPtr;
> +
> +const char *virDomainCheckpointGetName(virDomainCheckpointPtr checkpoint);
> +virDomainPtr virDomainCheckpointGetDomain(virDomainCheckpointPtr checkpoint);
> +virConnectPtr virDomainCheckpointGetConnect(virDomainCheckpointPtr checkpoint);
> +
> +typedef enum {
> +    VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE    = (1 << 0), /* Restore or alter
> +                                                            metadata */
> +    VIR_DOMAIN_CHECKPOINT_CREATE_CURRENT     = (1 << 1), /* With redefine, make
> +                                                            checkpoint current */
> +    VIR_DOMAIN_CHECKPOINT_CREATE_NO_METADATA = (1 << 2), /* Make checkpoint without
> +                                                            remembering it */

Is this worth adding? Will there be a way to start an incremental backup
without a previously existing libvirt checkpoint (thus having metadata)?


> +    /* TODO: VIR_DOMAIN_CHECKPOINT_CREATE_QUIESCE */
> +} virDomainCheckpointCreateFlags;
> +
> +/* Create a checkpoint using the current VM state. */
> +virDomainCheckpointPtr virDomainCheckpointCreateXML(virDomainPtr domain,
> +                                                    const char *xmlDesc,
> +                                                    unsigned int flags);
> +
> +typedef enum {
> +    VIR_DOMAIN_CHECKPOINT_XML_SECURE    = (1 << 0), /* Include sensitive data */
> +    VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN = (1 << 1), /* Suppress <domain>
> +                                                       subelement */
> +    VIR_DOMAIN_CHECKPOINT_XML_SIZE      = (1 << 2), /* Include dynamic
> +                                                       per-<disk> size */
> +} virDomainCheckpointXMLFlags;
> +
> +/* Dump the XML of a checkpoint */
> +char *virDomainCheckpointGetXMLDesc(virDomainCheckpointPtr checkpoint,
> +                                    unsigned int flags);
> +
> +/**
> + * virDomainCheckpointListFlags:
> + *
> + * Flags valid for virDomainListCheckpoints() and
> + * virDomainCheckpointListChildren().  Note that the interpretation of
> + * flag (1<<0) depends on which function it is passed to; but serves
> + * to toggle the per-call default of whether the listing is shallow or
> + * recursive.  Remaining bits come in groups; if all bits from a group
> + * are 0, then that group is not used to filter results.  */
> +typedef enum {
> +    VIR_DOMAIN_CHECKPOINT_LIST_ROOTS       = (1 << 0), /* Filter by checkpoints
> +                                                          with no parents, when
> +                                                          listing a domain */
> +    VIR_DOMAIN_CHECKPOINT_LIST_DESCENDANTS = (1 << 0), /* List all descendants,
> +                                                          not just children, when
> +                                                          listing a checkpoint */
> +
> +    VIR_DOMAIN_CHECKPOINT_LIST_LEAVES      = (1 << 1), /* Filter by checkpoints
> +                                                          with no children */
> +    VIR_DOMAIN_CHECKPOINT_LIST_NO_LEAVES   = (1 << 2), /* Filter by checkpoints
> +                                                          that have children */
> +
> +    VIR_DOMAIN_CHECKPOINT_LIST_METADATA    = (1 << 3), /* Filter by checkpoints
> +                                                          which have metadata */
> +    VIR_DOMAIN_CHECKPOINT_LIST_NO_METADATA = (1 << 4), /* Filter by checkpoints
> +                                                          with no metadata */
> +} virDomainCheckpointListFlags;
> +
> +/* Get all checkpoint objects for this domain */
> +int virDomainListCheckpoints(virDomainPtr domain,
> +                             virDomainCheckpointPtr **checkpoints,
> +                             unsigned int flags);
> +
> +/* Get all checkpoint object children for this checkpoint */
> +int virDomainCheckpointListChildren(virDomainCheckpointPtr checkpoint,
> +                                    virDomainCheckpointPtr **children,
> +                                    unsigned int flags);
> +
> +/* Get a handle to a named checkpoint */
> +virDomainCheckpointPtr virDomainCheckpointLookupByName(virDomainPtr domain,
> +                                                       const char *name,
> +                                                       unsigned int flags);
> +
> +/* Check whether a domain has a checkpoint which is currently used */
> +int virDomainHasCurrentCheckpoint(virDomainPtr domain, unsigned int flags);
> +
> +/* Get a handle to the current checkpoint */
> +virDomainCheckpointPtr virDomainCheckpointCurrent(virDomainPtr domain,
> +                                                  unsigned int flags);
> +
> +/* Get a handle to the parent checkpoint, if one exists */
> +virDomainCheckpointPtr virDomainCheckpointGetParent(virDomainCheckpointPtr checkpoint,
> +                                                    unsigned int flags);
> +
> +/* Determine if a checkpoint is the current checkpoint of its domain.  */
> +int virDomainCheckpointIsCurrent(virDomainCheckpointPtr checkpoint,
> +                                 unsigned int flags);
> +
> +/* Determine if checkpoint has metadata that would prevent domain deletion.  */
> +int virDomainCheckpointHasMetadata(virDomainCheckpointPtr checkpoint,
> +                                   unsigned int flags);
> +
> +/* Delete a checkpoint */
> +typedef enum {
> +    VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN      = (1 << 0), /* Also delete children */
> +    VIR_DOMAIN_CHECKPOINT_DELETE_METADATA_ONLY = (1 << 1), /* Delete just metadata */
> +    VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY = (1 << 2), /* Delete just children */
> +} virDomainCheckpointDeleteFlags;
> +
> +int virDomainCheckpointDelete(virDomainCheckpointPtr checkpoint,
> +                              unsigned int flags);
> +
> +int virDomainCheckpointRef(virDomainCheckpointPtr checkpoint);
> +int virDomainCheckpointFree(virDomainCheckpointPtr checkpoint);
> +
> +#endif /* __VIR_LIBVIRT_DOMAIN_CHECKPOINT_H__ */
> diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h
> index 26887a40e7..4e7da0afc4 100644
> --- a/include/libvirt/libvirt.h
> +++ b/include/libvirt/libvirt.h
> @@ -4,7 +4,7 @@
>   * Description: Provides the interfaces of the libvirt library to handle
>   *              virtualized domains
>   *
> - * Copyright (C) 2005-2006, 2010-2014 Red Hat, Inc.
> + * Copyright (C) 2005-2006, 2010-2018 Red Hat, Inc.
>   *
>   * This library is free software; you can redistribute it and/or
>   * modify it under the terms of the GNU Lesser General Public
> @@ -36,8 +36,7 @@ extern "C" {
>  # include <libvirt/libvirt-common.h>
>  # include <libvirt/libvirt-host.h>
>  # include <libvirt/libvirt-domain.h>
> -typedef struct _virDomainCheckpoint virDomainCheckpoint;
> -typedef virDomainCheckpoint *virDomainCheckpointPtr;

This should be part of the patch adding the data structure.

> +# include <libvirt/libvirt-domain-checkpoint.h>
>  # include <libvirt/libvirt-domain-snapshot.h>
>  # include <libvirt/libvirt-event.h>
>  # include <libvirt/libvirt-interface.h>


[...]

> diff --git a/src/libvirt-domain-checkpoint.c b/src/libvirt-domain-checkpoint.c
> new file mode 100644
> index 0000000000..8a7b5b3c56
> --- /dev/null
> +++ b/src/libvirt-domain-checkpoint.c
> @@ -0,0 +1,723 @@
> +/*
> + * libvirt-domain-checkpoint.c: entry points for virDomainCheckpointPtr APIs
> + *
> + * Copyright (C) 2006-2014, 2018 Red Hat, Inc.

For a new file?

> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library.  If not, see
> + * <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <config.h>
> +
> +#include "datatypes.h"
> +#include "virlog.h"
> +
> +VIR_LOG_INIT("libvirt.domain-checkpoint");
> +
> +#define VIR_FROM_THIS VIR_FROM_DOMAIN_CHECKPOINT
> +
> +/**
> + * virDomainCheckpointGetName:
> + * @checkpoint: a checkpoint object
> + *
> + * Get the public name for that checkpoint
> + *
> + * Returns a pointer to the name or NULL, the string need not be deallocated
> + * as its lifetime will be the same as the checkpoint object.
> + */
> +const char *
> +virDomainCheckpointGetName(virDomainCheckpointPtr checkpoint)
> +{
> +    VIR_DEBUG("checkpoint=%p", checkpoint);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, NULL);
> +
> +    return checkpoint->name;
> +}
> +
> +
> +/**
> + * virDomainCheckpointGetDomain:
> + * @checkpoint: a checkpoint object
> + *
> + * Provides the domain pointer associated with a checkpoint.  The
> + * reference counter on the domain is not increased by this
> + * call.
> + *
> + * Returns the domain or NULL.
> + */
> +virDomainPtr
> +virDomainCheckpointGetDomain(virDomainCheckpointPtr checkpoint)
> +{
> +    VIR_DEBUG("checkpoint=%p", checkpoint);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, NULL);
> +
> +    return checkpoint->domain;
> +}
> +
> +
> +/**
> + * virDomainCheckpointGetConnect:
> + * @checkpoint: a checkpoint object
> + *
> + * Provides the connection pointer associated with a checkpoint.  The
> + * reference counter on the connection is not increased by this
> + * call.
> + *
> + * Returns the connection or NULL.
> + */
> +virConnectPtr
> +virDomainCheckpointGetConnect(virDomainCheckpointPtr checkpoint)

This does not seem to be very useful. Users always can do a two step
lookup.

> +{
> +    VIR_DEBUG("checkpoint=%p", checkpoint);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, NULL);
> +
> +    return checkpoint->domain->conn;
> +}
> +
> +
> +/**
> + * virDomainCheckpointCreateXML:
> + * @domain: a domain object
> + * @xmlDesc: description of the checkpoint to create
> + * @flags: bitwise-OR of supported virDomainCheckpointCreateFlags
> + *
> + * Create a new checkpoint using @xmlDesc on a running @domain.
> + * Typically, it is more common to create a new checkpoint as part of
> + * kicking off a backup job with virDomainBackupBegin(); however, it
> + * is also possible to start a checkpoint without a backup.
> + *
> + * See <a href=formatcheckpoint.html#CheckpointAttributes">Checkpoint XML</a>
> + * for more details on @xmlDesc. In particular, some hypervisors may require
> + * particular disk formats, such as qcow2, in order to support this
> + * command; where @xmlDesc can be used to limit the checkpoint to a working
> + * subset of the domain's disks.
> + *
> + * If @flags includes VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE, then this
> + * is a request to reinstate checkpoint metadata that was previously
> + * discarded, rather than creating a new checkpoint.  When redefining
> + * checkpoint metadata, the current checkpoint will not be altered
> + * unless the VIR_DOMAIN_CHECKPOINT_CREATE_CURRENT flag is also
> + * present.  It is an error to request the
> + * VIR_DOMAIN_CHECKPOINT_CREATE_CURRENT flag without
> + * VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE.
> + *
> + * If @flags includes VIR_DOMAIN_CHECKPOINT_CREATE_NO_METADATA, then
> + * the domain's disk images are modified according to @xmlDesc, but
> + * then the just-created checkpoint has its metadata deleted.  This
> + * flag is incompatible with VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE.
> + *
> + * Returns an (opaque) new virDomainCheckpointPtr on success, or NULL
> + * on failure.
> + */
> +virDomainCheckpointPtr
> +virDomainCheckpointCreateXML(virDomainPtr domain,
> +                             const char *xmlDesc,
> +                             unsigned int flags)
> +{
> +    virConnectPtr conn;
> +
> +    VIR_DOMAIN_DEBUG(domain, "xmlDesc=%s, flags=0x%x", xmlDesc, flags);
> +
> +    virResetLastError();
> +
> +    virCheckDomainReturn(domain, NULL);
> +    conn = domain->conn;
> +
> +    virCheckNonNullArgGoto(xmlDesc, error);
> +    virCheckReadOnlyGoto(conn->flags, error);
> +
> +    VIR_REQUIRE_FLAG_GOTO(VIR_DOMAIN_CHECKPOINT_CREATE_CURRENT,
> +                          VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE,
> +                          error);
> +
> +    VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE,
> +                             VIR_DOMAIN_CHECKPOINT_CREATE_NO_METADATA,
> +                             error);
> +
> +    if (conn->driver->domainCheckpointCreateXML) {
> +        virDomainCheckpointPtr ret;
> +        ret = conn->driver->domainCheckpointCreateXML(domain, xmlDesc, flags);
> +        if (!ret)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return NULL;
> +}
> +
> +
> +/**
> + * virDomainCheckpointGetXMLDesc:
> + * @checkpoint: a domain checkpoint object
> + * @flags: bitwise-OR of supported virDomainCheckpointXMLFlags
> + *
> + * Provide an XML description of the domain checkpoint.
> + *
> + * No security-sensitive data will be included unless @flags contains
> + * VIR_DOMAIN_CHECKPOINT_XML_SECURE; this flag is rejected on read-only
> + * connections.

As discussed in other places, I'm not convinced that storing a domain is
needed with backups.

> + *
> + * Normally, the XML description includes an element giving a full
> + * description of the domain at the time the snapshot was created; to

Missed reference to snapshots.

> + * reduce parsing time, it will be suppressed when @flags contains
> + * VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN.
> + *
> + * By default, the XML description contains only static information that
> + * does not change over time. However, when @flags contains
> + * VIR_DOMAIN_CHECKPOINT_XML_SIZE, each <disk> listing adds an additional
> + * attribute that shows an estimate of the current size in bytes that
> + * have been dirtied between the time the checkpoint was created and the
> + * current point in time.
> + *
> + * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
> + *         the caller must free() the returned value.
> + */
> +char *
> +virDomainCheckpointGetXMLDesc(virDomainCheckpointPtr checkpoint,
> +                              unsigned int flags)
> +{
> +    virConnectPtr conn;
> +    VIR_DEBUG("checkpoint=%p, flags=0x%x", checkpoint, flags);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, NULL);
> +    conn = checkpoint->domain->conn;
> +
> +    if ((conn->flags & VIR_CONNECT_RO) &&
> +        (flags & VIR_DOMAIN_CHECKPOINT_XML_SECURE)) {
> +        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
> +                       _("virDomainCheckpointGetXMLDesc with secure flag"));
> +        goto error;
> +    }
> +
> +    if (conn->driver->domainCheckpointGetXMLDesc) {
> +        char *ret;
> +        ret = conn->driver->domainCheckpointGetXMLDesc(checkpoint, flags);
> +        if (!ret)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return NULL;
> +}
> +
> +
> +/**
> + * virDomainListCheckpoints:
> + * @domain: a domain object
> + * @checkpoints: pointer to variable to store the array containing checkpoint
> + *               objects, or NULL if the list is not required (just returns
> + *               number of checkpoints)
> + * @flags: bitwise-OR of supported virDomainCheckpoinListFlags

s/virDomainCheckpoinListFlags/virDomainCheckpointListFlags/

> + *
> + * Collect the list of domain checkpoints for the given domain, and allocate
> + * an array to store those objects.
> + *
> + * By default, this command covers all checkpoints; it is also possible to
> + * limit things to just checkpoints with no parents, when @flags includes
> + * VIR_DOMAIN_CHECKPOINT_LIST_ROOTS.  Additional filters are provided in
> + * groups, where each group contains bits that describe mutually exclusive
> + * attributes of a checkpoint, and where all bits within a group describe
> + * all possible checkpoints.  Some hypervisors might reject explicit bits
> + * from a group where the hypervisor cannot make a distinction.  For a
> + * group supported by a given hypervisor, the behavior when no bits of a
> + * group are set is identical to the behavior when all bits in that group
> + * are set.  When setting bits from more than one group, it is possible to
> + * select an impossible combination, in that case a hypervisor may return
> + * either 0 or an error.
> + *
> + * The first group of @flags is VIR_DOMAIN_CHECKPOINT_LIST_LEAVES and
> + * VIR_DOMAIN_CHECKPOINT_LIST_NO_LEAVES, to filter based on checkpoints that
> + * have no further children (a leaf checkpoint).
> + *
> + * The next group of @flags is VIR_DOMAIN_CHECKPOINT_LIST_METADATA and
> + * VIR_DOMAIN_CHECKPOINT_LIST_NO_METADATA, for filtering checkpoints based on
> + * whether they have metadata that would prevent the removal of the last
> + * reference to a domain.
> + *
> + * Returns the number of domain checkpoints found or -1 and sets @checkpoints
> + * to NULL in case of error.  On success, the array stored into @checkpoints
> + * is guaranteed to have an extra allocated element set to NULL but not
> + * included in the return count, to make iteration easier.  The caller is
> + * responsible for calling virDomainCheckpointFree() on each array element,
> + * then calling free() on @checkpoints.
> + */
> +int
> +virDomainListCheckpoints(virDomainPtr domain,
> +                         virDomainCheckpointPtr **checkpoints,
> +                         unsigned int flags)
> +{
> +    virConnectPtr conn;
> +
> +    VIR_DOMAIN_DEBUG(domain, "checkpoints=%p, flags=0x%x", checkpoints, flags);
> +
> +    virResetLastError();
> +
> +    if (checkpoints)
> +        *checkpoints = NULL;
> +
> +    virCheckDomainReturn(domain, -1);
> +    conn = domain->conn;
> +
> +    if (conn->driver->domainListCheckpoints) {
> +        int ret = conn->driver->domainListCheckpoints(domain, checkpoints,
> +                                                      flags);
> +        if (ret < 0)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return -1;
> +}

[...]

> +/**
> + * virDomainCheckpointIsCurrent:
> + * @checkpoint: a checkpoint object
> + * @flags: extra flags; not used yet, so callers should always pass 0
> + *
> + * Determine if the given checkpoint is the domain's current checkpoint.  See
> + * also virDomainHasCurrentCheckpoint().

Depending on whether 'current checkpoint' makes sense this might not be
needed.

> + *
> + * Returns 1 if current, 0 if not current, or -1 on error.
> + */
> +int
> +virDomainCheckpointIsCurrent(virDomainCheckpointPtr checkpoint,
> +                             unsigned int flags)
> +{
> +    virConnectPtr conn;
> +
> +    VIR_DEBUG("checkpoint=%p, flags=0x%x", checkpoint, flags);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, -1);
> +    conn = checkpoint->domain->conn;
> +
> +    if (conn->driver->domainCheckpointIsCurrent) {
> +        int ret;
> +        ret = conn->driver->domainCheckpointIsCurrent(checkpoint, flags);
> +        if (ret < 0)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return -1;
> +}
> +
> +
> +/**
> + * virDomainCheckpointHasMetadata:
> + * @checkpoint: a checkpoint object
> + * @flags: extra flags; not used yet, so callers should always pass 0
> + *
> + * Determine if the given checkpoint is associated with libvirt metadata
> + * that would prevent the deletion of the domain.

Given that we've never implemented metadata-less snapshots do we expect
this to happen with checkpoints?

> + * Returns 1 if the checkpoint has metadata, 0 if the checkpoint exists without
> + * help from libvirt, or -1 on error.
> + */
> +int
> +virDomainCheckpointHasMetadata(virDomainCheckpointPtr checkpoint,
> +                               unsigned int flags)
> +{
> +    virConnectPtr conn;
> +
> +    VIR_DEBUG("checkpoint=%p, flags=0x%x", checkpoint, flags);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, -1);
> +    conn = checkpoint->domain->conn;
> +
> +    if (conn->driver->domainCheckpointHasMetadata) {
> +        int ret;
> +        ret = conn->driver->domainCheckpointHasMetadata(checkpoint, flags);
> +        if (ret < 0)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return -1;
> +}
> +
> +
> +/**
> + * virDomainCheckpointDelete:
> + * @checkpoint: the checkpoint to remove
> + * @flags: not used yet, pass 0
> + * @flags: bitwise-OR of supported virDomainCheckpointDeleteFlags

@flags present twice

> + *
> + * Removes a checkpoint from the domain.
> + *
> + * When removing a checkpoint, the record of which portions of the
> + * disk were dirtied after the checkpoint will be merged into the
> + * record tracked by the parent checkpoint, if any.

So as a high-level question, since from the APIs added here is clear
that we expect tree-like topologies of checkpoints. Does merging of the
data _into_ the parent invalidate any other children?

This is a big problem we'll be facing when doing external snapshot
reversion.

> Likewise, if the
> + * checkpoint being deleted was the current checkpoint, the parent
> + * checkpoint becomes the new current checkpoint.
> + *
> + * If @flags includes VIR_DOMAIN_CHECKPOINT_DELETE_METADATA_ONLY, then
> + * any checkpoint metadata tracked by libvirt is removed while keeping
> + * the checkpoint contents intact; if a hypervisor does not require
> + * any libvirt metadata to track checkpoints, then this flag is
> + * silently ignored.
> + *
> + * Returns 0 on success, -1 on error.
> + */
> +int
> +virDomainCheckpointDelete(virDomainCheckpointPtr checkpoint,
> +                          unsigned int flags)
> +{
> +    virConnectPtr conn;
> +
> +    VIR_DEBUG("checkpoint=%p, flags=0x%x", checkpoint, flags);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, -1);
> +    conn = checkpoint->domain->conn;
> +
> +    virCheckReadOnlyGoto(conn->flags, error);
> +
> +    VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN,
> +                             VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY,
> +                             error);
> +
> +    if (conn->driver->domainCheckpointDelete) {
> +        int ret = conn->driver->domainCheckpointDelete(checkpoint, flags);
> +        if (ret < 0)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return -1;
> +}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20181012/0c83f794/attachment-0001.sig>


More information about the libvir-list mailing list