[libvirt] [PATCHv2 13/7] snapshot: implement snapshot children listing in vbox

Eric Blake eblake at redhat.com
Fri Oct 7 00:12:12 UTC 2011


Adding this for VBox was a bit harder than for ESX, but the same
principles apply for starting the traversal at a known point
rather than covering the entire hierarchy.

* src/vbox/vbox_tmpl.c (vboxCountDescendants)
(vboxDomainSnapshotNumChildren)
(vboxDomainSnapshotListChildrenNames): New functions.
---

Changes in v2: avoid leaking snapshot, and fix recursive children
names to get through loop properly by transferring initial snapshot
into loop then skipping that element while grabbing names.

Still untested from my end, but hopefully does better.

 src/vbox/vbox_tmpl.c |  213 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 213 insertions(+), 0 deletions(-)

diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index c74d2cf..84a4fca 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -5976,6 +5976,217 @@ cleanup:
     return ret;
 }

+static int
+vboxCountDescendants(ISnapshot *snapshot, bool recurse)
+{
+    vboxArray children = VBOX_ARRAY_INITIALIZER;
+    nsresult rc;
+    int count = 0;
+    int i;
+
+    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
+    if (NS_FAILED(rc)) {
+        vboxError(VIR_ERR_INTERNAL_ERROR,
+                  "%s", _("could not get children snapshots"));
+        count = -1;
+        goto cleanup;
+    }
+
+    if (recurse) {
+        for (i = 0; i < children.count; i++) {
+            int descendants = vboxCountDescendants(children.items[i], true);
+            if (descendants < 0) {
+                count = -1;
+                goto cleanup;
+            }
+            count += 1 + descendants;
+        }
+    } else {
+        count = children.count;
+    }
+
+cleanup:
+    vboxArrayRelease(&children);
+    return count;
+}
+
+static int
+vboxDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
+                              unsigned int flags)
+{
+    virDomainPtr dom = snapshot->domain;
+    VBOX_OBJECT_CHECK(dom->conn, int, -1);
+    vboxIID iid = VBOX_IID_INITIALIZER;
+    IMachine *machine = NULL;
+    ISnapshot *snap = NULL;
+    nsresult rc;
+    bool recurse;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
+
+    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
+
+    vboxIIDFromUUID(&iid, dom->uuid);
+    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
+    if (NS_FAILED(rc)) {
+        vboxError(VIR_ERR_NO_DOMAIN, "%s",
+                  _("no domain with matching UUID"));
+        goto cleanup;
+    }
+
+    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
+        goto cleanup;
+
+    /* VBox snapshots do not require libvirt to maintain any metadata.  */
+    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    ret = vboxCountDescendants(snap, recurse);
+
+cleanup:
+    VBOX_RELEASE(machine);
+    VBOX_RELEASE(snap);
+    vboxIIDUnalloc(&iid);
+    return ret;
+}
+
+static int
+vboxDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
+                                    char **names,
+                                    int nameslen,
+                                    unsigned int flags)
+{
+    virDomainPtr dom = snapshot->domain;
+    VBOX_OBJECT_CHECK(dom->conn, int, -1);
+    vboxIID iid = VBOX_IID_INITIALIZER;
+    IMachine *machine = NULL;
+    ISnapshot *snap = NULL;
+    nsresult rc;
+    ISnapshot **snapshots = NULL;
+    PRUint32 count = 0;
+    int i;
+    vboxArray children = VBOX_ARRAY_INITIALIZER;
+
+    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
+
+    vboxIIDFromUUID(&iid, dom->uuid);
+    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
+    if (NS_FAILED(rc)) {
+        vboxError(VIR_ERR_NO_DOMAIN, "%s",
+                  _("no domain with matching UUID"));
+        goto cleanup;
+    }
+
+    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
+        goto cleanup;
+
+    if (!nameslen || (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    /* Over-allocates, but this is the easiest way to do things */
+    rc = machine->vtbl->GetSnapshotCount(machine, &count);
+    if (NS_FAILED(rc)) {
+        vboxError(VIR_ERR_INTERNAL_ERROR,
+                  _("could not get snapshot count for domain %s"),
+                  dom->name);
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC_N(snapshots, count) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    rc = vboxArrayGet(&children, snap, snap->vtbl->GetChildren);
+    if (NS_FAILED(rc)) {
+        vboxError(VIR_ERR_INTERNAL_ERROR,
+                  "%s", _("could not get children snapshots"));
+        goto cleanup;
+    }
+
+    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) {
+        int top = children.count;
+        int next;
+
+        snapshots[0] = snap;
+        snap = NULL;
+        for (next = 0; next < count; next++) {
+            if (!snapshots[next])
+                break;
+            rc = vboxArrayGet(&children, snapshots[next],
+                              snapshots[next]->vtbl->GetChildren);
+            if (NS_FAILED(rc)) {
+                vboxError(VIR_ERR_INTERNAL_ERROR,
+                          "%s", _("could not get children snapshots"));
+                goto cleanup;
+            }
+            for (i = 0; i < children.count; i++) {
+                ISnapshot *child = children.items[i];
+                if (!child)
+                    continue;
+                if (top == count) {
+                    vboxError(VIR_ERR_INTERNAL_ERROR,
+                              _("unexpected number of snapshots > %u"), count);
+                    vboxArrayRelease(&children);
+                    goto cleanup;
+                }
+                VBOX_ADDREF(child);
+                snapshots[top++] = child;
+            }
+            vboxArrayRelease(&children);
+        }
+        count = top - 1;
+    } else {
+        count = children.count;
+    }
+
+    for (i = 0; i < nameslen; i++) {
+        PRUnichar *nameUtf16;
+        char *name;
+        int j = i + !!(flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS);
+
+        if (i >= count)
+            break;
+
+        rc = snapshots[j]->vtbl->GetName(snapshots[j], &nameUtf16);
+        if (NS_FAILED(rc) || !nameUtf16) {
+            vboxError(VIR_ERR_INTERNAL_ERROR,
+                      "%s", _("could not get snapshot name"));
+            goto cleanup;
+        }
+        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
+        VBOX_UTF16_FREE(nameUtf16);
+        names[i] = strdup(name);
+        VBOX_UTF8_FREE(name);
+        if (!names[i]) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    if (count <= nameslen)
+        ret = count;
+    else
+        ret = nameslen;
+
+cleanup:
+    if (count > 0) {
+        for (i = 0; i < count; i++)
+            VBOX_RELEASE(snapshots[i]);
+    }
+    VIR_FREE(snapshots);
+    VBOX_RELEASE(machine);
+    VBOX_RELEASE(snap);
+    vboxIIDUnalloc(&iid);
+    return ret;
+}
+
 static virDomainSnapshotPtr
 vboxDomainSnapshotLookupByName(virDomainPtr dom,
                                const char *name,
@@ -8945,6 +9156,8 @@ virDriver NAME(Driver) = {
     .domainSnapshotGetXMLDesc = vboxDomainSnapshotGetXMLDesc, /* 0.8.0 */
     .domainSnapshotNum = vboxDomainSnapshotNum, /* 0.8.0 */
     .domainSnapshotListNames = vboxDomainSnapshotListNames, /* 0.8.0 */
+    .domainSnapshotNumChildren = vboxDomainSnapshotNumChildren, /* 0.9.7 */
+    .domainSnapshotListChildrenNames = vboxDomainSnapshotListChildrenNames, /* 0.9.7 */
     .domainSnapshotLookupByName = vboxDomainSnapshotLookupByName, /* 0.8.0 */
     .domainHasCurrentSnapshot = vboxDomainHasCurrentSnapshot, /* 0.8.0 */
     .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
-- 
1.7.4.4




More information about the libvir-list mailing list