On Wed, Mar 27, 2019 at 05:10:40AM -0500, Eric Blake wrote:
Add a new file checkpoint_conf.c that performs the translation to and from new XML describing a checkpoint. The code shares a common base class with snapshots, since a checkpoint similarly represents the domain state at a moment in time. Add some basic testing of round trip XML handling through the new code. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- src/conf/checkpoint_conf.h | 96 +++++ src/conf/virconftypes.h | 3 + po/POTFILES | 1 + src/conf/Makefile.inc.am | 2 + src/conf/checkpoint_conf.c | 553 ++++++++++++++++++++++++++++ src/libvirt_private.syms | 8 + tests/Makefile.am | 9 +- tests/domaincheckpointxml2xmltest.c | 212 +++++++++++ 8 files changed, 882 insertions(+), 2 deletions(-) create mode 100644 src/conf/checkpoint_conf.h create mode 100644 src/conf/checkpoint_conf.c create mode 100644 tests/domaincheckpointxml2xmltest.c diff --git a/src/conf/checkpoint_conf.h b/src/conf/checkpoint_conf.h new file mode 100644 index 0000000000..6647d0cd7c --- /dev/null +++ b/src/conf/checkpoint_conf.h @@ -0,0 +1,96 @@ +/* + * checkpoint_conf.h: domain checkpoint XML processing + * (based on snapshot_conf.h) + * + * Copyright (C) 2006-2019 Red Hat, Inc. + * Copyright (C) 2006-2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef LIBVIRT_CHECKPOINT_CONF_H +# define LIBVIRT_CHECKPOINT_CONF_H + +# include "internal.h" +# include "domain_conf.h" +# include "moment_conf.h" + +/* Items related to checkpoint state */ + +typedef enum { + VIR_DOMAIN_CHECKPOINT_TYPE_DEFAULT = 0, + VIR_DOMAIN_CHECKPOINT_TYPE_NONE, + VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP, + + VIR_DOMAIN_CHECKPOINT_TYPE_LAST +} virDomainCheckpointType; + +/* Stores disk-checkpoint information */ +typedef struct _virDomainCheckpointDiskDef virDomainCheckpointDiskDef; +typedef virDomainCheckpointDiskDef *virDomainCheckpointDiskDefPtr; +struct _virDomainCheckpointDiskDef { + char *name; /* name matching the <target dev='...' of the domain */ + int idx; /* index within checkpoint->dom->disks that matches name */ + int type; /* virDomainCheckpointType */ + char *bitmap; /* bitmap name, if type is bitmap */ + unsigned long long size; /* current checkpoint size in bytes */ +}; + +/* Stores the complete checkpoint metadata */ +struct _virDomainCheckpointDef { + virDomainMomentDef common; + + /* Additional Public XML. */ + size_t ndisks; /* should not exceed dom->ndisks */ + virDomainCheckpointDiskDef *disks; +}; + + +typedef enum { + VIR_DOMAIN_CHECKPOINT_PARSE_REDEFINE = 1 << 0, + VIR_DOMAIN_CHECKPOINT_PARSE_INTERNAL = 1 << 1, +} virDomainCheckpointParseFlags; + +typedef enum { + VIR_DOMAIN_CHECKPOINT_FORMAT_SECURE = 1 << 0, + VIR_DOMAIN_CHECKPOINT_FORMAT_NO_DOMAIN = 1 << 1, + VIR_DOMAIN_CHECKPOINT_FORMAT_SIZE = 1 << 2, + VIR_DOMAIN_CHECKPOINT_FORMAT_INTERNAL = 1 << 3, + VIR_DOMAIN_CHECKPOINT_FORMAT_CURRENT = 1 << 4, +} virDomainCheckpointFormatFlags; + +unsigned int virDomainCheckpointFormatConvertXMLFlags(unsigned int flags); + +virDomainCheckpointDefPtr virDomainCheckpointDefParseString(const char *xmlStr, + virCapsPtr caps, + virDomainXMLOptionPtr xmlopt, + bool *current, + unsigned int flags); +virDomainCheckpointDefPtr virDomainCheckpointDefParseNode(xmlDocPtr xml, + xmlNodePtr root, + virCapsPtr caps, + virDomainXMLOptionPtr xmlopt, + bool *current, + unsigned int flags); +void virDomainCheckpointDefFree(virDomainCheckpointDefPtr def); +char *virDomainCheckpointDefFormat(virDomainCheckpointDefPtr def, + virCapsPtr caps, + virDomainXMLOptionPtr xmlopt, + unsigned int flags); +int virDomainCheckpointAlignDisks(virDomainCheckpointDefPtr checkpoint); + +VIR_ENUM_DECL(virDomainCheckpoint); + +#endif /* LIBVIRT_CHECKPOINT_CONF_H */ diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index 6a8267c422..f01721c6d5 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -103,6 +103,9 @@ typedef virDomainBlkiotune *virDomainBlkiotunePtr; typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo; typedef virDomainBlockIoTuneInfo *virDomainBlockIoTuneInfoPtr; +typedef struct _virDomainCheckpointDef virDomainCheckpointDef; +typedef virDomainCheckpointDef *virDomainCheckpointDefPtr; + typedef struct _virDomainChrDef virDomainChrDef; typedef virDomainChrDef *virDomainChrDefPtr; diff --git a/po/POTFILES b/po/POTFILES index 88af551664..57c55fb35f 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -15,6 +15,7 @@ src/bhyve/bhyve_monitor.c src/bhyve/bhyve_parse_command.c src/bhyve/bhyve_process.c src/conf/capabilities.c +src/conf/checkpoint_conf.c src/conf/cpu_conf.c src/conf/device_conf.c src/conf/domain_addr.c diff --git a/src/conf/Makefile.inc.am b/src/conf/Makefile.inc.am index 6eb64db9de..913e21e2d1 100644 --- a/src/conf/Makefile.inc.am +++ b/src/conf/Makefile.inc.am @@ -10,6 +10,8 @@ NETDEV_CONF_SOURCES = \ DOMAIN_CONF_SOURCES = \ conf/capabilities.c \ conf/capabilities.h \ + conf/checkpoint_conf.c \ + conf/checkpoint_conf.h \ conf/domain_addr.c \ conf/domain_addr.h \ conf/domain_capabilities.c \ diff --git a/src/conf/checkpoint_conf.c b/src/conf/checkpoint_conf.c new file mode 100644 index 0000000000..bdcf763a48 --- /dev/null +++ b/src/conf/checkpoint_conf.c @@ -0,0 +1,553 @@ +/* + * checkpoint_conf.c: domain checkpoint XML processing + * + * Copyright (C) 2006-2019 Red Hat, Inc. + * Copyright (C) 2006-2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <sys/time.h> + +#include "internal.h" +#include "virbitmap.h" +#include "virbuffer.h" +#include "datatypes.h" +#include "domain_conf.h" +#include "virlog.h" +#include "viralloc.h" +#include "checkpoint_conf.h" +#include "virstoragefile.h" +#include "viruuid.h" +#include "virfile.h" +#include "virerror.h" +#include "virxml.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_DOMAIN_CHECKPOINT + +VIR_LOG_INIT("conf.checkpoint_conf"); + +VIR_ENUM_IMPL(virDomainCheckpoint, VIR_DOMAIN_CHECKPOINT_TYPE_LAST, + "default", "no", "bitmap"); + + +/* Checkpoint Def functions */ +static void +virDomainCheckpointDiskDefClear(virDomainCheckpointDiskDefPtr disk) +{ + VIR_FREE(disk->name); + VIR_FREE(disk->bitmap); +} + +void virDomainCheckpointDefFree(virDomainCheckpointDefPtr def) +{ + size_t i; + + if (!def) + return; + + virDomainMomentDefClear(&def->common); + for (i = 0; i < def->ndisks; i++) + virDomainCheckpointDiskDefClear(&def->disks[i]); + VIR_FREE(def->disks); + VIR_FREE(def); +} + +static int +virDomainCheckpointDiskDefParseXML(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virDomainCheckpointDiskDefPtr def) +{ + int ret = -1; + char *checkpoint = NULL; + char *bitmap = NULL; + xmlNodePtr saved = ctxt->node; + + ctxt->node = node; + + def->name = virXMLPropString(node, "name"); + if (!def->name) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing name from disk checkpoint element")); + goto cleanup; + } + + checkpoint = virXMLPropString(node, "checkpoint"); + if (checkpoint) { + def->type = virDomainCheckpointTypeFromString(checkpoint); + if (def->type <= 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown disk checkpoint setting '%s'"), + checkpoint); + goto cleanup; + } + } else { + def->type = VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP; + } + + bitmap = virXMLPropString(node, "bitmap"); + if (bitmap) { + if (def->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk checkpoint bitmap '%s' requires " + "type='bitmap'"), + bitmap); + goto cleanup; + } + VIR_STEAL_PTR(def->bitmap, bitmap); + } + + ret = 0; + cleanup: + ctxt->node = saved; + + VIR_FREE(checkpoint); + VIR_FREE(bitmap); + if (ret < 0) + virDomainCheckpointDiskDefClear(def); + return ret; +} + +/* flags is bitwise-or of virDomainCheckpointParseFlags. If flags + * does not include VIR_DOMAIN_CHECKPOINT_PARSE_REDEFINE, then caps + * are ignored. If flags does not include + * VIR_DOMAIN_CHECKPOINT_PARSE_INTERNAL, then current is ignored. + */ +static virDomainCheckpointDefPtr +virDomainCheckpointDefParse(xmlXPathContextPtr ctxt, + virCapsPtr caps, + virDomainXMLOptionPtr xmlopt, + bool *current, + unsigned int flags) +{ + virDomainCheckpointDefPtr def = NULL; + virDomainCheckpointDefPtr ret = NULL; + xmlNodePtr *nodes = NULL; + size_t i; + int n; + char *creation = NULL; + struct timeval tv; + int active; + char *tmp; + + if (VIR_ALLOC(def) < 0) + goto cleanup; + + gettimeofday(&tv, NULL); +
Eww. I'd expect an XML parsing function to behave the same regardless of the time of day. For domains, we'd put this kind of stuff into a post-parse function.
+ def->common.name = virXPathString("string(./name)", ctxt); + if (def->common.name == NULL) { + if (flags & VIR_DOMAIN_CHECKPOINT_PARSE_REDEFINE) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("a redefined checkpoint must have a name")); + goto cleanup; + } + if (virAsprintf(&def->common.name, "%lld", (long long)tv.tv_sec) < 0) + goto cleanup; + } + + def->common.description = virXPathString("string(./description)", ctxt); + + if (flags & VIR_DOMAIN_CHECKPOINT_PARSE_REDEFINE) { + if (virXPathLongLong("string(./creationTime)", ctxt, + &def->common.creationTime) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing creationTime from existing checkpoint")); + goto cleanup; + } + + def->common.parent = virXPathString("string(./parent/name)", ctxt); +
+ if ((tmp = virXPathString("string(./domain/@type)", ctxt))) {
tmp is freed right away and the error reported on else is duplicate with the one a few lines below.
+ int domainflags = VIR_DOMAIN_DEF_PARSE_INACTIVE | + VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE; + xmlNodePtr domainNode = virXPathNode("./domain", ctxt); + + VIR_FREE(tmp); + if (!domainNode) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing domain in checkpoint")); + goto cleanup; + } + def->common.dom = virDomainDefParseNode(ctxt->node->doc, domainNode, + caps, xmlopt, NULL, + domainflags); + if (!def->common.dom) + goto cleanup; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing domain in checkpoint redefine")); + goto cleanup; + }
+ } else { + def->common.creationTime = tv.tv_sec; + } +
Jano
Attachment:
signature.asc
Description: PGP signature
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list