[libvirt] [PATCHv2 08/13] list: add virDomainListAllSnapshots API

Eric Blake eblake at redhat.com
Fri Jun 15 04:18:33 UTC 2012


There was an inherent race between virDomainSnapshotNum() and
virDomainSnapshotListNames(), where an additional snapshot could
be created in the meantime, or where a snapshot could be deleted
before converting the name back to a virDomainSnapshotPtr.  It
was also an awkward name: the function operates on domains, not
domain snapshots.  virDomainSnapshotListChildrenNames() suffered
from the same inherent race, although its naming was nicer.

This patch makes things nicer by grabbing a snapshot list
atomically, in the format most useful to the user.

* include/libvirt/libvirt.h.in (virDomainListAllSnapshots)
(virDomainSnapshotListAllChildren): New declarations.
* src/libvirt.c (virDomainListAllSnapshots)
(virDomainSnapshotListAllChildren): New functions.
* src/libvirt_public.syms (LIBVIRT_0.9.13): Export them.
* src/driver.h (virDrvDomainListAllSnapshots)
(virDrvDomainSnapshotListAllChildren): New callbacks.
* python/generator.py (skip_function): Prepare for later
hand-written versions.
---

v2: guarantee NULL on error

 include/libvirt/libvirt.h.in |   13 +++-
 python/generator.py          |    2 +
 src/driver.h                 |   12 ++++
 src/libvirt.c                |  149 ++++++++++++++++++++++++++++++++++++++++++
 src/libvirt_public.syms      |    2 +
 5 files changed, 177 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index e1e8cbb..04244bc 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3389,7 +3389,8 @@ char *virDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
  *
  * Flags valid for virDomainSnapshotNum(),
  * virDomainSnapshotListNames(), virDomainSnapshotNumChildren(), and
- * virDomainSnapshotListChildrenNames().  Note that the interpretation
+ * virDomainSnapshotListChildrenNames(), virDomainListAllSnapshots(),
+ * and virDomainSnapshotListAllChildren().  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
@@ -3422,6 +3423,11 @@ int virDomainSnapshotNum(virDomainPtr domain, unsigned int flags);
 int virDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
                                unsigned int flags);

+/* Get all snapshot objects for this domain */
+int virDomainListAllSnapshots(virDomainPtr domain,
+                              virDomainSnapshotPtr **snaps,
+                              unsigned int flags);
+
 /* Return the number of child snapshots for this snapshot */
 int virDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
                                  unsigned int flags);
@@ -3431,6 +3437,11 @@ int virDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
                                        char **names, int nameslen,
                                        unsigned int flags);

+/* Get all snapshot object children for this snapshot */
+int virDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
+                                     virDomainSnapshotPtr **snaps,
+                                     unsigned int flags);
+
 /* Get a handle to a named snapshot */
 virDomainSnapshotPtr virDomainSnapshotLookupByName(virDomainPtr domain,
                                                    const char *name,
diff --git a/python/generator.py b/python/generator.py
index 0b6ac7c..2dada6e 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -454,6 +454,8 @@ skip_function = (
     'virSaveLastError', # We have our own python error wrapper
     'virFreeError', # Only needed if we use virSaveLastError
     'virConnectListAllDomains', #overridden in virConnect.py
+    'virDomainListAllSnapshots', # overridden in virDomain.py
+    'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py

     'virStreamRecvAll', # Pure python libvirt-override-virStream.py
     'virStreamSendAll', # Pure python libvirt-override-virStream.py
diff --git a/src/driver.h b/src/driver.h
index bbeca06..4a4b60f 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -628,6 +628,11 @@ typedef int
                                      unsigned int flags);

 typedef int
+    (*virDrvDomainListAllSnapshots)(virDomainPtr domain,
+                                    virDomainSnapshotPtr **snaps,
+                                    unsigned int flags);
+
+typedef int
     (*virDrvDomainSnapshotNumChildren)(virDomainSnapshotPtr snapshot,
                                        unsigned int flags);

@@ -637,6 +642,11 @@ typedef int
                                              int nameslen,
                                              unsigned int flags);

+typedef int
+    (*virDrvDomainSnapshotListAllChildren)(virDomainSnapshotPtr snapshot,
+                                           virDomainSnapshotPtr **snaps,
+                                           unsigned int flags);
+
 typedef virDomainSnapshotPtr
     (*virDrvDomainSnapshotLookupByName)(virDomainPtr domain,
                                         const char *name,
@@ -993,8 +1003,10 @@ struct _virDriver {
     virDrvDomainSnapshotGetXMLDesc domainSnapshotGetXMLDesc;
     virDrvDomainSnapshotNum domainSnapshotNum;
     virDrvDomainSnapshotListNames domainSnapshotListNames;
+    virDrvDomainListAllSnapshots domainListAllSnapshots;
     virDrvDomainSnapshotNumChildren domainSnapshotNumChildren;
     virDrvDomainSnapshotListChildrenNames domainSnapshotListChildrenNames;
+    virDrvDomainSnapshotListAllChildren domainSnapshotListAllChildren;
     virDrvDomainSnapshotLookupByName domainSnapshotLookupByName;
     virDrvDomainHasCurrentSnapshot domainHasCurrentSnapshot;
     virDrvDomainSnapshotGetParent domainSnapshotGetParent;
diff --git a/src/libvirt.c b/src/libvirt.c
index 1eb7bd0..c44bf0a 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -17192,6 +17192,79 @@ error:
 }

 /**
+ * virDomainListAllSnapshots:
+ * @domain: a domain object
+ * @snaps: pointer to variable to store the array containing snapshot objects,
+ *         or NULL if the list is not required (just returns number of
+ *         snapshots)
+ * @flags: bitwise-OR of supported virDomainSnapshotListFlags
+ *
+ * Collect the list of domain snapshots for the given domain, and allocate
+ * an array to store those objects.  Caller is responsible for calling
+ * virDomainSnapshotFree() on each member of the array, then free() on the
+ * array itself.
+ *
+ * By default, this command covers all snapshots; it is also possible to
+ * limit things to just snapshots with no parents, when @flags includes
+ * VIR_DOMAIN_SNAPSHOT_LIST_ROOTS.  Additional 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
+ * 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.
+ *
+ * The first group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_LEAVES and
+ * VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, to filter based on snapshots that
+ * have no further children (a leaf snapshot).
+ *
+ * The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_METADATA and
+ * VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, for filtering snapshots based on
+ * whether they have metadata that would prevent the removal of the last
+ * reference to a domain.
+ *
+ * Returns the number of domain snapshots found or -1 in case of error.
+ * On success, the array stored into @snaps is guaranteed to have an
+ * extra allocated element set to NULL, to make iteration easier.
+ */
+int
+virDomainListAllSnapshots(virDomainPtr domain, virDomainSnapshotPtr **snaps,
+                          unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "snaps=%p, flags=%x", snaps, flags);
+
+    virResetLastError();
+
+    if (snaps)
+        *snaps = NULL;
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainListAllSnapshots) {
+        int ret = conn->driver->domainListAllSnapshots(domain, snaps, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+/**
  * virDomainSnapshotNumChildren:
  * @snapshot: a domain snapshot object
  * @flags: bitwise-OR of supported virDomainSnapshotListFlags
@@ -17336,6 +17409,82 @@ error:
 }

 /**
+ * virDomainSnapshotListAllChildren:
+ * @snapshot: a domain snapshot object
+ * @snaps: pointer to variable to store the array containing snapshot objects,
+ *         or NULL if the list is not required (just returns number of
+ *         snapshots)
+ * @flags: bitwise-OR of supported virDomainSnapshotListFlags
+ *
+ * Collect the list of domain snapshots that are children of the given
+ * snapshot, and allocate an array to store those objects.  Caller is
+ * responsible for calling virDomainSnapshotFree() on each member of the
+ * array, then free() on the array itself.
+ *
+ * By default, this command covers only direct children; it is also possible
+ * to expand things to cover all descendants, when @flags includes
+ * VIR_DOMAIN_SNAPSHOT_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
+ * 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.
+ *
+ * The first group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_LEAVES and
+ * VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, to filter based on snapshots that
+ * have no further children (a leaf snapshot).
+ *
+ * The next group of @flags is VIR_DOMAIN_SNAPSHOT_LIST_METADATA and
+ * VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, for filtering snapshots based on
+ * whether they have metadata that would prevent the removal of the last
+ * reference to a domain.
+ *
+ * Returns the number of domain snapshots found or -1 in case of error.
+ * On success, the array stored into @snaps is guaranteed to have an
+ * extra allocated element set to NULL, to make iteration easier.
+ */
+int
+virDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
+                                 virDomainSnapshotPtr **snaps,
+                                 unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DEBUG("snapshot=%p, snaps=%p, flags=%x", snapshot, snaps, flags);
+
+    virResetLastError();
+
+    if (snaps)
+        *snaps = NULL;
+
+    if (!VIR_IS_DOMAIN_SNAPSHOT(snapshot)) {
+        virLibDomainSnapshotError(VIR_ERR_INVALID_DOMAIN_SNAPSHOT,
+                                  __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = snapshot->domain->conn;
+
+    if (conn->driver->domainSnapshotListAllChildren) {
+        int ret = conn->driver->domainSnapshotListAllChildren(snapshot, snaps,
+                                                              flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+/**
  * virDomainSnapshotLookupByName:
  * @domain: a domain object
  * @name: name for the domain snapshot
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index ea49a68..2913a81 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -537,8 +537,10 @@ LIBVIRT_0.9.11 {
 LIBVIRT_0.9.13 {
     global:
         virConnectListAllDomains;
+        virDomainListAllSnapshots;
         virDomainSnapshotHasMetadata;
         virDomainSnapshotIsCurrent;
+        virDomainSnapshotListAllChildren;
         virDomainSnapshotRef;
 } LIBVIRT_0.9.11;

-- 
1.7.10.2




More information about the libvir-list mailing list