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 <sys/time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#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 "count-one-bits.h"
|
|
|
|
#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
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_DOMAIN_SNAPSHOT
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("conf.snapshot_conf");
|
|
|
|
|
2012-08-13 22:59:57 +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-02-26 20:14:36 +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
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
|
|
|
|
{
|
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
|
|
|
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
virDomainMomentDefClear(&def->common);
|
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
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
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;
|
2015-04-10 09:55:43 +00:00
|
|
|
xmlNodePtr saved = ctxt->node;
|
|
|
|
|
|
|
|
ctxt->node = node;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2019-02-14 15:20:25 +00:00
|
|
|
if (!(def->src = virStorageSourceNew()))
|
2014-05-21 21:21:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
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)) &&
|
2017-12-12 16:55:03 +00:00
|
|
|
virDomainDiskSourceParse(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
|
|
|
ctxt->node = saved;
|
|
|
|
|
|
|
|
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.
|
|
|
|
* If flags does not include VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE, then
|
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
|
|
|
* caps are ignored. If flags does not include
|
|
|
|
* 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,
|
|
|
|
virCapsPtr caps,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
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;
|
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;
|
2012-08-14 00:09:12 +00:00
|
|
|
char *creation = NULL, *state = NULL;
|
|
|
|
struct timeval tv;
|
|
|
|
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);
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2013-07-04 10:02:00 +00:00
|
|
|
if (VIR_ALLOC(def) < 0)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.name = virXPathString("string(./name)", ctxt);
|
|
|
|
if (def->common.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-03-22 02:02:19 +00:00
|
|
|
if (virAsprintf(&def->common.name, "%lld", (long long)tv.tv_sec) < 0)
|
2012-10-25 22:26:41 +00:00
|
|
|
goto cleanup;
|
2012-08-14 00:09:12 +00:00
|
|
|
}
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.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-03-22 02:02:19 +00:00
|
|
|
&def->common.creationTime) < 0) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing creationTime from existing snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.parent = 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);
|
|
|
|
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))) {
|
2016-05-26 13:58:53 +00:00
|
|
|
int domainflags = VIR_DOMAIN_DEF_PARSE_INACTIVE |
|
|
|
|
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE;
|
2012-08-14 00:09:12 +00:00
|
|
|
xmlNodePtr domainNode = virXPathNode("./domain", ctxt);
|
|
|
|
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
if (!domainNode) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing domain in snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.dom = virDomainDefParseNode(ctxt->node->doc, domainNode,
|
|
|
|
caps, xmlopt, NULL, domainflags);
|
|
|
|
if (!def->common.dom)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
VIR_WARN("parsing older snapshot that lacks domain");
|
|
|
|
}
|
|
|
|
} else {
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.creationTime = tv.tv_sec;
|
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;
|
|
|
|
}
|
2018-06-21 10:11:29 +00:00
|
|
|
VIR_STEAL_PTR(def->file, 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;
|
|
|
|
|
2018-06-21 10:11:29 +00:00
|
|
|
VIR_STEAL_PTR(ret, 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(creation);
|
|
|
|
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);
|
2018-06-21 10:11:29 +00:00
|
|
|
virDomainSnapshotDefFree(def);
|
2013-08-07 14:34:40 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainSnapshotDefPtr
|
|
|
|
virDomainSnapshotDefParseNode(xmlDocPtr xml,
|
|
|
|
xmlNodePtr root,
|
|
|
|
virCapsPtr caps,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
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)
|
|
|
|
{
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
virDomainSnapshotDefPtr def = NULL;
|
|
|
|
|
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"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
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
|
|
|
def = virDomainSnapshotDefParse(ctxt, caps, xmlopt, current, flags);
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2013-08-07 14:34:40 +00:00
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainSnapshotDefPtr
|
|
|
|
virDomainSnapshotDefParseString(const char *xmlStr,
|
|
|
|
virCapsPtr caps,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
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),
|
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
|
|
|
caps, xmlopt, 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-03-22 02:02:19 +00:00
|
|
|
* @other is non-NULL, this may include swapping def->common.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-03-22 02:02:19 +00:00
|
|
|
def->common.name);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-03-22 02:02:19 +00:00
|
|
|
if (def->common.dom && memcmp(def->common.dom->uuid, domain_uuid,
|
|
|
|
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-03-22 02:02:19 +00:00
|
|
|
def->common.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-03-22 02:02:19 +00:00
|
|
|
def->common.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-03-22 02:02:19 +00:00
|
|
|
def->common.name);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
if (otherdef->common.dom) {
|
|
|
|
if (def->common.dom) {
|
|
|
|
if (!virDomainDefCheckABIStability(otherdef->common.dom,
|
|
|
|
def->common.dom, xmlopt))
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
/* Transfer the domain def */
|
2019-03-22 02:02:19 +00:00
|
|
|
VIR_STEAL_PTR(def->common.dom, otherdef->common.dom);
|
2019-03-07 22:12:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
if (def->common.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-03-22 02:02:19 +00:00
|
|
|
if (!(origpath = virDomainDiskGetSource(def->common.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
|
|
|
|
2016-02-11 08:42:36 +00:00
|
|
|
if (VIR_STRDUP(tmppath, origpath) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* drop suffix of the file name */
|
|
|
|
if ((tmp = strrchr(tmppath, '.')) && !strchr(tmp, '/'))
|
|
|
|
*tmp = '\0';
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
if (virAsprintf(&disk->src->path, "%s.%s", tmppath, def->common.name) < 0) {
|
2016-02-11 08:42:36 +00:00
|
|
|
VIR_FREE(tmppath);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-03-22 02:02:19 +00:00
|
|
|
/* Align def->disks to def->common.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-03-22 02:02:19 +00:00
|
|
|
if (!def->common.dom) {
|
2012-08-14 00:09:12 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing domain in snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
if (def->ndisks > def->common.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-03-22 02:02:19 +00:00
|
|
|
if (!def->common.dom->ndisks) {
|
2012-08-14 00:09:12 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
if (!(map = virBitmapNew(def->common.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-03-22 02:02:19 +00:00
|
|
|
int idx = virDomainDiskIndexByName(def->common.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-03-22 02:02:19 +00:00
|
|
|
disk_snapshot = def->common.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-03-22 02:02:19 +00:00
|
|
|
if (STRNEQ(disk->name, def->common.dom->disks[idx]->dst)) {
|
2012-08-14 00:09:12 +00:00
|
|
|
VIR_FREE(disk->name);
|
2019-03-22 02:02:19 +00:00
|
|
|
if (VIR_STRDUP(disk->name, def->common.dom->disks[idx]->dst) < 0)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Provide defaults for all remaining disks. */
|
|
|
|
ndisks = def->ndisks;
|
|
|
|
if (VIR_EXPAND_N(def->disks, def->ndisks,
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.dom->ndisks - def->ndisks) < 0)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
for (i = 0; i < def->common.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++];
|
2019-02-14 15:20:25 +00:00
|
|
|
if (!(disk->src = virStorageSourceNew()))
|
2014-05-21 21:21:02 +00:00
|
|
|
goto cleanup;
|
2019-03-22 02:02:19 +00:00
|
|
|
if (VIR_STRDUP(disk->name, def->common.dom->disks[i]->dst) < 0)
|
2012-08-14 00:09:12 +00:00
|
|
|
goto cleanup;
|
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-03-22 02:02:19 +00:00
|
|
|
if (virStorageSourceIsEmpty(def->common.dom->disks[i]->src))
|
2014-09-11 15:45:06 +00:00
|
|
|
disk->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
|
|
|
|
else
|
2019-03-22 02:02:19 +00:00
|
|
|
disk->snapshot = def->common.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));
|
2017-11-08 12:13:20 +00:00
|
|
|
if (virDomainDiskSourceFormat(buf, disk->src, 0, 0, xmlopt) < 0)
|
|
|
|
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,
|
|
|
|
virCapsPtr caps,
|
|
|
|
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-03-22 02:02:19 +00:00
|
|
|
virBufferEscapeString(buf, "<name>%s</name>\n", def->common.name);
|
|
|
|
if (def->common.description)
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferEscapeString(buf, "<description>%s</description>\n",
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.description);
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAsprintf(buf, "<state>%s</state>\n",
|
2012-08-14 00:09:12 +00:00
|
|
|
virDomainSnapshotStateTypeToString(def->state));
|
2017-06-01 13:57:55 +00:00
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
if (def->common.parent) {
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferAddLit(buf, "<parent>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2019-03-22 02:02:19 +00:00
|
|
|
virBufferEscapeString(buf, "<name>%s</name>\n", def->common.parent);
|
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-02-17 01:58:58 +00:00
|
|
|
virBufferAsprintf(buf, "<creationTime>%lld</creationTime>\n",
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.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)
|
2017-11-08 12:13:20 +00:00
|
|
|
goto error;
|
|
|
|
}
|
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-03-22 02:02:19 +00:00
|
|
|
if (def->common.dom) {
|
|
|
|
if (virDomainDefFormatInternal(def->common.dom, caps, domainflags, buf,
|
2019-02-15 20:43:43 +00:00
|
|
|
xmlopt) < 0)
|
2017-06-01 13:57:55 +00:00
|
|
|
goto error;
|
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-02-17 01:58:58 +00:00
|
|
|
if (virSaveCookieFormatBuf(buf, def->cookie,
|
2017-06-01 22:44:46 +00:00
|
|
|
virDomainXMLOptionGetSaveCookie(xmlopt)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
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
|
|
|
if (virBufferCheckError(buf) < 0)
|
|
|
|
goto error;
|
2012-08-14 00:09:12 +00:00
|
|
|
|
2019-02-17 01:58:58 +00:00
|
|
|
return 0;
|
2017-06-01 13:57:55 +00:00
|
|
|
|
|
|
|
error:
|
2019-02-17 01:58:58 +00:00
|
|
|
virBufferFreeAndReset(buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
virDomainSnapshotDefFormat(const char *uuidstr,
|
|
|
|
virDomainSnapshotDefPtr def,
|
|
|
|
virCapsPtr caps,
|
|
|
|
virDomainXMLOptionPtr xmlopt,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
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-02-17 01:58:58 +00:00
|
|
|
if (virDomainSnapshotDefFormatInternal(&buf, uuidstr, def, caps,
|
|
|
|
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
|
|
|
|
virDomainSnapshotRedefinePrep(virDomainPtr domain,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
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
|
|
|
bool *update_current,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virDomainSnapshotDefPtr def = *defptr;
|
2019-03-22 04:45:25 +00:00
|
|
|
virDomainMomentObjPtr other;
|
2019-03-18 21:13:50 +00:00
|
|
|
virDomainSnapshotDefPtr otherdef;
|
2019-03-07 22:12:24 +00:00
|
|
|
bool check_if_stolen;
|
2013-08-21 20:39:02 +00:00
|
|
|
|
|
|
|
/* Prevent circular chains */
|
2019-03-22 02:02:19 +00:00
|
|
|
if (def->common.parent) {
|
|
|
|
if (STREQ(def->common.name, def->common.parent)) {
|
2013-08-21 20:39:02 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("cannot set snapshot %s as its own parent"),
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.name);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
2013-08-21 20:39:02 +00:00
|
|
|
}
|
2019-03-22 02:02:19 +00:00
|
|
|
other = virDomainSnapshotFindByName(vm->snapshots, def->common.parent);
|
2013-08-21 20:39:02 +00:00
|
|
|
if (!other) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("parent %s for snapshot %s not found"),
|
2019-03-22 02:02:19 +00:00
|
|
|
def->common.parent, def->common.name);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
2013-08-21 20:39:02 +00:00
|
|
|
}
|
2019-03-18 21:13:50 +00:00
|
|
|
otherdef = virDomainSnapshotObjGetDef(other);
|
2019-03-22 02:02:19 +00:00
|
|
|
while (otherdef->common.parent) {
|
|
|
|
if (STREQ(otherdef->common.parent, def->common.name)) {
|
2013-08-21 20:39:02 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("parent %s would create cycle to %s"),
|
2019-03-22 02:02:19 +00:00
|
|
|
otherdef->common.name, def->common.name);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
2013-08-21 20:39:02 +00:00
|
|
|
}
|
|
|
|
other = virDomainSnapshotFindByName(vm->snapshots,
|
2019-03-22 02:02:19 +00:00
|
|
|
otherdef->common.parent);
|
2013-08-21 20:39:02 +00:00
|
|
|
if (!other) {
|
|
|
|
VIR_WARN("snapshots are inconsistent for %s",
|
|
|
|
vm->def->name);
|
|
|
|
break;
|
|
|
|
}
|
2019-03-23 22:04:43 +00:00
|
|
|
otherdef = virDomainSnapshotObjGetDef(other);
|
2013-08-21 20:39:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-22 02:02:19 +00:00
|
|
|
other = virDomainSnapshotFindByName(vm->snapshots, def->common.name);
|
2019-03-18 21:13:50 +00:00
|
|
|
otherdef = other ? virDomainSnapshotObjGetDef(other) : NULL;
|
2019-03-22 02:02:19 +00:00
|
|
|
check_if_stolen = other && otherdef->common.dom;
|
2019-03-07 22:12:24 +00:00
|
|
|
if (virDomainSnapshotRedefineValidate(def, domain->uuid, other, xmlopt,
|
|
|
|
flags) < 0) {
|
|
|
|
/* revert any stealing of the snapshot domain definition */
|
2019-03-22 02:02:19 +00:00
|
|
|
if (check_if_stolen && def->common.dom && !otherdef->common.dom)
|
|
|
|
VIR_STEAL_PTR(otherdef->common.dom, def->common.dom);
|
2019-03-07 22:12:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (other) {
|
2019-03-21 20:00:08 +00:00
|
|
|
if (other == virDomainSnapshotGetCurrent(vm->snapshots)) {
|
2013-08-21 20:39:02 +00:00
|
|
|
*update_current = true;
|
2019-03-21 20:00:08 +00:00
|
|
|
virDomainSnapshotSetCurrent(vm->snapshots, NULL);
|
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-03-18 21:13:50 +00:00
|
|
|
virDomainSnapshotDefFree(otherdef);
|
2019-03-22 04:44:33 +00:00
|
|
|
other->def = &(*defptr)->common;
|
|
|
|
*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
|
|
|
}
|