[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 2/6] Snapshot internal methods.



Signed-off-by: Chris Lalancette <clalance redhat com>
---
 src/conf/domain_conf.c   |  365 ++++++++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h   |   55 +++++++
 src/libvirt_private.syms |   10 ++
 3 files changed, 430 insertions(+), 0 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index d6ba4f6..41c83fd 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -28,6 +28,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <dirent.h>
+#include <sys/time.h>
 
 #include "virterror_internal.h"
 #include "datatypes.h"
@@ -43,6 +44,7 @@
 #include "network.h"
 #include "macvtap.h"
 #include "nwfilter_conf.h"
+#include "ignore-value.h"
 
 #define VIR_FROM_THIS VIR_FROM_DOMAIN
 
@@ -744,6 +746,8 @@ static void virDomainObjFree(virDomainObjPtr dom)
 
     virMutexDestroy(&dom->lock);
 
+    virDomainSnapshotObjListDeinit(&dom->snapshots);
+
     VIR_FREE(dom);
 }
 
@@ -796,6 +800,8 @@ static virDomainObjPtr virDomainObjNew(virCapsPtr caps)
     domain->state = VIR_DOMAIN_SHUTOFF;
     domain->refs = 1;
 
+    virDomainSnapshotObjListInit(&domain->snapshots);
+
     VIR_DEBUG("obj=%p", domain);
     return domain;
 }
@@ -6558,4 +6564,363 @@ cleanup:
     return -1;
 }
 
+/* Snapshot Def functions */
+void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->name);
+    VIR_FREE(def->description);
+    VIR_FREE(def->parent);
+    VIR_FREE(def);
+}
+
+virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
+                                                        int newSnapshot)
+{
+    xmlXPathContextPtr ctxt = NULL;
+    xmlDocPtr xml = NULL;
+    xmlNodePtr root;
+    virDomainSnapshotDefPtr def = NULL;
+    virDomainSnapshotDefPtr ret = NULL;
+    char *creation = NULL, *state = NULL;
+    struct timeval tv;
+
+    xml = virXMLParse(NULL, xmlStr, "domainsnapshot.xml");
+    if (!xml) {
+        virDomainReportError(VIR_ERR_XML_ERROR,
+                             "%s",_("failed to parse snapshot xml document"));
+        return NULL;
+    }
+
+    if ((root = xmlDocGetRootElement(xml)) == NULL) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("missing root element"));
+        goto cleanup;
+    }
+
+    if (!xmlStrEqual(root->name, BAD_CAST "domainsnapshot")) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("incorrect root element"));
+        goto cleanup;
+    }
+
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    ctxt->node = root;
+
+    gettimeofday(&tv, NULL);
+
+    def->name = virXPathString("string(./name)", ctxt);
+    if (def->name == NULL)
+        ignore_value(virAsprintf(&def->name, "%ld", tv.tv_sec));
+
+    if (def->name == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->description = virXPathString("string(./description)", ctxt);
+
+    if (!newSnapshot) {
+        if (virXPathLong("string(./creationTime)", ctxt,
+                         &def->creationTime) < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                 _("missing creationTime from existing snapshot"));
+            goto cleanup;
+        }
+
+        def->parent = virXPathString("string(./parent/name)", ctxt);
+
+        state = virXPathString("string(./state)", ctxt);
+        if (state == NULL) {
+            /* there was no state in an existing snapshot; this
+             * should never happen
+             */
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                 _("missing state from existing snapshot"));
+            goto cleanup;
+        }
+        def->state = virDomainStateTypeFromString(state);
+        if (def->state < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("Invalid state '%s' in domain snapshot XML"),
+                                 state);
+            goto cleanup;
+        }
+
+        if (virXPathLong("string(./active)", ctxt, &def->active) < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                 _("Could not find 'active' element"));
+            goto cleanup;
+        }
+    }
+    else
+        def->creationTime = tv.tv_sec;
+
+    ret = def;
+
+cleanup:
+    VIR_FREE(creation);
+    VIR_FREE(state);
+    xmlXPathFreeContext(ctxt);
+    if (ret == NULL)
+        virDomainSnapshotDefFree(def);
+    xmlFreeDoc(xml);
+
+    return ret;
+}
+
+char *virDomainSnapshotDefFormat(char *domain_uuid,
+                                 virDomainSnapshotDefPtr def,
+                                 int internal)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAddLit(&buf, "<domainsnapshot>\n");
+    virBufferVSprintf(&buf, "  <name>%s</name>\n", def->name);
+    if (def->description)
+        virBufferVSprintf(&buf, "  <description>%s</description>\n",
+                          def->description);
+    virBufferVSprintf(&buf, "  <state>%s</state>\n",
+                      virDomainStateTypeToString(def->state));
+    if (def->parent) {
+        virBufferAddLit(&buf, "  <parent>\n");
+        virBufferVSprintf(&buf, "    <name>%s</name>\n", def->parent);
+        virBufferAddLit(&buf, "  </parent>\n");
+    }
+    virBufferVSprintf(&buf, "  <creationTime>%ld</creationTime>\n",
+                      def->creationTime);
+    virBufferAddLit(&buf, "  <domain>\n");
+    virBufferVSprintf(&buf, "    <uuid>%s</uuid>\n", domain_uuid);
+    virBufferAddLit(&buf, "  </domain>\n");
+    if (internal)
+        virBufferVSprintf(&buf, "  <active>%ld</active>\n", def->active);
+    virBufferAddLit(&buf, "</domainsnapshot>\n");
+
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+/* Snapshot Obj functions */
+static virDomainSnapshotObjPtr virDomainSnapshotObjNew(void)
+{
+    virDomainSnapshotObjPtr snapshot;
+
+    if (VIR_ALLOC(snapshot) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    snapshot->refs = 1;
+
+    VIR_DEBUG("obj=%p", snapshot);
+
+    return snapshot;
+}
+
+static void virDomainSnapshotObjFree(virDomainSnapshotObjPtr snapshot)
+{
+    if (!snapshot)
+        return;
+
+    VIR_DEBUG("obj=%p", snapshot);
+
+    virDomainSnapshotDefFree(snapshot->def);
+}
+
+int virDomainSnapshotObjUnref(virDomainSnapshotObjPtr snapshot)
+{
+    snapshot->refs--;
+    VIR_DEBUG("obj=%p refs=%d", snapshot, snapshot->refs);
+    if (snapshot->refs == 0) {
+        virDomainSnapshotObjFree(snapshot);
+        return 0;
+    }
+    return snapshot->refs;
+}
+
+virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
+                                                   const virDomainSnapshotDefPtr def)
+{
+    virDomainSnapshotObjPtr snap;
+
+    if (virHashLookup(snapshots->objs, def->name) != NULL) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected domain snapshot %s already exists"),
+                             def->name);
+        return NULL;
+    }
+
+    if (!(snap = virDomainSnapshotObjNew()))
+        return NULL;
+    snap->def = def;
+
+    if (virHashAddEntry(snapshots->objs, snap->def->name, snap) < 0) {
+        VIR_FREE(snap);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return snap;
+}
+
+/* Snapshot Obj List functions */
+int virDomainSnapshotObjListInit(virDomainSnapshotObjListPtr snapshots)
+{
+    snapshots->objs = virHashCreate(50);
+    if (!snapshots->objs) {
+        virReportOOMError();
+        return -1;
+    }
+    return 0;
+}
+
+static void virDomainSnapshotObjListDeallocator(void *payload,
+                                                const char *name ATTRIBUTE_UNUSED)
+{
+    virDomainSnapshotObjPtr obj = payload;
+
+    virDomainSnapshotObjUnref(obj);
+}
+
+void virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr snapshots)
+{
+    if (snapshots->objs)
+        virHashFree(snapshots->objs, virDomainSnapshotObjListDeallocator);
+}
+
+struct virDomainSnapshotNameData {
+    int oom;
+    int numnames;
+    int maxnames;
+    char **const names;
+};
+
+static void virDomainSnapshotObjListCopyNames(void *payload,
+                                              const char *name ATTRIBUTE_UNUSED,
+                                              void *opaque)
+{
+    virDomainSnapshotObjPtr obj = payload;
+    struct virDomainSnapshotNameData *data = opaque;
+
+    if (data->oom)
+        return;
+
+    if (data->numnames < data->maxnames) {
+        if (!(data->names[data->numnames] = strdup(obj->def->name)))
+            data->oom = 1;
+        else
+            data->numnames++;
+    }
+}
+
+int virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
+                                     char **const names, int maxnames)
+{
+    struct virDomainSnapshotNameData data = { 0, 0, maxnames, names };
+    int i;
+
+    virHashForEach(snapshots->objs, virDomainSnapshotObjListCopyNames, &data);
+    if (data.oom) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    return data.numnames;
+
+cleanup:
+    for (i = 0; i < data.numnames; i++)
+        VIR_FREE(data.names[i]);
+    return -1;
+}
+
+static void virDomainSnapshotObjListCount(void *payload ATTRIBUTE_UNUSED,
+                                          const char *name ATTRIBUTE_UNUSED,
+                                          void *data)
+{
+    int *count = data;
+
+    (*count)++;
+}
+
+int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots)
+{
+    int count = 0;
+
+    virHashForEach(snapshots->objs, virDomainSnapshotObjListCount, &count);
+
+    return count;
+}
+
+static int virDomainSnapshotObjListSearchName(const void *payload,
+                                              const char *name ATTRIBUTE_UNUSED,
+                                              const void *data)
+{
+    virDomainSnapshotObjPtr obj = (virDomainSnapshotObjPtr)payload;
+    int want = 0;
+
+    if (STREQ(obj->def->name, (const char *)data))
+        want = 1;
+
+    return want;
+}
+
+virDomainSnapshotObjPtr virDomainSnapshotFindByName(const virDomainSnapshotObjListPtr snapshots,
+                                                    const char *name)
+{
+    return virHashSearch(snapshots->objs, virDomainSnapshotObjListSearchName, name);
+}
+
+void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
+                                    virDomainSnapshotObjPtr snapshot)
+{
+    virHashRemoveEntry(snapshots->objs, snapshot->def->name,
+                       virDomainSnapshotObjListDeallocator);
+}
+
+struct snapshot_has_children {
+    char *name;
+    int number;
+};
+
+static void virDomainSnapshotCountChildren(void *payload,
+                                           const char *name ATTRIBUTE_UNUSED,
+                                           void *data)
+{
+    virDomainSnapshotObjPtr obj = payload;
+    struct snapshot_has_children *curr = data;
+
+    if (obj->def->parent && STREQ(obj->def->parent, curr->name))
+        curr->number++;
+}
+
+int virDomainSnapshotHasChildren(virDomainSnapshotObjPtr snap,
+                                virDomainSnapshotObjListPtr snapshots)
+{
+    struct snapshot_has_children children;
+
+    children.name = snap->def->name;
+    children.number = 0;
+    virHashForEach(snapshots->objs, virDomainSnapshotCountChildren, &children);
+
+    return children.number;
+}
+
+
 #endif /* ! PROXY */
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index b789289..5c64a47 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -741,6 +741,58 @@ struct _virDomainClockDef {
 
 # define VIR_DOMAIN_CPUMASK_LEN 1024
 
+
+/* Snapshot state */
+typedef struct _virDomainSnapshotDef virDomainSnapshotDef;
+typedef virDomainSnapshotDef *virDomainSnapshotDefPtr;
+struct _virDomainSnapshotDef {
+    char *name;
+    char *description;
+    char *parent;
+    time_t creationTime;
+    int state;
+
+    long active;
+};
+
+typedef struct _virDomainSnapshotObj virDomainSnapshotObj;
+typedef virDomainSnapshotObj *virDomainSnapshotObjPtr;
+struct _virDomainSnapshotObj {
+    int refs;
+
+    virDomainSnapshotDefPtr def;
+};
+
+typedef struct _virDomainSnapshotObjList virDomainSnapshotObjList;
+typedef virDomainSnapshotObjList *virDomainSnapshotObjListPtr;
+struct _virDomainSnapshotObjList {
+    /* name string -> virDomainSnapshotObj  mapping
+     * for O(1), lockless lookup-by-name */
+    virHashTable *objs;
+};
+
+virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
+                                                        int newSnapshot);
+void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def);
+char *virDomainSnapshotDefFormat(char *domain_uuid,
+                                 virDomainSnapshotDefPtr def,
+                                 int internal);
+virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
+                                                   const virDomainSnapshotDefPtr def);
+
+int virDomainSnapshotObjListInit(virDomainSnapshotObjListPtr objs);
+void virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr objs);
+int virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
+                                     char **const names, int maxnames);
+int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots);
+virDomainSnapshotObjPtr virDomainSnapshotFindByName(const virDomainSnapshotObjListPtr snapshots,
+                                                    const char *name);
+void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
+                                    virDomainSnapshotObjPtr snapshot);
+int virDomainSnapshotObjUnref(virDomainSnapshotObjPtr snapshot);
+int virDomainSnapshotHasChildren(virDomainSnapshotObjPtr snap,
+                                virDomainSnapshotObjListPtr snapshots);
+
 /* Guest VM main configuration */
 typedef struct _virDomainDef virDomainDef;
 typedef virDomainDef *virDomainDefPtr;
@@ -828,6 +880,9 @@ struct _virDomainObj {
     virDomainDefPtr def; /* The current definition */
     virDomainDefPtr newDef; /* New definition to activate at shutdown */
 
+    virDomainSnapshotObjList snapshots;
+    virDomainSnapshotObjPtr current_snapshot;
+
     void *privateData;
     void (*privateDataFreeFunc)(void *);
 };
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 86aacd7..1682b25 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -206,6 +206,16 @@ virDomainTimerTickpolicyTypeToString;
 virDomainTimerTickpolicyTypeFromString;
 virDomainTimerModeTypeToString;
 virDomainTimerModeTypeFromString;
+virDomainSnapshotObjListGetNames;
+virDomainSnapshotObjListNum;
+virDomainSnapshotFindByName;
+virDomainSnapshotObjListAdd;
+virDomainSnapshotObjListRemove;
+virDomainSnapshotHasChildren;
+virDomainSnapshotObjUnref;
+virDomainSnapshotDefParseString;
+virDomainSnapshotDefFormat;
+virDomainSnapshotAssignDef;
 
 
 # domain_event.h
-- 
1.6.6.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]