[libvirt] [PATCH v4 07/20] backup: Introduce virDomainCheckpoint APIs

John Ferlan jferlan at redhat.com
Mon Feb 11 21:19:37 UTC 2019



On 2/6/19 2:18 PM, 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 | 155 +++++
>  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, 971 insertions(+), 4 deletions(-)
>  create mode 100644 include/libvirt/libvirt-domain-checkpoint.h
>  create mode 100644 src/libvirt-domain-checkpoint.c
> 

After reading and commenting further I came back here and started
wondering if we should just name this 'libvirt-domain-backup' since
checkpoint is part of backup... Then of course adjust various comments
accordingly to indicate checkpoint and backup.

Of course there's also something to be said for separating out the
domain-backup API's into their own module too.

So while you may see comments later about splitting just keep this
secondary thought in mind.

> diff --git a/include/libvirt/libvirt-domain-checkpoint.h b/include/libvirt/libvirt-domain-checkpoint.h
> new file mode 100644
> index 0000000000..9006a46c6e
> --- /dev/null
> +++ b/include/libvirt/libvirt-domain-checkpoint.h
> @@ -0,0 +1,155 @@
> +/*
> + * libvirt-domain-checkpoint.h
> + * Summary: APIs for management of domain checkpoints
> + * Description: Provides APIs for the management of domain checkpoints
> + *
> + * Copyright (C) 2006-2019 Red Hat, Inc.

New file right, so should this just be 2019? There's varying opinions to
follow on this...

> + *
> + * 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 LIBVIRT_DOMAIN_CHECKPOINT_H
> +# define 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 */
> +    /* TODO: VIR_DOMAIN_CHECKPOINT_CREATE_QUIESCE */

Need to remove the TODO or add the flag of course...

> +} 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 /* LIBVIRT_DOMAIN_CHECKPOINT_H */
> diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h
> index b7238bd96e..5db12783be 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
> @@ -34,8 +34,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;
> +# 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/driver-hypervisor.h b/src/driver-hypervisor.h
> index 5315e33dde..14db8e49f3 100644
> --- a/src/driver-hypervisor.h
> +++ b/src/driver-hypervisor.h
> @@ -1,7 +1,7 @@
>  /*
>   * driver-hypervisor.h: entry points for hypervisor drivers
>   *
> - * Copyright (C) 2006-2015 Red Hat, Inc.
> + * 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
> @@ -1328,6 +1328,53 @@ typedef int
>                                          int *nparams,
>                                          unsigned int flags);
> 
> +typedef virDomainCheckpointPtr
> +(*virDrvDomainCheckpointCreateXML)(virDomainPtr domain,
> +                                   const char *xmlDesc,
> +                                   unsigned int flags);
> +
> +typedef char *
> +(*virDrvDomainCheckpointGetXMLDesc)(virDomainCheckpointPtr checkpoint,
> +                                    unsigned int flags);
> +
> +typedef int
> +(*virDrvDomainListCheckpoints)(virDomainPtr domain,
> +                               virDomainCheckpointPtr **checkpoints,
> +                               unsigned int flags);
> +
> +typedef int
> +(*virDrvDomainCheckpointListChildren)(virDomainCheckpointPtr checkpoint,
> +                                      virDomainCheckpointPtr **children,
> +                                      unsigned int flags);
> +
> +typedef virDomainCheckpointPtr
> +(*virDrvDomainCheckpointLookupByName)(virDomainPtr domain,
> +                                      const char *name,
> +                                      unsigned int flags);
> +
> +typedef int
> +(*virDrvDomainHasCurrentCheckpoint)(virDomainPtr domain,
> +                                    unsigned int flags);
> +
> +typedef virDomainCheckpointPtr
> +(*virDrvDomainCheckpointGetParent)(virDomainCheckpointPtr checkpoint,
> +                                   unsigned int flags);
> +
> +typedef virDomainCheckpointPtr
> +(*virDrvDomainCheckpointCurrent)(virDomainPtr domain,
> +                                 unsigned int flags);
> +
> +typedef int
> +(*virDrvDomainCheckpointIsCurrent)(virDomainCheckpointPtr checkpoint,
> +                                   unsigned int flags);
> +
> +typedef int
> +(*virDrvDomainCheckpointHasMetadata)(virDomainCheckpointPtr checkpoint,
> +                                     unsigned int flags);
> +
> +typedef int
> +(*virDrvDomainCheckpointDelete)(virDomainCheckpointPtr checkpoint,
> +                                unsigned int flags);
> 
>  typedef struct _virHypervisorDriver virHypervisorDriver;
>  typedef virHypervisorDriver *virHypervisorDriverPtr;
> @@ -1580,6 +1627,17 @@ struct _virHypervisorDriver {
>      virDrvConnectBaselineHypervisorCPU connectBaselineHypervisorCPU;
>      virDrvNodeGetSEVInfo nodeGetSEVInfo;
>      virDrvDomainGetLaunchSecurityInfo domainGetLaunchSecurityInfo;
> +    virDrvDomainCheckpointCreateXML domainCheckpointCreateXML;
> +    virDrvDomainCheckpointGetXMLDesc domainCheckpointGetXMLDesc;
> +    virDrvDomainListCheckpoints domainListCheckpoints;
> +    virDrvDomainCheckpointListChildren domainCheckpointListChildren;
> +    virDrvDomainCheckpointLookupByName domainCheckpointLookupByName;
> +    virDrvDomainHasCurrentCheckpoint domainHasCurrentCheckpoint;
> +    virDrvDomainCheckpointGetParent domainCheckpointGetParent;
> +    virDrvDomainCheckpointCurrent domainCheckpointCurrent;
> +    virDrvDomainCheckpointIsCurrent domainCheckpointIsCurrent;
> +    virDrvDomainCheckpointHasMetadata domainCheckpointHasMetadata;
> +    virDrvDomainCheckpointDelete domainCheckpointDelete;
>  };

Since we're adding new I think we should be consistent w/ naming

virDrvDomainCheckpoint* and domainCheckpoint*

DomainListCheckpoints and DomainHasCurrent break the mold, so to speak.

> 
> 
> diff --git a/docs/Makefile.am b/docs/Makefile.am
> index bd7bc1a431..88c1e83275 100644
> --- a/docs/Makefile.am
> +++ b/docs/Makefile.am
> @@ -25,6 +25,7 @@ apihtml = \
>  apihtml_generated = \
>    html/libvirt-libvirt-common.html \
>    html/libvirt-libvirt-domain.html \
> +  html/libvirt-libvirt-domain-checkpoint.html \
>    html/libvirt-libvirt-domain-snapshot.html \
>    html/libvirt-libvirt-event.html \
>    html/libvirt-libvirt-host.html \
> @@ -316,6 +317,7 @@ $(python_generated_files): $(APIBUILD_STAMP)
>  $(APIBUILD_STAMP): $(srcdir)/apibuild.py \
>  		$(top_srcdir)/include/libvirt/libvirt.h \
>  		$(top_srcdir)/include/libvirt/libvirt-common.h.in \
> +		$(top_srcdir)/include/libvirt/libvirt-domain-checkpoint.h \
>  		$(top_srcdir)/include/libvirt/libvirt-domain-snapshot.h \
>  		$(top_srcdir)/include/libvirt/libvirt-domain.h \
>  		$(top_srcdir)/include/libvirt/libvirt-event.h \
> @@ -332,6 +334,7 @@ $(APIBUILD_STAMP): $(srcdir)/apibuild.py \
>  		$(top_srcdir)/include/libvirt/libvirt-admin.h \
>  		$(top_srcdir)/include/libvirt/virterror.h \
>  		$(top_srcdir)/src/libvirt.c \
> +		$(top_srcdir)/src/libvirt-domain-checkpoint.c \
>  		$(top_srcdir)/src/libvirt-domain-snapshot.c \
>  		$(top_srcdir)/src/libvirt-domain.c \
>  		$(top_srcdir)/src/libvirt-host.c \
> diff --git a/docs/apibuild.py b/docs/apibuild.py
> index 9e04871220..dbdc1c95af 100755
> --- a/docs/apibuild.py
> +++ b/docs/apibuild.py
> @@ -26,6 +26,7 @@ debugsym = None
>  included_files = {
>    "libvirt-common.h": "header with general libvirt API definitions",
>    "libvirt-domain.h": "header with general libvirt API definitions",
> +  "libvirt-domain-checkpoint.h": "header with general libvirt API definitions",
>    "libvirt-domain-snapshot.h": "header with general libvirt API definitions",
>    "libvirt-event.h": "header with general libvirt API definitions",
>    "libvirt-host.h": "header with general libvirt API definitions",
> @@ -39,6 +40,7 @@ included_files = {
>    "virterror.h": "header with error specific API definitions",
>    "libvirt.c": "Main interfaces for the libvirt library",
>    "libvirt-domain.c": "Domain interfaces for the libvirt library",
> +  "libvirt-domain-checkpoint.c": "Domain checkpoint interfaces for the libvirt library",
>    "libvirt-domain-snapshot.c": "Domain snapshot interfaces for the libvirt library",
>    "libvirt-host.c": "Host interfaces for the libvirt library",
>    "libvirt-interface.c": "Interface interfaces for the libvirt library",
> diff --git a/docs/docs.html.in b/docs/docs.html.in
> index 4914e7dbed..596bc1613d 100644
> --- a/docs/docs.html.in
> +++ b/docs/docs.html.in
> @@ -97,6 +97,7 @@
>          <dd>Reference manual for the C public API, split in
>            <a href="html/libvirt-libvirt-common.html">common</a>,
>            <a href="html/libvirt-libvirt-domain.html">domain</a>,
> +          <a href="html/libvirt-libvirt-domain-checkpoint.html">domain checkpoint</a>,
>            <a href="html/libvirt-libvirt-domain-snapshot.html">domain snapshot</a>,
>            <a href="html/libvirt-virterror.html">error</a>,
>            <a href="html/libvirt-libvirt-event.html">event</a>,
> diff --git a/libvirt.spec.in b/libvirt.spec.in
> index 2e9213510d..08c8a896e0 100644
> --- a/libvirt.spec.in
> +++ b/libvirt.spec.in
> @@ -1873,6 +1873,7 @@ exit 0
>  %{_includedir}/libvirt/libvirt-admin.h
>  %{_includedir}/libvirt/libvirt-common.h
>  %{_includedir}/libvirt/libvirt-domain.h
> +%{_includedir}/libvirt/libvirt-domain-checkpoint.h
>  %{_includedir}/libvirt/libvirt-domain-snapshot.h
>  %{_includedir}/libvirt/libvirt-event.h
>  %{_includedir}/libvirt/libvirt-host.h
> diff --git a/mingw-libvirt.spec.in b/mingw-libvirt.spec.in
> index a7b697d7bd..be735bce48 100644
> --- a/mingw-libvirt.spec.in
> +++ b/mingw-libvirt.spec.in
> @@ -271,6 +271,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
>  %{mingw32_includedir}/libvirt/libvirt.h
>  %{mingw32_includedir}/libvirt/libvirt-common.h
>  %{mingw32_includedir}/libvirt/libvirt-domain.h
> +%{mingw32_includedir}/libvirt/libvirt-domain-checkpoint.h
>  %{mingw32_includedir}/libvirt/libvirt-domain-snapshot.h
>  %{mingw32_includedir}/libvirt/libvirt-event.h
>  %{mingw32_includedir}/libvirt/libvirt-host.h
> @@ -360,6 +361,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
>  %{mingw64_includedir}/libvirt/libvirt.h
>  %{mingw64_includedir}/libvirt/libvirt-common.h
>  %{mingw64_includedir}/libvirt/libvirt-domain.h
> +%{mingw64_includedir}/libvirt/libvirt-domain-checkpoint.h
>  %{mingw64_includedir}/libvirt/libvirt-domain-snapshot.h
>  %{mingw64_includedir}/libvirt/libvirt-event.h
>  %{mingw64_includedir}/libvirt/libvirt-host.h
> diff --git a/po/POTFILES b/po/POTFILES
> index 9dd4ee7d99..88af551664 100644
> --- a/po/POTFILES
> +++ b/po/POTFILES
> @@ -69,6 +69,7 @@ src/interface/interface_backend_netcf.c
>  src/interface/interface_backend_udev.c
>  src/internal.h
>  src/libvirt-admin.c
> +src/libvirt-domain-checkpoint.c
>  src/libvirt-domain-snapshot.c
>  src/libvirt-domain.c
>  src/libvirt-host.c
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 8c8dfe3dcf..c871e12d8f 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -176,6 +176,7 @@ DRIVER_SOURCES += \
>  		$(DATATYPES_SOURCES) \
>  		libvirt.c libvirt_internal.h \
>  		libvirt-domain.c \
> +		libvirt-domain-checkpoint.c \
>  		libvirt-domain-snapshot.c \
>  		libvirt-host.c \
>  		libvirt-interface.c \
> @@ -727,6 +728,7 @@ libvirt_setuid_rpc_client_la_SOURCES = \
>  		datatypes.c \
>  		libvirt.c \
>  		libvirt-domain.c \
> +		libvirt-domain-checkpoint.c \
>  		libvirt-domain-snapshot.c \
>  		libvirt-host.c \
>  		libvirt-interface.c \
> 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.
> + *
> + * 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)

I see a copy of virDomainSnapshotGetConnect - part of me wonders why
since this isn't the Checkpoint's @conn, why shouldn't the API writer
use virDomainGetConnect once they have the @domain object.  No big deal,
just a while I'm reading type comment...

> +{
> +    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.

NIT, but no big deal... Patch order has virDomainBackupBegin in the next
patch...

> + *
> + * 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

s/just-created/just created/

> + * flag is incompatible with VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE.
> + *
> + * Returns an (opaque) new virDomainCheckpointPtr on success, or NULL

s/, or/ or/

> + * 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.
> + *
> + * Normally, the XML description includes an element giving a full
> + * description of the domain at the time the snapshot was created; to
> + * 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.

s/, or/ or/

> + *         the caller must free() the returned value.

s/the/The/

the indention is probably unnecessary too.

> + */
> +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

s/, or/ or/

> + *               number of checkpoints)
> + * @flags: bitwise-OR of supported virDomainCheckpoinListFlags
> + *
> + * Collect the list of domain checkpoints for the given domain, and allocate

s/, and/ and/

> + * an array to store those objects.
> + *
> + * By default, this command covers all checkpoints; it is also possible to

s/; it/. It/

> + * 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

s/, and/ and/



> + * 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.

Not clear what a group is within this context and how one defines that,
uses that, and of course the CYA condition of impossible combination ;-).

Of course groups start to be clearer the following description... Not
that I completely understand them. Seems to add levels of complexity.

> + *
> + * 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)

Why not virDomainCheckpointListAll (beyond the difference w/ Snapshots)

> +{
> +    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;
> +}
> +
> +
> +/**
> + * virDomainCheckpointListChildren:
> + * @checkpoint: a domain checkpoint object
> + * @children: pointer to variable to store the array containing checkpoint
> + *            objects, or NULL if the list is not required (just returns

s/, or/ or/

> + *            number of checkpoints)
> + * @flags: bitwise-OR of supported virDomainCheckpointListFlags
> + *
> + * Collect the list of domain checkpoints that are children of the given
> + * checkpoint, and allocate an array to store those objects.

s/, and/ and/

> + *
> + * By default, this command covers only direct children; it is also possible
> + * to expand things to cover all descendants, when @flags includes
> + * VIR_DOMAIN_CHECKPOINT_LIST_DESCENDANTS.  Also, some filters are provided in
> + * groups, where each group contains bits that describe mutually exclusive
> + * attributes of a snapshot, and where all bits within a group describe

s/, and/ and/

> + * all possible snapshots.  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.

Can we just say similar to ListAll - that way we don't need to update both.

If these really are similar API's then perhaps they could be combined
such that if @checkpoint == NULL, then we're listing from root;
otherwise, we're listing from @checkpoint. Assuming checkpoint == NULL
is ListAll right?

Could be easier to not have ListAll and ListChildren...

> + *
> + * 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 @children to
> + * NULL in case of error.  On success, the array stored into @children 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 @children.
> + */
> +int
> +virDomainCheckpointListChildren(virDomainCheckpointPtr checkpoint,
> +                                virDomainCheckpointPtr **children,
> +                                unsigned int flags)
> +{
> +    virConnectPtr conn;
> +
> +    VIR_DEBUG("checkpoint=%p, children=%p, flags=0x%x",
> +              checkpoint, children, flags);
> +
> +    virResetLastError();
> +
> +    if (children)
> +        *children = NULL;
> +
> +    virCheckDomainCheckpointReturn(checkpoint, -1);
> +    conn = checkpoint->domain->conn;
> +
> +    if (conn->driver->domainCheckpointListChildren) {
> +        int ret = conn->driver->domainCheckpointListChildren(checkpoint,
> +                                                             children, flags);
> +        if (ret < 0)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return -1;
> +}
> +
> +
> +/**
> + * virDomainCheckpointLookupByName:
> + * @domain: a domain object
> + * @name: name for the domain checkpoint
> + * @flags: extra flags; not used yet, so callers should always pass 0
> + *
> + * Try to lookup a domain checkpoint based on its name.
> + *
> + * Returns a domain checkpoint object or NULL in case of failure.  If the
> + * domain checkpoint cannot be found, then the VIR_ERR_NO_DOMAIN_CHECKPOINT
> + * error is raised.
> + */
> +virDomainCheckpointPtr
> +virDomainCheckpointLookupByName(virDomainPtr domain,
> +                                const char *name,
> +                                unsigned int flags)
> +{
> +    virConnectPtr conn;
> +
> +    VIR_DOMAIN_DEBUG(domain, "name=%s, flags=0x%x", name, flags);
> +
> +    virResetLastError();
> +
> +    virCheckDomainReturn(domain, NULL);
> +    conn = domain->conn;
> +
> +    virCheckNonNullArgGoto(name, error);
> +
> +    if (conn->driver->domainCheckpointLookupByName) {
> +        virDomainCheckpointPtr dom;
> +        dom = conn->driver->domainCheckpointLookupByName(domain, name, flags);
> +        if (!dom)
> +            goto error;
> +        return dom;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return NULL;
> +}
> +
> +
> +/**
> + * virDomainHasCurrentCheckpoint:
> + * @domain: pointer to the domain object
> + * @flags: extra flags; not used yet, so callers should always pass 0
> + *
> + * Determine if the domain has a current checkpoint.
> + *
> + * Returns 1 if such checkpoint exists, 0 if it doesn't, -1 on error.
> + */
> +int
> +virDomainHasCurrentCheckpoint(virDomainPtr domain, unsigned int flags)

Use one line for each argument.

Why not virDomainCheckpointHasCurrent to keep the virDomainCheckpoint*
namespace consistent?

> +{
> +    virConnectPtr conn;
> +
> +    VIR_DOMAIN_DEBUG(domain, "flags=0x%x", flags);
> +
> +    virResetLastError();
> +
> +    virCheckDomainReturn(domain, -1);
> +    conn = domain->conn;
> +
> +    if (conn->driver->domainHasCurrentCheckpoint) {
> +        int ret = conn->driver->domainHasCurrentCheckpoint(domain, flags);
> +        if (ret < 0)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return -1;
> +}
> +
> +
> +/**
> + * virDomainCheckpointCurrent:
> + * @domain: a domain object
> + * @flags: extra flags; not used yet, so callers should always pass 0
> + *
> + * Get the current checkpoint for a domain, if any.
> + *
> + * virDomainCheckpointFree should be used to free the resources after the
> + * checkpoint object is no longer needed.
> + *
> + * Returns a domain checkpoint object or NULL in case of failure.  If the
> + * current domain checkpoint cannot be found, then the
> + * VIR_ERR_NO_DOMAIN_CHECKPOINT error is raised.
> + */
> +virDomainCheckpointPtr
> +virDomainCheckpointCurrent(virDomainPtr domain,
> +                           unsigned int flags)

Why isn't this virDomainCheckpointGetCurrent for consistency?

> +{
> +    virConnectPtr conn;
> +
> +    VIR_DOMAIN_DEBUG(domain, "flags=0x%x", flags);
> +
> +    virResetLastError();
> +
> +    virCheckDomainReturn(domain, NULL);
> +    conn = domain->conn;
> +
> +    if (conn->driver->domainCheckpointCurrent) {
> +        virDomainCheckpointPtr snap;
> +        snap = conn->driver->domainCheckpointCurrent(domain, flags);
> +        if (!snap)
> +            goto error;
> +        return snap;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return NULL;
> +}
> +
> +
> +/**
> + * virDomainCheckpointGetParent:
> + * @checkpoint: a checkpoint object
> + * @flags: extra flags; not used yet, so callers should always pass 0
> + *
> + * Get the parent checkpoint for @checkpoint, if any.
> + *
> + * virDomainCheckpointFree should be used to free the resources after the
> + * checkpoint object is no longer needed.
> + *
> + * Returns a domain checkpoint object or NULL in case of failure.  If the
> + * given checkpoint is a root (no parent), then the VIR_ERR_NO_DOMAIN_CHECKPOINT
> + * error is raised.
> + */
> +virDomainCheckpointPtr
> +virDomainCheckpointGetParent(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->driver->domainCheckpointGetParent) {
> +        virDomainCheckpointPtr snap;
> +        snap = conn->driver->domainCheckpointGetParent(checkpoint, flags);
> +        if (!snap)
> +            goto error;
> +        return snap;
> +    }
> +
> +    virReportUnsupportedError();
> + error:
> +    virDispatchError(conn);
> +    return NULL;
> +}
> +
> +
> +/**
> + * 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().
> + *
> + * 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.
> + *
> + * 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

Remove this one^^

> + * @flags: bitwise-OR of supported virDomainCheckpointDeleteFlags
> + *
> + * 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.  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,

Two more flags that need to be documented above


John

> +                             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;
> +}
> +
> +
> +/**
> + * virDomainCheckpointRef:
> + * @checkpoint: the checkpoint to hold a reference on
> + *
> + * Increment the reference count on the checkpoint. For each
> + * additional call to this method, there shall be a corresponding
> + * call to virDomainCheckpointFree to release the reference count, once
> + * the caller no longer needs the reference to this object.
> + *
> + * This method is typically useful for applications where multiple
> + * threads are using a connection, and it is required that the
> + * connection and domain remain open until all threads have finished
> + * using the checkpoint. ie, each new thread using a checkpoint would
> + * increment the reference count.
> + *
> + * Returns 0 in case of success and -1 in case of failure.
> + */
> +int
> +virDomainCheckpointRef(virDomainCheckpointPtr checkpoint)
> +{
> +    VIR_DEBUG("checkpoint=%p, refs=%d", checkpoint,
> +              checkpoint ? checkpoint->parent.u.s.refs : 0);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, -1);
> +
> +    virObjectRef(checkpoint);
> +    return 0;
> +}
> +
> +
> +/**
> + * virDomainCheckpointFree:
> + * @checkpoint: a domain checkpoint object
> + *
> + * Free the domain checkpoint object.  The checkpoint itself is not modified.
> + * The data structure is freed and should not be used thereafter.
> + *
> + * Returns 0 in case of success and -1 in case of failure.
> + */
> +int
> +virDomainCheckpointFree(virDomainCheckpointPtr checkpoint)
> +{
> +    VIR_DEBUG("checkpoint=%p", checkpoint);
> +
> +    virResetLastError();
> +
> +    virCheckDomainCheckpointReturn(checkpoint, -1);
> +
> +    virObjectUnref(checkpoint);
> +    return 0;
> +}
> diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
> index 042b4df043..1b18402e5e 100644
> --- a/src/libvirt_public.syms
> +++ b/src/libvirt_public.syms
> @@ -814,4 +814,24 @@ LIBVIRT_4.10.0 {
>          virDomainSetIOThreadParams;
>  } LIBVIRT_4.5.0;
> 
> +LIBVIRT_5.1.0 {
> +    global:
> +        virDomainCheckpointCreateXML;
> +        virDomainCheckpointCurrent;
> +        virDomainCheckpointDelete;
> +        virDomainCheckpointFree;
> +        virDomainCheckpointGetConnect;
> +        virDomainCheckpointGetDomain;
> +        virDomainCheckpointGetName;
> +        virDomainCheckpointGetParent;
> +        virDomainCheckpointGetXMLDesc;
> +        virDomainCheckpointHasMetadata;
> +        virDomainCheckpointIsCurrent;
> +        virDomainCheckpointListChildren;
> +        virDomainCheckpointLookupByName;
> +        virDomainCheckpointRef;
> +        virDomainHasCurrentCheckpoint;
> +        virDomainListCheckpoints;
> +} LIBVIRT_4.10.0;
> +
>  # .... define new API here using predicted next version number ....
> 




More information about the libvir-list mailing list