2012-08-14 00:09:12 +00:00
|
|
|
/*
|
|
|
|
* snapshot_conf.c: domain snapshot XML processing
|
|
|
|
*
|
2019-02-15 20:43:43 +00:00
|
|
|
* Copyright (C) 2006-2019 Red Hat, Inc.
|
2012-08-14 00:09:12 +00:00
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-08-14 00:09:12 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2019-07-06 03:02:03 +00:00
|
|
|
#include "configmake.h"
|
2012-08-14 00:09:12 +00:00
|
|
|
#include "internal.h"
|
2012-12-04 11:56:32 +00:00
|
|
|
#include "virbitmap.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-08-14 00:09:12 +00:00
|
|
|
#include "datatypes.h"
|
|
|
|
#include "domain_conf.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-08-14 00:09:12 +00:00
|
|
|
#include "netdev_bandwidth_conf.h"
|
|
|
|
#include "netdev_vport_profile_conf.h"
|
|
|
|
#include "nwfilter_conf.h"
|
|
|
|
#include "secret_conf.h"
|
|
|
|
#include "snapshot_conf.h"
|
2012-12-13 15:25:48 +00:00
|
|
|
#include "virstoragefile.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2012-08-14 00:09:12 +00:00
|
|
|
#include "virfile.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-13 18:13:21 +00:00
|
|
|
#include "virxml.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2019-03-15 02:19:18 +00:00
|
|
|
#include "virdomainsnapshotobjlist.h"
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2018-09-04 13:42:42 +00:00
|
|
|
#define LIBVIRT_SNAPSHOT_CONF_PRIV_H_ALLOW
|
|
|
|
#include "snapshot_conf_priv.h"
|
|
|
|
|
2012-08-14 00:09:12 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_DOMAIN_SNAPSHOT
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("conf.snapshot_conf");
|
|
|
|
|
2019-05-09 14:59:06 +00:00
|
|
|
static virClassPtr virDomainSnapshotDefClass;
|
|
|
|
static void virDomainSnapshotDefDispose(void *obj);
|
|
|
|
|
|
|
|
static int
|
|
|
|
virDomainSnapshotOnceInit(void)
|
|
|
|
{
|
|
|
|
if (!VIR_CLASS_NEW(virDomainSnapshotDef, virClassForDomainMomentDef()))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_ONCE_GLOBAL_INIT(virDomainSnapshot);
|
|
|
|
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainSnapshotLocation,
|
|
|
|
VIR_DOMAIN_SNAPSHOT_LOCATION_LAST,
|
2012-08-14 00:09:12 +00:00
|
|
|
"default",
|
|
|
|
"no",
|
|
|
|
"internal",
|
2019-01-20 16:30:15 +00:00
|
|
|
"external",
|
|
|
|
);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
|
|
|
/* virDomainSnapshotState is really virDomainState plus one extra state */
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainSnapshotState,
|
|
|
|
VIR_DOMAIN_SNAPSHOT_LAST,
|
2012-08-14 00:09:12 +00:00
|
|
|
"nostate",
|
|
|
|
"running",
|
|
|
|
"blocked",
|
|
|
|
"paused",
|
|
|
|
"shutdown",
|
|
|
|
"shutoff",
|
|
|
|
"crashed",
|
|
|
|
"pmsuspended",
|
2019-01-20 16:30:15 +00:00
|
|
|
"disk-snapshot",
|
|
|
|
);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
|
|
|
/* Snapshot Def functions */
|
|
|
|
static void
|
|
|
|
virDomainSnapshotDiskDefClear(virDomainSnapshotDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
VIR_FREE(disk->name);
|
2019-02-15 12:03:58 +00:00
|
|
|
virObjectUnref(disk->src);
|
2014-05-21 21:21:02 +00:00
|
|
|
disk->src = NULL;
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
|
2018-09-04 14:02:43 +00:00
|
|
|
void
|
|
|
|
virDomainSnapshotDiskDefFree(virDomainSnapshotDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
if (!disk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virDomainSnapshotDiskDefClear(disk);
|
|
|
|
VIR_FREE(disk);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-09 14:59:06 +00:00
|
|
|
/* Allocate a new virDomainSnapshotDef; free with virObjectUnref() */
|
2019-05-08 18:30:38 +00:00
|
|
|
virDomainSnapshotDefPtr
|
|
|
|
virDomainSnapshotDefNew(void)
|
|
|
|
{
|
2019-05-09 14:59:06 +00:00
|
|
|
if (virDomainSnapshotInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2019-10-17 08:10:10 +00:00
|
|
|
return virObjectNew(virDomainSnapshotDefClass);
|
2019-05-08 18:30:38 +00:00
|
|
|
}
|
|
|
|
|
2019-05-09 14:59:06 +00:00
|
|
|
static void
|
|
|
|
virDomainSnapshotDefDispose(void *obj)
|
2012-08-14 00:09:12 +00:00
|
|
|
{
|
2019-05-09 14:59:06 +00:00
|
|
|
virDomainSnapshotDefPtr def = obj;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
VIR_FREE(def->file);
|
2012-08-14 00:09:12 +00:00
|
|
|
for (i = 0; i < def->ndisks; i++)
|
|
|
|
virDomainSnapshotDiskDefClear(&def->disks[i]);
|
|
|
|
VIR_FREE(def->disks);
|
2017-06-01 22:44:46 +00:00
|
|
|
virObjectUnref(def->cookie);
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
|
2018-09-04 13:42:42 +00:00
|
|
|
int
|
2012-08-14 00:09:12 +00:00
|
|
|
virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
2014-11-11 10:35:25 +00:00
|
|
|
xmlXPathContextPtr ctxt,
|
2017-08-30 15:35:34 +00:00
|
|
|
virDomainSnapshotDiskDefPtr def,
|
2017-12-12 16:55:03 +00:00
|
|
|
unsigned int flags,
|
|
|
|
virDomainXMLOptionPtr xmlopt)
|
2012-08-14 00:09:12 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *snapshot = NULL;
|
2013-11-12 13:15:51 +00:00
|
|
|
char *type = NULL;
|
2015-04-10 09:55:43 +00:00
|
|
|
char *driver = NULL;
|
2012-08-14 00:09:12 +00:00
|
|
|
xmlNodePtr cur;
|
2020-07-28 19:47:48 +00:00
|
|
|
VIR_XPATH_NODE_AUTORESTORE(ctxt)
|
2015-04-10 09:55:43 +00:00
|
|
|
|
|
|
|
ctxt->node = node;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2020-09-22 09:04:17 +00:00
|
|
|
def->src = virStorageSourceNew();
|
2012-08-14 00:09:12 +00:00
|
|
|
def->name = virXMLPropString(node, "name");
|
|
|
|
if (!def->name) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing name from disk snapshot element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
snapshot = virXMLPropString(node, "snapshot");
|
|
|
|
if (snapshot) {
|
2012-08-13 22:59:57 +00:00
|
|
|
def->snapshot = virDomainSnapshotLocationTypeFromString(snapshot);
|
2012-08-14 00:09:12 +00:00
|
|
|
if (def->snapshot <= 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-08-14 00:09:12 +00:00
|
|
|
_("unknown disk snapshot setting '%s'"),
|
|
|
|
snapshot);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-12 13:15:51 +00:00
|
|
|
if ((type = virXMLPropString(node, "type"))) {
|
2014-05-21 21:21:02 +00:00
|
|
|
if ((def->src->type = virStorageTypeFromString(type)) <= 0 ||
|
|
|
|
def->src->type == VIR_STORAGE_TYPE_VOLUME ||
|
|
|
|
def->src->type == VIR_STORAGE_TYPE_DIR) {
|
2013-11-12 13:15:51 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("unknown disk snapshot type '%s'"), type);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
2014-05-21 21:21:02 +00:00
|
|
|
def->src->type = VIR_STORAGE_TYPE_FILE;
|
2013-11-12 13:15:51 +00:00
|
|
|
}
|
2013-11-12 10:37:04 +00:00
|
|
|
|
2015-04-10 09:55:43 +00:00
|
|
|
if ((cur = virXPathNode("./source", ctxt)) &&
|
2019-03-11 09:47:53 +00:00
|
|
|
virDomainStorageSourceParse(cur, ctxt, def->src, flags, xmlopt) < 0)
|
2015-04-10 09:55:43 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2018-09-04 13:48:48 +00:00
|
|
|
if ((driver = virXPathString("string(./driver/@type)", ctxt)) &&
|
|
|
|
(def->src->format = virStorageFileFormatTypeFromString(driver)) <= 0) {
|
2015-04-10 09:55:43 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2018-09-04 13:48:48 +00:00
|
|
|
_("unknown disk snapshot driver '%s'"), driver);
|
2015-04-10 09:55:43 +00:00
|
|
|
goto cleanup;
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
|
2014-08-06 13:17:00 +00:00
|
|
|
/* validate that the passed path is absolute */
|
2016-12-16 17:30:39 +00:00
|
|
|
if (virStorageSourceIsRelative(def->src)) {
|
2014-08-06 13:17:00 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("disk snapshot image path '%s' must be absolute"),
|
|
|
|
def->src->path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-05-21 21:21:02 +00:00
|
|
|
if (!def->snapshot && (def->src->path || def->src->format))
|
2012-08-13 22:59:57 +00:00
|
|
|
def->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2015-04-10 09:55:43 +00:00
|
|
|
|
|
|
|
VIR_FREE(driver);
|
2012-08-14 00:09:12 +00:00
|
|
|
VIR_FREE(snapshot);
|
2013-11-12 13:15:51 +00:00
|
|
|
VIR_FREE(type);
|
2012-08-14 00:09:12 +00:00
|
|
|
if (ret < 0)
|
|
|
|
virDomainSnapshotDiskDefClear(def);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flags is bitwise-or of virDomainSnapshotParseFlags.
|
2019-11-27 13:10:21 +00:00
|
|
|
* If flags does not include
|
snapshot: Drop virDomainSnapshotDef.current
The only use for the 'current' member of virDomainSnapshotDef was with
the PARSE/FORMAT_INTERNAL flag for controlling an internal-use
<active> element marking whether a particular snapshot definition was
current, and even then, only by the qemu driver on output, and by qemu
and test driver on input. But this duplicates vm->snapshot_current,
and gets in the way of potential simplifications to have qemu store a
single file for all snapshots rather than one file per snapshot. Get
rid of the member by adding a bool* parameter during parse (ignored if
the PARSE_INTERNAL flag is not set), and by adding a new flag during
format (if FORMAT_INTERNAL is set, the value printed in <active>
depends on the new FORMAT_CURRENT).
Then update the qemu driver accordingly, which involves hoisting
assignments to vm->current_snapshot to occur prior to any point where
a snapshot XML file is written (although qemu kept
vm->current_snapshot and snapshot->def_current in sync by the end of
the function, they were not always identical in the middle of
functions, so the shuffling gets a bit interesting). Later patches
will clean up some of that confusing churn to vm->current_snapshot.
Note: even if later patches refactor qemu to no longer use
FORMAT_INTERNAL for output (by storing bulk snapshot XML instead), we
will always need PARSE_INTERNAL for input (because on upgrade, a new
libvirt still has to parse XML left from a previous libvirt).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
2019-03-19 03:56:19 +00:00
|
|
|
* VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL, then current is ignored.
|
2012-08-14 00:09:12 +00:00
|
|
|
*/
|
2013-08-07 14:34:40 +00:00
|
|
|
static virDomainSnapshotDefPtr
|
|
|
|
virDomainSnapshotDefParse(xmlXPathContextPtr ctxt,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
2019-08-06 12:19:35 +00:00
|
|
|
void *parseOpaque,
|
snapshot: Drop virDomainSnapshotDef.current
The only use for the 'current' member of virDomainSnapshotDef was with
the PARSE/FORMAT_INTERNAL flag for controlling an internal-use
<active> element marking whether a particular snapshot definition was
current, and even then, only by the qemu driver on output, and by qemu
and test driver on input. But this duplicates vm->snapshot_current,
and gets in the way of potential simplifications to have qemu store a
single file for all snapshots rather than one file per snapshot. Get
rid of the member by adding a bool* parameter during parse (ignored if
the PARSE_INTERNAL flag is not set), and by adding a new flag during
format (if FORMAT_INTERNAL is set, the value printed in <active>
depends on the new FORMAT_CURRENT).
Then update the qemu driver accordingly, which involves hoisting
assignments to vm->current_snapshot to occur prior to any point where
a snapshot XML file is written (although qemu kept
vm->current_snapshot and snapshot->def_current in sync by the end of
the function, they were not always identical in the middle of
functions, so the shuffling gets a bit interesting). Later patches
will clean up some of that confusing churn to vm->current_snapshot.
Note: even if later patches refactor qemu to no longer use
FORMAT_INTERNAL for output (by storing bulk snapshot XML instead), we
will always need PARSE_INTERNAL for input (because on upgrade, a new
libvirt still has to parse XML left from a previous libvirt).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
2019-03-19 03:56:19 +00:00
|
|
|
bool *current,
|
2013-08-07 14:34:40 +00:00
|
|
|
unsigned int flags)
|
2012-08-14 00:09:12 +00:00
|
|
|
{
|
|
|
|
virDomainSnapshotDefPtr def = NULL;
|
|
|
|
virDomainSnapshotDefPtr ret = NULL;
|
|
|
|
xmlNodePtr *nodes = NULL;
|
2019-08-29 20:55:43 +00:00
|
|
|
xmlNodePtr inactiveDomNode = NULL;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
|
|
|
int n;
|
2020-06-11 03:26:29 +00:00
|
|
|
char *state = NULL;
|
2012-08-14 00:09:12 +00:00
|
|
|
int active;
|
|
|
|
char *tmp;
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
char *memorySnapshot = NULL;
|
|
|
|
char *memoryFile = NULL;
|
|
|
|
bool offline = !!(flags & VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE);
|
2017-06-01 22:44:46 +00:00
|
|
|
virSaveCookieCallbacksPtr saveCookie = virDomainXMLOptionGetSaveCookie(xmlopt);
|
2019-08-29 20:55:43 +00:00
|
|
|
int domainflags = VIR_DOMAIN_DEF_PARSE_INACTIVE |
|
|
|
|
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2019-05-08 18:30:38 +00:00
|
|
|
if (!(def = virDomainSnapshotDefNew()))
|
|
|
|
return NULL;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.name = virXPathString("string(./name)", ctxt);
|
|
|
|
if (def->parent.name == NULL) {
|
2012-08-14 00:09:12 +00:00
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("a redefined snapshot must have a name"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.description = virXPathString("string(./description)", ctxt);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE) {
|
|
|
|
if (virXPathLongLong("string(./creationTime)", ctxt,
|
2019-05-08 22:10:58 +00:00
|
|
|
&def->parent.creationTime) < 0) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing creationTime from existing snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.parent_name = virXPathString("string(./parent/name)", ctxt);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
|
|
|
state = virXPathString("string(./state)", ctxt);
|
|
|
|
if (state == NULL) {
|
|
|
|
/* there was no state in an existing snapshot; this
|
|
|
|
* should never happen
|
|
|
|
*/
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing state from existing snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
def->state = virDomainSnapshotStateTypeFromString(state);
|
snapshot: Don't expose testsuite-only state in snapshot XML
None of the existing drivers actually use the 0-valued 'nostate'
snapshot state; rather, it was a fluke of implementation. In fact,
some drivers, like qemu, actively reject 'nostate' as invalid during a
snapshot redefine. Normally, a driver computes the state post-parse
from the current domain, and thus virDomainSnapshotGetXMLDesc() will
never expose the state. However, since the testsuite lacks any
associated domain to copy state from, and lacks post-parse processing
that normal drivers have, the testsuite output had several spots with
the state, coupled with a regex filter to ignore the oddity.
It is better to follow the lead of other XML defaults, by not
outputting anything during format if post-parse defaults have not been
applied, and rejecting the default value during parsing. The testsuite
needs a bit of an update, by adding another flag for when to simulate
a post-parse action of setting a snapshot state, but none of the
drivers are impacted other than rejecting XML that was previously
already suspicious in nature.
Similarly, don't expose creation time 0 (for now, only possible if a
user redefined a snapshot to claim creation at the Epoch, but also
happens once setting the creation time is deferred to a post-parse
handler).
This is also a step towards cleaning up snapshot_conf.c to separate
its existing post-parse work (namely, setting the creationTime and
default snapshot name) from the pure parsing work, so that we can get
rid of the testsuite hack of regex filtering of the XML and instead
have more accurate testing of our parser/formatter code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Cole Robinson <crobinso@redhat.com>
2019-04-16 22:44:38 +00:00
|
|
|
if (def->state <= 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-08-14 00:09:12 +00:00
|
|
|
_("Invalid state '%s' in domain snapshot XML"),
|
|
|
|
state);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2019-02-26 20:14:36 +00:00
|
|
|
offline = (def->state == VIR_DOMAIN_SNAPSHOT_SHUTOFF ||
|
|
|
|
def->state == VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
|
|
|
/* Older snapshots were created with just <domain>/<uuid>, and
|
|
|
|
* lack domain/@type. In that case, leave dom NULL, and
|
|
|
|
* clients will have to decide between best effort
|
|
|
|
* initialization or outright failure. */
|
|
|
|
if ((tmp = virXPathString("string(./domain/@type)", ctxt))) {
|
|
|
|
xmlNodePtr domainNode = virXPathNode("./domain", ctxt);
|
|
|
|
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
if (!domainNode) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing domain in snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.dom = virDomainDefParseNode(ctxt->node->doc, domainNode,
|
2019-11-27 12:29:21 +00:00
|
|
|
xmlopt, parseOpaque,
|
2019-08-06 12:19:35 +00:00
|
|
|
domainflags);
|
2019-05-08 22:10:58 +00:00
|
|
|
if (!def->parent.dom)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
VIR_WARN("parsing older snapshot that lacks domain");
|
|
|
|
}
|
2019-08-29 20:55:43 +00:00
|
|
|
|
|
|
|
/* /inactiveDomain entry saves the config XML present in a running
|
|
|
|
* VM. In case of absent, leave parent.inactiveDom NULL and use
|
|
|
|
* parent.dom for config and live XML. */
|
|
|
|
if ((inactiveDomNode = virXPathNode("./inactiveDomain", ctxt))) {
|
|
|
|
def->parent.inactiveDom = virDomainDefParseNode(ctxt->node->doc, inactiveDomNode,
|
2019-11-27 12:29:21 +00:00
|
|
|
xmlopt, NULL, domainflags);
|
2019-08-29 20:55:43 +00:00
|
|
|
if (!def->parent.inactiveDom)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2019-05-08 22:10:58 +00:00
|
|
|
} else if (virDomainXMLOptionRunMomentPostParse(xmlopt, &def->parent) < 0) {
|
2019-04-15 22:25:52 +00:00
|
|
|
goto cleanup;
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
memorySnapshot = virXPathString("string(./memory/@snapshot)", ctxt);
|
|
|
|
memoryFile = virXPathString("string(./memory/@file)", ctxt);
|
|
|
|
if (memorySnapshot) {
|
|
|
|
def->memory = virDomainSnapshotLocationTypeFromString(memorySnapshot);
|
|
|
|
if (def->memory <= 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
_("unknown memory snapshot setting '%s'"),
|
|
|
|
memorySnapshot);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (memoryFile &&
|
|
|
|
def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("memory filename '%s' requires external snapshot"),
|
|
|
|
memoryFile);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-11-15 23:38:13 +00:00
|
|
|
if (!memoryFile &&
|
|
|
|
def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("external memory snapshots require a filename"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
} else if (memoryFile) {
|
|
|
|
def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
|
|
|
|
} else if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE) {
|
|
|
|
def->memory = (offline ?
|
|
|
|
VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
|
|
|
|
VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL);
|
|
|
|
}
|
|
|
|
if (offline && def->memory &&
|
|
|
|
def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_NONE) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2013-01-25 10:50:43 +00:00
|
|
|
_("memory state cannot be saved with offline or "
|
|
|
|
"disk-only snapshot"));
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2019-10-16 11:43:01 +00:00
|
|
|
def->file = g_steal_pointer(&memoryFile);
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
|
2014-08-06 13:17:00 +00:00
|
|
|
/* verify that memory path is absolute */
|
|
|
|
if (def->file && def->file[0] != '/') {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("memory snapshot file path (%s) must be absolute"),
|
|
|
|
def->file);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
if ((n = virXPathNodeSet("./disks/*", ctxt, &nodes)) < 0)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_DISKS) {
|
2013-09-25 08:34:25 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->disks, n) < 0)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
2013-09-25 08:34:25 +00:00
|
|
|
def->ndisks = n;
|
2012-08-14 00:09:12 +00:00
|
|
|
for (i = 0; i < def->ndisks; i++) {
|
2017-12-12 16:55:03 +00:00
|
|
|
if (virDomainSnapshotDiskDefParseXML(nodes[i], ctxt, &def->disks[i],
|
|
|
|
flags, xmlopt) < 0)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
} else if (n) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
|
|
|
|
_("unable to handle disk requests in snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL) {
|
snapshot: Drop virDomainSnapshotDef.current
The only use for the 'current' member of virDomainSnapshotDef was with
the PARSE/FORMAT_INTERNAL flag for controlling an internal-use
<active> element marking whether a particular snapshot definition was
current, and even then, only by the qemu driver on output, and by qemu
and test driver on input. But this duplicates vm->snapshot_current,
and gets in the way of potential simplifications to have qemu store a
single file for all snapshots rather than one file per snapshot. Get
rid of the member by adding a bool* parameter during parse (ignored if
the PARSE_INTERNAL flag is not set), and by adding a new flag during
format (if FORMAT_INTERNAL is set, the value printed in <active>
depends on the new FORMAT_CURRENT).
Then update the qemu driver accordingly, which involves hoisting
assignments to vm->current_snapshot to occur prior to any point where
a snapshot XML file is written (although qemu kept
vm->current_snapshot and snapshot->def_current in sync by the end of
the function, they were not always identical in the middle of
functions, so the shuffling gets a bit interesting). Later patches
will clean up some of that confusing churn to vm->current_snapshot.
Note: even if later patches refactor qemu to no longer use
FORMAT_INTERNAL for output (by storing bulk snapshot XML instead), we
will always need PARSE_INTERNAL for input (because on upgrade, a new
libvirt still has to parse XML left from a previous libvirt).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
2019-03-19 03:56:19 +00:00
|
|
|
if (!current) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("internal parse requested with NULL current"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-08-14 00:09:12 +00:00
|
|
|
if (virXPathInt("string(./active)", ctxt, &active) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Could not find 'active' element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
snapshot: Drop virDomainSnapshotDef.current
The only use for the 'current' member of virDomainSnapshotDef was with
the PARSE/FORMAT_INTERNAL flag for controlling an internal-use
<active> element marking whether a particular snapshot definition was
current, and even then, only by the qemu driver on output, and by qemu
and test driver on input. But this duplicates vm->snapshot_current,
and gets in the way of potential simplifications to have qemu store a
single file for all snapshots rather than one file per snapshot. Get
rid of the member by adding a bool* parameter during parse (ignored if
the PARSE_INTERNAL flag is not set), and by adding a new flag during
format (if FORMAT_INTERNAL is set, the value printed in <active>
depends on the new FORMAT_CURRENT).
Then update the qemu driver accordingly, which involves hoisting
assignments to vm->current_snapshot to occur prior to any point where
a snapshot XML file is written (although qemu kept
vm->current_snapshot and snapshot->def_current in sync by the end of
the function, they were not always identical in the middle of
functions, so the shuffling gets a bit interesting). Later patches
will clean up some of that confusing churn to vm->current_snapshot.
Note: even if later patches refactor qemu to no longer use
FORMAT_INTERNAL for output (by storing bulk snapshot XML instead), we
will always need PARSE_INTERNAL for input (because on upgrade, a new
libvirt still has to parse XML left from a previous libvirt).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
2019-03-19 03:56:19 +00:00
|
|
|
*current = active != 0;
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
|
2017-06-01 22:44:46 +00:00
|
|
|
if (!offline && virSaveCookieParse(ctxt, &def->cookie, saveCookie) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2019-10-16 11:43:01 +00:00
|
|
|
ret = g_steal_pointer(&def);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2012-08-14 00:09:12 +00:00
|
|
|
VIR_FREE(state);
|
|
|
|
VIR_FREE(nodes);
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
VIR_FREE(memorySnapshot);
|
|
|
|
VIR_FREE(memoryFile);
|
2019-05-09 14:59:06 +00:00
|
|
|
virObjectUnref(def);
|
2013-08-07 14:34:40 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainSnapshotDefPtr
|
|
|
|
virDomainSnapshotDefParseNode(xmlDocPtr xml,
|
|
|
|
xmlNodePtr root,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
2019-08-06 12:19:35 +00:00
|
|
|
void *parseOpaque,
|
snapshot: Drop virDomainSnapshotDef.current
The only use for the 'current' member of virDomainSnapshotDef was with
the PARSE/FORMAT_INTERNAL flag for controlling an internal-use
<active> element marking whether a particular snapshot definition was
current, and even then, only by the qemu driver on output, and by qemu
and test driver on input. But this duplicates vm->snapshot_current,
and gets in the way of potential simplifications to have qemu store a
single file for all snapshots rather than one file per snapshot. Get
rid of the member by adding a bool* parameter during parse (ignored if
the PARSE_INTERNAL flag is not set), and by adding a new flag during
format (if FORMAT_INTERNAL is set, the value printed in <active>
depends on the new FORMAT_CURRENT).
Then update the qemu driver accordingly, which involves hoisting
assignments to vm->current_snapshot to occur prior to any point where
a snapshot XML file is written (although qemu kept
vm->current_snapshot and snapshot->def_current in sync by the end of
the function, they were not always identical in the middle of
functions, so the shuffling gets a bit interesting). Later patches
will clean up some of that confusing churn to vm->current_snapshot.
Note: even if later patches refactor qemu to no longer use
FORMAT_INTERNAL for output (by storing bulk snapshot XML instead), we
will always need PARSE_INTERNAL for input (because on upgrade, a new
libvirt still has to parse XML left from a previous libvirt).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
2019-03-19 03:56:19 +00:00
|
|
|
bool *current,
|
2013-08-07 14:34:40 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2013-08-07 14:34:40 +00:00
|
|
|
|
2017-08-14 12:31:52 +00:00
|
|
|
if (!virXMLNodeNameEqual(root, "domainsnapshot")) {
|
2013-08-07 14:34:40 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s", _("domainsnapshot"));
|
2019-09-16 10:52:57 +00:00
|
|
|
return NULL;
|
2013-08-07 14:34:40 +00:00
|
|
|
}
|
|
|
|
|
2019-07-06 03:02:03 +00:00
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_VALIDATE) {
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *schema = NULL;
|
2019-07-06 03:02:03 +00:00
|
|
|
|
|
|
|
schema = virFileFindResource("domainsnapshot.rng",
|
|
|
|
abs_top_srcdir "/docs/schemas",
|
|
|
|
PKGDATADIR "/schemas");
|
|
|
|
if (!schema)
|
2019-09-16 10:52:57 +00:00
|
|
|
return NULL;
|
2019-07-06 03:02:03 +00:00
|
|
|
if (virXMLValidateAgainstSchema(schema, xml) < 0)
|
2019-09-16 10:52:57 +00:00
|
|
|
return NULL;
|
2019-07-06 03:02:03 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 06:33:58 +00:00
|
|
|
if (!(ctxt = virXMLXPathContextNew(xml)))
|
2019-09-16 10:52:57 +00:00
|
|
|
return NULL;
|
2013-08-07 14:34:40 +00:00
|
|
|
|
|
|
|
ctxt->node = root;
|
2019-11-27 13:10:21 +00:00
|
|
|
return virDomainSnapshotDefParse(ctxt, xmlopt, parseOpaque, current, flags);
|
2013-08-07 14:34:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virDomainSnapshotDefPtr
|
|
|
|
virDomainSnapshotDefParseString(const char *xmlStr,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
2019-08-06 12:19:35 +00:00
|
|
|
void *parseOpaque,
|
snapshot: Drop virDomainSnapshotDef.current
The only use for the 'current' member of virDomainSnapshotDef was with
the PARSE/FORMAT_INTERNAL flag for controlling an internal-use
<active> element marking whether a particular snapshot definition was
current, and even then, only by the qemu driver on output, and by qemu
and test driver on input. But this duplicates vm->snapshot_current,
and gets in the way of potential simplifications to have qemu store a
single file for all snapshots rather than one file per snapshot. Get
rid of the member by adding a bool* parameter during parse (ignored if
the PARSE_INTERNAL flag is not set), and by adding a new flag during
format (if FORMAT_INTERNAL is set, the value printed in <active>
depends on the new FORMAT_CURRENT).
Then update the qemu driver accordingly, which involves hoisting
assignments to vm->current_snapshot to occur prior to any point where
a snapshot XML file is written (although qemu kept
vm->current_snapshot and snapshot->def_current in sync by the end of
the function, they were not always identical in the middle of
functions, so the shuffling gets a bit interesting). Later patches
will clean up some of that confusing churn to vm->current_snapshot.
Note: even if later patches refactor qemu to no longer use
FORMAT_INTERNAL for output (by storing bulk snapshot XML instead), we
will always need PARSE_INTERNAL for input (because on upgrade, a new
libvirt still has to parse XML left from a previous libvirt).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
2019-03-19 03:56:19 +00:00
|
|
|
bool *current,
|
2013-08-07 14:34:40 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainSnapshotDefPtr ret = NULL;
|
|
|
|
xmlDocPtr xml;
|
|
|
|
int keepBlanksDefault = xmlKeepBlanksDefault(0);
|
|
|
|
|
|
|
|
if ((xml = virXMLParse(NULL, xmlStr, _("(domain_snapshot)")))) {
|
|
|
|
xmlKeepBlanksDefault(keepBlanksDefault);
|
|
|
|
ret = virDomainSnapshotDefParseNode(xml, xmlDocGetRootElement(xml),
|
2019-11-27 13:10:21 +00:00
|
|
|
xmlopt, parseOpaque,
|
2019-08-06 12:19:35 +00:00
|
|
|
current, flags);
|
2013-08-07 14:34:40 +00:00
|
|
|
xmlFreeDoc(xml);
|
|
|
|
}
|
|
|
|
xmlKeepBlanksDefault(keepBlanksDefault);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-02-11 08:07:05 +00:00
|
|
|
|
2019-03-07 22:12:24 +00:00
|
|
|
/* Perform sanity checking on a redefined snapshot definition. If
|
2019-05-08 22:10:58 +00:00
|
|
|
* @other is non-NULL, this may include swapping def->parent.dom from other
|
2019-03-07 22:12:24 +00:00
|
|
|
* into def. */
|
2019-03-15 02:12:51 +00:00
|
|
|
int
|
2019-03-07 22:12:24 +00:00
|
|
|
virDomainSnapshotRedefineValidate(virDomainSnapshotDefPtr def,
|
|
|
|
const unsigned char *domain_uuid,
|
2019-03-22 04:45:25 +00:00
|
|
|
virDomainMomentObjPtr other,
|
2019-03-07 22:12:24 +00:00
|
|
|
virDomainXMLOptionPtr xmlopt,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
|
|
|
|
bool align_match = true;
|
|
|
|
bool external = def->state == VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT ||
|
|
|
|
virDomainSnapshotDefIsExternal(def);
|
|
|
|
|
|
|
|
if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) && !external) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("disk-only flag for snapshot %s requires "
|
|
|
|
"disk-snapshot state"),
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.name);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-05-08 22:10:58 +00:00
|
|
|
if (def->parent.dom && memcmp(def->parent.dom->uuid, domain_uuid,
|
2019-03-22 02:02:19 +00:00
|
|
|
VIR_UUID_BUFLEN)) {
|
2019-03-07 22:12:24 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(domain_uuid, uuidstr);
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("definition for snapshot %s must use uuid %s"),
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.name, uuidstr);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (other) {
|
2019-03-18 21:13:50 +00:00
|
|
|
virDomainSnapshotDefPtr otherdef = virDomainSnapshotObjGetDef(other);
|
|
|
|
|
|
|
|
if ((otherdef->state == VIR_DOMAIN_SNAPSHOT_RUNNING ||
|
|
|
|
otherdef->state == VIR_DOMAIN_SNAPSHOT_PAUSED) !=
|
2019-03-07 22:12:24 +00:00
|
|
|
(def->state == VIR_DOMAIN_SNAPSHOT_RUNNING ||
|
|
|
|
def->state == VIR_DOMAIN_SNAPSHOT_PAUSED)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("cannot change between online and offline "
|
|
|
|
"snapshot state in snapshot %s"),
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.name);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-03-18 21:13:50 +00:00
|
|
|
if ((otherdef->state == VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT) !=
|
2019-03-07 22:12:24 +00:00
|
|
|
(def->state == VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("cannot change between disk only and "
|
|
|
|
"full system in snapshot %s"),
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.name);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (otherdef->parent.dom) {
|
|
|
|
if (def->parent.dom) {
|
|
|
|
if (!virDomainDefCheckABIStability(otherdef->parent.dom,
|
|
|
|
def->parent.dom, xmlopt))
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
/* Transfer the domain def */
|
2019-10-16 11:43:01 +00:00
|
|
|
def->parent.dom = g_steal_pointer(&otherdef->parent.dom);
|
2019-03-07 22:12:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (def->parent.dom) {
|
2019-03-07 22:12:24 +00:00
|
|
|
if (external) {
|
|
|
|
align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
|
|
|
|
align_match = false;
|
|
|
|
}
|
|
|
|
if (virDomainSnapshotAlignDisks(def, align_location,
|
|
|
|
align_match) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-11 08:07:05 +00:00
|
|
|
/**
|
|
|
|
* virDomainSnapshotDefAssignExternalNames:
|
|
|
|
* @def: snapshot def object
|
|
|
|
*
|
|
|
|
* Generate default external file names for snapshot targets. Returns 0 on
|
|
|
|
* success, -1 on error.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virDomainSnapshotDefAssignExternalNames(virDomainSnapshotDefPtr def)
|
|
|
|
{
|
2016-02-11 08:42:36 +00:00
|
|
|
const char *origpath;
|
|
|
|
char *tmppath;
|
|
|
|
char *tmp;
|
|
|
|
struct stat sb;
|
2016-02-11 08:07:05 +00:00
|
|
|
size_t i;
|
2016-02-11 08:57:45 +00:00
|
|
|
size_t j;
|
2016-02-11 08:07:05 +00:00
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks; i++) {
|
|
|
|
virDomainSnapshotDiskDefPtr disk = &def->disks[i];
|
|
|
|
|
2016-02-11 08:42:36 +00:00
|
|
|
if (disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL ||
|
|
|
|
disk->src->path)
|
|
|
|
continue;
|
2016-02-11 08:07:05 +00:00
|
|
|
|
2016-02-11 08:42:36 +00:00
|
|
|
if (disk->src->type != VIR_STORAGE_TYPE_FILE) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("cannot generate external snapshot name "
|
|
|
|
"for disk '%s' on a '%s' device"),
|
|
|
|
disk->name, virStorageTypeToString(disk->src->type));
|
|
|
|
return -1;
|
|
|
|
}
|
2016-02-11 08:07:05 +00:00
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (!(origpath = virDomainDiskGetSource(def->parent.dom->disks[i]))) {
|
2016-02-11 08:42:36 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("cannot generate external snapshot name "
|
|
|
|
"for disk '%s' without source"),
|
|
|
|
disk->name);
|
|
|
|
return -1;
|
2016-02-11 08:07:05 +00:00
|
|
|
}
|
|
|
|
|
2016-02-11 08:42:36 +00:00
|
|
|
if (stat(origpath, &sb) < 0 || !S_ISREG(sb.st_mode)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("source for disk '%s' is not a regular "
|
|
|
|
"file; refusing to generate external "
|
|
|
|
"snapshot name"),
|
|
|
|
disk->name);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-02-11 08:07:05 +00:00
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
tmppath = g_strdup(origpath);
|
2016-02-11 08:42:36 +00:00
|
|
|
|
|
|
|
/* drop suffix of the file name */
|
|
|
|
if ((tmp = strrchr(tmppath, '.')) && !strchr(tmp, '/'))
|
|
|
|
*tmp = '\0';
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
disk->src->path = g_strdup_printf("%s.%s", tmppath, def->parent.name);
|
2016-02-11 08:42:36 +00:00
|
|
|
|
|
|
|
VIR_FREE(tmppath);
|
2016-02-11 08:57:45 +00:00
|
|
|
|
|
|
|
/* verify that we didn't generate a duplicate name */
|
|
|
|
for (j = 0; j < i; j++) {
|
|
|
|
if (STREQ_NULLABLE(disk->src->path, def->disks[j].src->path)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("cannot generate external snapshot name for "
|
|
|
|
"disk '%s': collision with disk '%s'"),
|
|
|
|
disk->name, def->disks[j].name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2016-02-11 08:42:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2016-02-11 08:07:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-14 00:09:12 +00:00
|
|
|
static int
|
2016-02-11 07:42:00 +00:00
|
|
|
virDomainSnapshotCompareDiskIndex(const void *a, const void *b)
|
2012-08-14 00:09:12 +00:00
|
|
|
{
|
|
|
|
const virDomainSnapshotDiskDef *diska = a;
|
|
|
|
const virDomainSnapshotDiskDef *diskb = b;
|
|
|
|
|
|
|
|
/* Integer overflow shouldn't be a problem here. */
|
2015-04-14 11:35:29 +00:00
|
|
|
return diska->idx - diskb->idx;
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
/* Align def->disks to def->parent.dom. Sort the list of def->disks,
|
2012-08-14 00:09:12 +00:00
|
|
|
* filling in any missing disks or snapshot state defaults given by
|
|
|
|
* the domain, with a fallback to a passed in default. Convert paths
|
|
|
|
* to disk targets for uniformity. Issue an error and return -1 if
|
|
|
|
* any def->disks[n]->name appears more than once or does not map to
|
2012-10-23 15:12:24 +00:00
|
|
|
* dom->disks. If require_match, also ensure that there is no
|
|
|
|
* conflicting requests for both internal and external snapshots. */
|
2012-08-14 00:09:12 +00:00
|
|
|
int
|
|
|
|
virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
|
|
|
|
int default_snapshot,
|
|
|
|
bool require_match)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
virBitmapPtr map = NULL;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-08-14 00:09:12 +00:00
|
|
|
int ndisks;
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (!def->parent.dom) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing domain in snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (def->ndisks > def->parent.dom->ndisks) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("too many disk snapshot requests for domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unlikely to have a guest without disks but technically possible. */
|
2019-05-08 22:10:58 +00:00
|
|
|
if (!def->parent.dom->ndisks) {
|
2012-08-14 00:09:12 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (!(map = virBitmapNew(def->parent.dom->ndisks)))
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Double check requested disks. */
|
|
|
|
for (i = 0; i < def->ndisks; i++) {
|
|
|
|
virDomainSnapshotDiskDefPtr disk = &def->disks[i];
|
2019-05-08 22:10:58 +00:00
|
|
|
int idx = virDomainDiskIndexByName(def->parent.dom, disk->name, false);
|
2012-08-14 00:09:12 +00:00
|
|
|
int disk_snapshot;
|
|
|
|
|
|
|
|
if (idx < 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("no disk named '%s'"), disk->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-03-11 15:41:57 +00:00
|
|
|
if (virBitmapIsBitSet(map, idx)) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("disk '%s' specified twice"),
|
|
|
|
disk->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
ignore_value(virBitmapSetBit(map, idx));
|
2015-04-14 11:35:29 +00:00
|
|
|
disk->idx = idx;
|
2012-10-23 15:12:24 +00:00
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
disk_snapshot = def->parent.dom->disks[idx]->snapshot;
|
2012-08-14 00:09:12 +00:00
|
|
|
if (!disk->snapshot) {
|
2012-10-23 15:12:24 +00:00
|
|
|
if (disk_snapshot &&
|
|
|
|
(!require_match ||
|
|
|
|
disk_snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE))
|
|
|
|
disk->snapshot = disk_snapshot;
|
|
|
|
else
|
|
|
|
disk->snapshot = default_snapshot;
|
|
|
|
} else if (require_match &&
|
|
|
|
disk->snapshot != default_snapshot &&
|
|
|
|
!(disk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE &&
|
|
|
|
disk_snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)) {
|
2012-08-13 22:59:57 +00:00
|
|
|
const char *tmp;
|
|
|
|
|
2012-10-23 15:12:24 +00:00
|
|
|
tmp = virDomainSnapshotLocationTypeToString(default_snapshot);
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("disk '%s' must use snapshot mode '%s'"),
|
|
|
|
disk->name, tmp);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-05-21 21:21:02 +00:00
|
|
|
if (disk->src->path &&
|
2012-08-13 22:59:57 +00:00
|
|
|
disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("file '%s' for disk '%s' requires "
|
|
|
|
"use of external snapshot mode"),
|
2014-05-21 21:21:02 +00:00
|
|
|
disk->src->path, disk->name);
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2019-05-08 22:10:58 +00:00
|
|
|
if (STRNEQ(disk->name, def->parent.dom->disks[idx]->dst)) {
|
2012-08-14 00:09:12 +00:00
|
|
|
VIR_FREE(disk->name);
|
2019-10-20 11:49:46 +00:00
|
|
|
disk->name = g_strdup(def->parent.dom->disks[idx]->dst);
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Provide defaults for all remaining disks. */
|
|
|
|
ndisks = def->ndisks;
|
|
|
|
if (VIR_EXPAND_N(def->disks, def->ndisks,
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.dom->ndisks - def->ndisks) < 0)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
for (i = 0; i < def->parent.dom->ndisks; i++) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virDomainSnapshotDiskDefPtr disk;
|
|
|
|
|
2015-03-11 15:41:57 +00:00
|
|
|
if (virBitmapIsBitSet(map, i))
|
2012-08-14 00:09:12 +00:00
|
|
|
continue;
|
|
|
|
disk = &def->disks[ndisks++];
|
2020-09-22 09:04:17 +00:00
|
|
|
disk->src = virStorageSourceNew();
|
2019-10-20 11:49:46 +00:00
|
|
|
disk->name = g_strdup(def->parent.dom->disks[i]->dst);
|
2015-04-14 11:35:29 +00:00
|
|
|
disk->idx = i;
|
2014-09-11 15:45:06 +00:00
|
|
|
|
|
|
|
/* Don't snapshot empty drives */
|
2019-05-08 22:10:58 +00:00
|
|
|
if (virStorageSourceIsEmpty(def->parent.dom->disks[i]->src))
|
2014-09-11 15:45:06 +00:00
|
|
|
disk->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
|
|
|
|
else
|
2019-05-08 22:10:58 +00:00
|
|
|
disk->snapshot = def->parent.dom->disks[i]->snapshot;
|
2014-09-11 15:45:06 +00:00
|
|
|
|
2014-05-21 21:21:02 +00:00
|
|
|
disk->src->type = VIR_STORAGE_TYPE_FILE;
|
2012-08-14 00:09:12 +00:00
|
|
|
if (!disk->snapshot)
|
|
|
|
disk->snapshot = default_snapshot;
|
|
|
|
}
|
|
|
|
|
2016-02-11 07:42:00 +00:00
|
|
|
qsort(&def->disks[0], def->ndisks, sizeof(def->disks[0]),
|
|
|
|
virDomainSnapshotCompareDiskIndex);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2016-02-11 08:07:05 +00:00
|
|
|
/* Generate default external file names for external snapshot locations */
|
|
|
|
if (virDomainSnapshotDefAssignExternalNames(def) < 0)
|
|
|
|
goto cleanup;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2012-08-14 00:09:12 +00:00
|
|
|
virBitmapFree(map);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-02-15 20:43:43 +00:00
|
|
|
|
|
|
|
/* Converts public VIR_DOMAIN_SNAPSHOT_XML_* into
|
|
|
|
* VIR_DOMAIN_SNAPSHOT_FORMAT_* flags, and silently ignores any other
|
|
|
|
* flags. */
|
|
|
|
unsigned int
|
|
|
|
virDomainSnapshotFormatConvertXMLFlags(unsigned int flags)
|
|
|
|
{
|
|
|
|
unsigned int formatFlags = 0;
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_XML_SECURE)
|
|
|
|
formatFlags |= VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE;
|
|
|
|
|
|
|
|
return formatFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-08 12:13:20 +00:00
|
|
|
static int
|
2013-05-16 06:24:56 +00:00
|
|
|
virDomainSnapshotDiskDefFormat(virBufferPtr buf,
|
2017-12-12 16:55:03 +00:00
|
|
|
virDomainSnapshotDiskDefPtr disk,
|
|
|
|
virDomainXMLOptionPtr xmlopt)
|
2013-05-16 06:24:56 +00:00
|
|
|
{
|
2014-05-21 21:21:02 +00:00
|
|
|
int type = disk->src->type;
|
2013-11-12 10:37:04 +00:00
|
|
|
|
2013-05-16 06:24:56 +00:00
|
|
|
if (!disk->name)
|
2017-11-08 12:13:20 +00:00
|
|
|
return 0;
|
2013-05-16 06:24:56 +00:00
|
|
|
|
2014-03-05 10:09:46 +00:00
|
|
|
virBufferEscapeString(buf, "<disk name='%s'", disk->name);
|
2013-05-16 06:24:56 +00:00
|
|
|
if (disk->snapshot > 0)
|
|
|
|
virBufferAsprintf(buf, " snapshot='%s'",
|
|
|
|
virDomainSnapshotLocationTypeToString(disk->snapshot));
|
2013-11-12 10:37:04 +00:00
|
|
|
|
2014-05-21 21:21:02 +00:00
|
|
|
if (!disk->src->path && disk->src->format == 0) {
|
2013-05-16 06:24:56 +00:00
|
|
|
virBufferAddLit(buf, "/>\n");
|
2017-11-08 12:13:20 +00:00
|
|
|
return 0;
|
2013-05-16 06:24:56 +00:00
|
|
|
}
|
|
|
|
|
conf: move host disk type to util/
A continuation of the migration of disk details to virstoragefile.
This patch moves a single enum, but converting the name has quite
a bit of fallout.
* src/conf/domain_conf.h (virDomainDiskType): Move...
* src/util/virstoragefile.h (virStorageType): ...and rename.
* src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr)
(virBhyveProcessBuildLoadCmd): Update clients.
* src/conf/domain_conf.c (virDomainDiskSourceDefParse)
(virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal)
(virDomainDiskDefFormat, virDomainDiskGetActualType)
(virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType):
Likewise.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML)
(virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat):
Likewise.
* src/esx/esx_driver.c (esxAutodetectSCSIControllerModel)
(esxDomainDefineXML): Likewise.
* src/locking/domain_lock.c (virDomainLockManagerAddDisk):
Likewise.
* src/lxc/lxc_controller.c
(virLXCControllerSetupLoopDeviceDisk)
(virLXCControllerSetupNBDDeviceDisk)
(virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk):
Likewise.
* src/parallels/parallels_driver.c (parallelsGetHddInfo):
Likewise.
* src/phyp/phyp_driver.c (phypDiskType): Likewise.
* src/qemu/qemu_command.c (qemuGetDriveSourceString)
(qemuDomainDiskGetSourceString, qemuBuildDriveStr)
(qemuBuildCommandLine, qemuParseCommandLineDisk)
(qemuParseCommandLine): Likewise.
* src/qemu/qemu_conf.c (qemuCheckSharedDevice)
(qemuTranslateDiskSourcePool)
(qemuTranslateSnapshotDiskSourcePool): Likewise.
* src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse)
(qemuDomainDetermineDiskChain): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo)
(qemuDomainSnapshotPrepareDiskExternalBackingInactive)
(qemuDomainSnapshotPrepareDiskExternalBackingActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayInactive)
(qemuDomainSnapshotPrepareDiskInternal)
(qemuDomainSnapshotPrepare)
(qemuDomainSnapshotCreateSingleDiskActive): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia):
Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise.
* src/security/security_apparmor.c
(AppArmorRestoreSecurityImageLabel)
(AppArmorSetSecurityImageLabel): Likewise.
* src/security/security_dac.c (virSecurityDACSetSecurityImageLabel)
(virSecurityDACRestoreSecurityImageLabelInt)
(virSecurityDACSetSecurityAllLabel): Likewise.
* src/security/security_selinux.c
(virSecuritySELinuxRestoreSecurityImageLabelInt)
(virSecuritySELinuxSetSecurityImageLabel)
(virSecuritySELinuxSetSecurityAllLabel): Likewise.
* src/storage/storage_backend.c (virStorageFileBackendForType):
Likewise.
* src/storage/storage_backend_fs.c (virStorageFileBackendFile)
(virStorageFileBackendBlock): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGluster): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives)
(vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise.
* src/vmware/vmware_conf.c (vmwareVmxPath): Likewise.
* src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk)
(virVMXFormatFloppy): Likewise.
* src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr)
(xenFormatSxprDisk): Likewise.
* src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise.
* tests/securityselinuxlabeltest.c (testSELinuxLoadDef):
Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
|
|
|
virBufferAsprintf(buf, " type='%s'>\n", virStorageTypeToString(type));
|
2014-03-05 10:09:46 +00:00
|
|
|
virBufferAdjustIndent(buf, 2);
|
2013-05-16 06:24:56 +00:00
|
|
|
|
2014-05-21 21:21:02 +00:00
|
|
|
if (disk->src->format > 0)
|
2014-03-05 10:09:46 +00:00
|
|
|
virBufferEscapeString(buf, "<driver type='%s'/>\n",
|
2014-05-21 21:21:02 +00:00
|
|
|
virStorageFileFormatTypeToString(disk->src->format));
|
2020-05-07 12:00:28 +00:00
|
|
|
if (virDomainDiskSourceFormat(buf, disk->src, "source", 0, false, 0,
|
|
|
|
false, false, xmlopt) < 0)
|
2017-11-08 12:13:20 +00:00
|
|
|
return -1;
|
2013-11-12 10:37:04 +00:00
|
|
|
|
2014-03-05 10:09:46 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</disk>\n");
|
2017-11-08 12:13:20 +00:00
|
|
|
return 0;
|
2013-05-16 06:24:56 +00:00
|
|
|
}
|
|
|
|
|
2017-06-01 13:57:55 +00:00
|
|
|
|
2019-02-17 01:58:58 +00:00
|
|
|
/* Append XML describing def into buf. Return 0 on success, or -1 on
|
|
|
|
* failure with buf cleared. */
|
2019-03-25 19:46:18 +00:00
|
|
|
static int
|
2019-02-17 01:58:58 +00:00
|
|
|
virDomainSnapshotDefFormatInternal(virBufferPtr buf,
|
|
|
|
const char *uuidstr,
|
|
|
|
virDomainSnapshotDefPtr def,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
|
|
|
unsigned int flags)
|
2012-08-14 00:09:12 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2019-02-15 20:43:43 +00:00
|
|
|
int domainflags = VIR_DOMAIN_DEF_FORMAT_INACTIVE;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2019-02-15 20:43:43 +00:00
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE)
|
|
|
|
domainflags |= VIR_DOMAIN_DEF_FORMAT_SECURE;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAddLit(buf, "<domainsnapshot>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2017-06-01 13:57:55 +00:00
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
virBufferEscapeString(buf, "<name>%s</name>\n", def->parent.name);
|
|
|
|
if (def->parent.description)
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferEscapeString(buf, "<description>%s</description>\n",
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.description);
|
snapshot: Don't expose testsuite-only state in snapshot XML
None of the existing drivers actually use the 0-valued 'nostate'
snapshot state; rather, it was a fluke of implementation. In fact,
some drivers, like qemu, actively reject 'nostate' as invalid during a
snapshot redefine. Normally, a driver computes the state post-parse
from the current domain, and thus virDomainSnapshotGetXMLDesc() will
never expose the state. However, since the testsuite lacks any
associated domain to copy state from, and lacks post-parse processing
that normal drivers have, the testsuite output had several spots with
the state, coupled with a regex filter to ignore the oddity.
It is better to follow the lead of other XML defaults, by not
outputting anything during format if post-parse defaults have not been
applied, and rejecting the default value during parsing. The testsuite
needs a bit of an update, by adding another flag for when to simulate
a post-parse action of setting a snapshot state, but none of the
drivers are impacted other than rejecting XML that was previously
already suspicious in nature.
Similarly, don't expose creation time 0 (for now, only possible if a
user redefined a snapshot to claim creation at the Epoch, but also
happens once setting the creation time is deferred to a post-parse
handler).
This is also a step towards cleaning up snapshot_conf.c to separate
its existing post-parse work (namely, setting the creationTime and
default snapshot name) from the pure parsing work, so that we can get
rid of the testsuite hack of regex filtering of the XML and instead
have more accurate testing of our parser/formatter code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Cole Robinson <crobinso@redhat.com>
2019-04-16 22:44:38 +00:00
|
|
|
if (def->state)
|
|
|
|
virBufferAsprintf(buf, "<state>%s</state>\n",
|
|
|
|
virDomainSnapshotStateTypeToString(def->state));
|
2017-06-01 13:57:55 +00:00
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (def->parent.parent_name) {
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAddLit(buf, "<parent>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2019-05-08 16:39:13 +00:00
|
|
|
virBufferEscapeString(buf, "<name>%s</name>\n",
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.parent_name);
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</parent>\n");
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
2017-06-01 13:57:55 +00:00
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (def->parent.creationTime)
|
snapshot: Don't expose testsuite-only state in snapshot XML
None of the existing drivers actually use the 0-valued 'nostate'
snapshot state; rather, it was a fluke of implementation. In fact,
some drivers, like qemu, actively reject 'nostate' as invalid during a
snapshot redefine. Normally, a driver computes the state post-parse
from the current domain, and thus virDomainSnapshotGetXMLDesc() will
never expose the state. However, since the testsuite lacks any
associated domain to copy state from, and lacks post-parse processing
that normal drivers have, the testsuite output had several spots with
the state, coupled with a regex filter to ignore the oddity.
It is better to follow the lead of other XML defaults, by not
outputting anything during format if post-parse defaults have not been
applied, and rejecting the default value during parsing. The testsuite
needs a bit of an update, by adding another flag for when to simulate
a post-parse action of setting a snapshot state, but none of the
drivers are impacted other than rejecting XML that was previously
already suspicious in nature.
Similarly, don't expose creation time 0 (for now, only possible if a
user redefined a snapshot to claim creation at the Epoch, but also
happens once setting the creation time is deferred to a post-parse
handler).
This is also a step towards cleaning up snapshot_conf.c to separate
its existing post-parse work (namely, setting the creationTime and
default snapshot name) from the pure parsing work, so that we can get
rid of the testsuite hack of regex filtering of the XML and instead
have more accurate testing of our parser/formatter code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Cole Robinson <crobinso@redhat.com>
2019-04-16 22:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<creationTime>%lld</creationTime>\n",
|
2019-05-08 22:10:58 +00:00
|
|
|
def->parent.creationTime);
|
2017-06-01 13:57:55 +00:00
|
|
|
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
if (def->memory) {
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAsprintf(buf, "<memory snapshot='%s'",
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
virDomainSnapshotLocationTypeToString(def->memory));
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferEscapeString(buf, " file='%s'", def->file);
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
}
|
2017-06-01 13:57:55 +00:00
|
|
|
|
snapshot: new XML for external system checkpoint
Each <domainsnapshot> can now contain an optional <memory>
element that describes how the VM state was handled, similar
to disk snapshots. The new element will always appear in
output; for back-compat, an input that lacks the element will
assume 'no' or 'internal' according to the domain state.
Along with this change, it is now possible to pass <disks> in
the XML for an offline snapshot; this also needs to be wired up
in a future patch, to make it possible to choose internal vs.
external on a per-disk basis for each disk in an offline domain.
At that point, using the --disk-only flag for an offline domain
will be able to work.
For some examples below, remember that qemu supports the
following snapshot actions:
qemu-img: offline external and internal disk
savevm: online internal VM and disk
migrate: online external VM
transaction: online external disk
=====
<domainsnapshot>
<memory snapshot='no'/>
...
</domainsnapshot>
implies that there is no VM state saved (mandatory for
offline and disk-only snapshots, not possible otherwise);
using qemu-img for offline domains and transaction for online.
=====
<domainsnapshot>
<memory snapshot='internal'/>
...
</domainsnapshot>
state is saved inside one of the disks (as in qemu's 'savevm'
system checkpoint implementation). If needed in the future,
we can also add an attribute pointing out _which_ disk saved
the internal state; maybe disk='vda'.
=====
<domainsnapshot>
<memory snapshot='external' file='/path/to/state'/>
...
</domainsnapshot>
This is not wired up yet, but future patches will allow this to
control a combination of 'virsh save /path/to/state' plus disk
snapshots from the same point in time.
=====
So for 1.0.1 (and later, as needed), I plan to implement this table
of combinations, with '*' designating new code and '+' designating
existing code reached through new combinations of xml and/or the
existing DISK_ONLY flag:
domain memory disk disk-only | result
-----------------------------------------
offline omit omit any | memory=no disk=int, via qemu-img
offline no omit any |+memory=no disk=int, via qemu-img
offline omit/no no any | invalid combination (nothing to snapshot)
offline omit/no int any |+memory=no disk=int, via qemu-img
offline omit/no ext any |*memory=no disk=ext, via qemu-img
offline int/ext any any | invalid combination (no memory to save)
online omit omit off | memory=int disk=int, via savevm
online omit omit on | memory=no disk=default, via transaction
online omit no/ext off | unsupported for now
online omit no on | invalid combination (nothing to snapshot)
online omit ext on | memory=no disk=ext, via transaction
online omit int off |+memory=int disk=int, via savevm
online omit int on | unsupported for now
online no omit any |+memory=no disk=default, via transaction
online no no any | invalid combination (nothing to snapshot)
online no int any | unsupported for now
online no ext any |+memory=no disk=ext, via transaction
online int/ext any on | invalid combination (disk-only vs. memory)
online int omit off |+memory=int disk=int, via savevm
online int no/ext off | unsupported for now
online int int off |+memory=int disk=int, via savevm
online ext omit off |*memory=ext disk=default, via migrate+trans
online ext no off |+memory=ext disk=no, via migrate
online ext int off | unsupported for now
online ext ext off |*memory=ext disk=ext, via migrate+transaction
* docs/schemas/domainsnapshot.rng (memory): New RNG element.
* docs/formatsnapshot.html.in: Document it.
* src/conf/snapshot_conf.h (virDomainSnapshotDef): New fields.
* src/conf/domain_conf.c (virDomainSnapshotDefFree)
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Manage new fields.
* tests/domainsnapshotxml2xmltest.c: New test.
* tests/domainsnapshotxml2xmlin/*.xml: Update existing tests.
* tests/domainsnapshotxml2xmlout/*.xml: Likewise.
2012-10-23 15:12:23 +00:00
|
|
|
if (def->ndisks) {
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAddLit(buf, "<disks>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2017-11-08 12:13:20 +00:00
|
|
|
for (i = 0; i < def->ndisks; i++) {
|
2019-02-17 01:58:58 +00:00
|
|
|
if (virDomainSnapshotDiskDefFormat(buf, &def->disks[i], xmlopt) < 0)
|
2020-07-03 03:19:26 +00:00
|
|
|
return -1;
|
2017-11-08 12:13:20 +00:00
|
|
|
}
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</disks>\n");
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
2017-06-01 13:57:55 +00:00
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
if (def->parent.dom) {
|
2019-11-26 19:40:46 +00:00
|
|
|
if (virDomainDefFormatInternal(def->parent.dom, xmlopt,
|
2019-11-27 11:57:34 +00:00
|
|
|
buf, domainflags) < 0)
|
2020-07-03 03:19:26 +00:00
|
|
|
return -1;
|
2019-02-21 15:43:49 +00:00
|
|
|
} else if (uuidstr) {
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAddLit(buf, "<domain>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</domain>\n");
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
2017-06-01 13:57:55 +00:00
|
|
|
|
2019-08-29 20:55:43 +00:00
|
|
|
if (def->parent.inactiveDom) {
|
2019-11-26 19:40:46 +00:00
|
|
|
if (virDomainDefFormatInternalSetRootName(def->parent.inactiveDom, xmlopt,
|
2019-11-27 11:57:34 +00:00
|
|
|
buf, "inactiveDomain",
|
2019-11-26 19:40:46 +00:00
|
|
|
domainflags) < 0)
|
2020-07-03 03:19:26 +00:00
|
|
|
return -1;
|
2019-08-29 20:55:43 +00:00
|
|
|
}
|
|
|
|
|
2019-02-17 01:58:58 +00:00
|
|
|
if (virSaveCookieFormatBuf(buf, def->cookie,
|
2017-06-01 22:44:46 +00:00
|
|
|
virDomainXMLOptionGetSaveCookie(xmlopt)) < 0)
|
2020-07-03 03:19:26 +00:00
|
|
|
return -1;
|
2017-06-01 22:44:46 +00:00
|
|
|
|
2019-02-15 20:43:43 +00:00
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_FORMAT_INTERNAL)
|
snapshot: Drop virDomainSnapshotDef.current
The only use for the 'current' member of virDomainSnapshotDef was with
the PARSE/FORMAT_INTERNAL flag for controlling an internal-use
<active> element marking whether a particular snapshot definition was
current, and even then, only by the qemu driver on output, and by qemu
and test driver on input. But this duplicates vm->snapshot_current,
and gets in the way of potential simplifications to have qemu store a
single file for all snapshots rather than one file per snapshot. Get
rid of the member by adding a bool* parameter during parse (ignored if
the PARSE_INTERNAL flag is not set), and by adding a new flag during
format (if FORMAT_INTERNAL is set, the value printed in <active>
depends on the new FORMAT_CURRENT).
Then update the qemu driver accordingly, which involves hoisting
assignments to vm->current_snapshot to occur prior to any point where
a snapshot XML file is written (although qemu kept
vm->current_snapshot and snapshot->def_current in sync by the end of
the function, they were not always identical in the middle of
functions, so the shuffling gets a bit interesting). Later patches
will clean up some of that confusing churn to vm->current_snapshot.
Note: even if later patches refactor qemu to no longer use
FORMAT_INTERNAL for output (by storing bulk snapshot XML instead), we
will always need PARSE_INTERNAL for input (because on upgrade, a new
libvirt still has to parse XML left from a previous libvirt).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
2019-03-19 03:56:19 +00:00
|
|
|
virBufferAsprintf(buf, "<active>%d</active>\n",
|
|
|
|
!!(flags & VIR_DOMAIN_SNAPSHOT_FORMAT_CURRENT));
|
2017-06-01 13:57:55 +00:00
|
|
|
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</domainsnapshot>\n");
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2019-02-17 01:58:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
virDomainSnapshotDefFormat(const char *uuidstr,
|
|
|
|
virDomainSnapshotDefPtr def,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2020-07-03 02:19:01 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2019-02-17 01:58:58 +00:00
|
|
|
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE |
|
snapshot: Drop virDomainSnapshotDef.current
The only use for the 'current' member of virDomainSnapshotDef was with
the PARSE/FORMAT_INTERNAL flag for controlling an internal-use
<active> element marking whether a particular snapshot definition was
current, and even then, only by the qemu driver on output, and by qemu
and test driver on input. But this duplicates vm->snapshot_current,
and gets in the way of potential simplifications to have qemu store a
single file for all snapshots rather than one file per snapshot. Get
rid of the member by adding a bool* parameter during parse (ignored if
the PARSE_INTERNAL flag is not set), and by adding a new flag during
format (if FORMAT_INTERNAL is set, the value printed in <active>
depends on the new FORMAT_CURRENT).
Then update the qemu driver accordingly, which involves hoisting
assignments to vm->current_snapshot to occur prior to any point where
a snapshot XML file is written (although qemu kept
vm->current_snapshot and snapshot->def_current in sync by the end of
the function, they were not always identical in the middle of
functions, so the shuffling gets a bit interesting). Later patches
will clean up some of that confusing churn to vm->current_snapshot.
Note: even if later patches refactor qemu to no longer use
FORMAT_INTERNAL for output (by storing bulk snapshot XML instead), we
will always need PARSE_INTERNAL for input (because on upgrade, a new
libvirt still has to parse XML left from a previous libvirt).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
2019-03-19 03:56:19 +00:00
|
|
|
VIR_DOMAIN_SNAPSHOT_FORMAT_INTERNAL |
|
|
|
|
VIR_DOMAIN_SNAPSHOT_FORMAT_CURRENT, NULL);
|
2019-11-27 13:10:21 +00:00
|
|
|
if (virDomainSnapshotDefFormatInternal(&buf, uuidstr, def,
|
2019-02-17 01:58:58 +00:00
|
|
|
xmlopt, flags) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
|
2019-02-17 02:13:44 +00:00
|
|
|
|
2012-10-19 09:55:36 +00:00
|
|
|
bool
|
2013-01-03 13:10:39 +00:00
|
|
|
virDomainSnapshotDefIsExternal(virDomainSnapshotDefPtr def)
|
2012-10-19 09:55:36 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-10-19 09:55:36 +00:00
|
|
|
|
2013-01-03 13:10:39 +00:00
|
|
|
if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
|
2012-10-19 09:55:36 +00:00
|
|
|
return true;
|
|
|
|
|
2013-01-03 13:10:39 +00:00
|
|
|
for (i = 0; i < def->ndisks; i++) {
|
|
|
|
if (def->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
|
2012-10-19 09:55:36 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2013-01-03 13:10:39 +00:00
|
|
|
|
|
|
|
bool
|
2019-03-22 04:45:25 +00:00
|
|
|
virDomainSnapshotIsExternal(virDomainMomentObjPtr snap)
|
2013-01-03 13:10:39 +00:00
|
|
|
{
|
2019-03-18 21:13:50 +00:00
|
|
|
virDomainSnapshotDefPtr def = virDomainSnapshotObjGetDef(snap);
|
|
|
|
|
|
|
|
return virDomainSnapshotDefIsExternal(def);
|
2013-01-03 13:10:39 +00:00
|
|
|
}
|
2013-08-21 20:39:02 +00:00
|
|
|
|
|
|
|
int
|
2019-09-20 10:25:51 +00:00
|
|
|
virDomainSnapshotRedefinePrep(virDomainObjPtr vm,
|
2013-08-21 20:39:02 +00:00
|
|
|
virDomainSnapshotDefPtr *defptr,
|
2019-03-22 04:45:25 +00:00
|
|
|
virDomainMomentObjPtr *snap,
|
2017-05-19 13:07:15 +00:00
|
|
|
virDomainXMLOptionPtr xmlopt,
|
2013-08-21 20:39:02 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainSnapshotDefPtr def = *defptr;
|
2019-03-22 04:45:25 +00:00
|
|
|
virDomainMomentObjPtr other;
|
2019-07-06 02:07:43 +00:00
|
|
|
virDomainSnapshotDefPtr otherdef = NULL;
|
2019-03-07 22:12:24 +00:00
|
|
|
bool check_if_stolen;
|
2013-08-21 20:39:02 +00:00
|
|
|
|
2019-07-06 02:07:43 +00:00
|
|
|
if (virDomainSnapshotCheckCycles(vm->snapshots, def, vm->def->name) < 0)
|
|
|
|
return -1;
|
2013-08-21 20:39:02 +00:00
|
|
|
|
2019-05-08 22:10:58 +00:00
|
|
|
other = virDomainSnapshotFindByName(vm->snapshots, def->parent.name);
|
2019-07-06 02:07:43 +00:00
|
|
|
if (other)
|
|
|
|
otherdef = virDomainSnapshotObjGetDef(other);
|
2019-05-08 22:10:58 +00:00
|
|
|
check_if_stolen = other && otherdef->parent.dom;
|
2019-09-20 10:25:51 +00:00
|
|
|
if (virDomainSnapshotRedefineValidate(def, vm->def->uuid, other, xmlopt,
|
2019-03-07 22:12:24 +00:00
|
|
|
flags) < 0) {
|
|
|
|
/* revert any stealing of the snapshot domain definition */
|
2019-05-08 22:10:58 +00:00
|
|
|
if (check_if_stolen && def->parent.dom && !otherdef->parent.dom)
|
2019-10-16 11:43:01 +00:00
|
|
|
otherdef->parent.dom = g_steal_pointer(&def->parent.dom);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (other) {
|
2013-08-21 20:39:02 +00:00
|
|
|
/* Drop and rebuild the parent relationship, but keep all
|
2019-03-07 22:12:24 +00:00
|
|
|
* child relations by reusing snap. */
|
2019-03-22 04:45:25 +00:00
|
|
|
virDomainMomentDropParent(other);
|
2019-05-09 14:59:06 +00:00
|
|
|
virObjectUnref(otherdef);
|
2019-05-08 22:10:58 +00:00
|
|
|
other->def = &(*defptr)->parent;
|
2019-03-22 04:44:33 +00:00
|
|
|
*defptr = NULL;
|
2013-08-21 20:39:02 +00:00
|
|
|
*snap = other;
|
|
|
|
}
|
|
|
|
|
2019-03-07 22:12:24 +00:00
|
|
|
return 0;
|
2013-08-21 20:39:02 +00:00
|
|
|
}
|