Signed-off-by: Chris Lalancette <clalance@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list