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