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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list