after snapshot */
VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY = (1 << 4), /* disk snapshot, not
system checkpoint */
+ VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT = (1 << 5), /* reuse any existing
+ external files */
} virDomainSnapshotCreateFlags;
/* Take a snapshot of the current VM state */
* inconsistent (as if power had been pulled), and specifying this
* with the VIR_DOMAIN_SNAPSHOT_CREATE_HALT flag risks data loss.
*
+ * By default, if the snapshot involves external files, and any of the
+ * destination files already exist as a regular file, the snapshot is
+ * rejected to avoid losing contents of those files. However, if
+ * @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT, then existing
+ * destination files are instead truncated and reused.
+ *
* Returns an (opaque) virDomainSnapshotPtr on success, NULL on failure.
+ * Be aware that although libvirt prefers to report errors up front with
+ * no other effect, there are certain types of failures where a failure
+ * can occur even though the guest configuration was changed (for
+ * example, if a disk snapshot request over two disks only fails on the
+ * second disk, leaving the first disk altered); so after getting a NULL
+ * return, it can be wise to use virDomainGetXMLDesc() to determine if
+ * any partial changes occurred.
*/
virDomainSnapshotPtr
virDomainSnapshotCreateXML(virDomainPtr domain,
}
static int
-qemuDomainSnapshotDiskPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def)
+qemuDomainSnapshotDiskPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
+ bool allow_reuse)
{
int ret = -1;
int i;
disk->name, disk->file);
goto cleanup;
}
- } else if (!S_ISBLK(st.st_mode)) {
+ } else if (!(S_ISBLK(st.st_mode) || allow_reuse)) {
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("external snapshot file for disk %s already "
"exists and is not a block device: %s"),
VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
- VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY, NULL);
+ VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
+ VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT, NULL);
if (((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
goto cleanup;
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
+ bool allow_reuse;
+
+ allow_reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
if (virDomainSnapshotAlignDisks(def,
VIR_DOMAIN_DISK_SNAPSHOT_EXTERNAL,
false) < 0)
goto cleanup;
- if (qemuDomainSnapshotDiskPrepare(vm, def) < 0)
+ if (qemuDomainSnapshotDiskPrepare(vm, def, allow_reuse) < 0)
goto cleanup;
def->state = VIR_DOMAIN_DISK_SNAPSHOT;
} else {
/*
* virsh.c: a shell to exercise the libvirt API
*
- * Copyright (C) 2005, 2007-2011 Red Hat, Inc.
+ * Copyright (C) 2005, 2007-2012 Red Hat, Inc.
*
* See COPYING.LIB for the License of this software
*
{"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")},
{"halt", VSH_OT_BOOL, 0, N_("halt domain after snapshot is created")},
{"disk-only", VSH_OT_BOOL, 0, N_("capture disk state but not vm state")},
+ {"reuse-external", VSH_OT_BOOL, 0, N_("reuse any existing external files")},
{NULL, 0, 0, NULL}
};
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT;
if (vshCommandOptBool(cmd, "disk-only"))
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;
+ if (vshCommandOptBool(cmd, "reuse-external"))
+ flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT;
if (!vshConnectionUsability(ctl, ctl->conn))
goto cleanup;
{"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")},
{"halt", VSH_OT_BOOL, 0, N_("halt domain after snapshot is created")},
{"disk-only", VSH_OT_BOOL, 0, N_("capture disk state but not vm state")},
+ {"reuse-external", VSH_OT_BOOL, 0, N_("reuse any existing external files")},
{"diskspec", VSH_OT_ARGV, 0,
N_("disk attributes: disk[,snapshot=type][,driver=type][,file=name]")},
{NULL, 0, 0, NULL}
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT;
if (vshCommandOptBool(cmd, "disk-only"))
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;
+ if (vshCommandOptBool(cmd, "reuse-external"))
+ flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT;
if (!vshConnectionUsability(ctl, ctl->conn))
goto cleanup;
=over 4
=item B<snapshot-create> I<domain> [I<xmlfile>] {[I<--redefine> [I<--current>]]
-| [I<--no-metadata>] [I<--halt>] [I<--disk-only>]}
+| [I<--no-metadata>] [I<--halt>] [I<--disk-only>] [I<--reuse-external]}
Create a snapshot for domain I<domain> with the properties specified in
I<xmlfile>. Normally, the only properties settable for a domain snapshot
unless I<--redefine> is later used to teach libvirt about the
metadata again).
+If I<--reuse-external> is specified, and the snapshot XML requests an
+external snapshot with a destination of an existing file, then the
+existing file is truncated and reused; otherwise, a snapshot is refused
+to avoid losing contents of the existing files.
+
Existence of snapshot metadata will prevent attempts to B<undefine>
a persistent domain. However, for transient domains, snapshot
metadata is silently lost when the domain quits running (whether
by command such as B<destroy> or by internal guest action).
=item B<snapshot-create-as> I<domain> {[I<--print-xml>]
-| [I<--no-metadata>] [I<--halt>]} [I<name>] [I<description>]
-[I<--disk-only> [[I<--diskspec>] B<diskspec>]...
+| [I<--no-metadata>] [I<--halt>] [I<--reuse-existing>]} [I<name>]
+[I<description>] [I<--disk-only> [[I<--diskspec>] B<diskspec>]...]
Create a snapshot for domain I<domain> with the given <name> and
<description>; if either value is omitted, libvirt will choose a
<source file='/path/to,new'/>
</disk>
+If I<--reuse-external> is specified, and the domain XML or I<diskspec>
+option requests an external snapshot with a destination of an existing
+file, then the existing file is truncated and reused; otherwise, a
+snapshot is refused to avoid losing contents of the existing files.
+
If I<--no-metadata> is specified, then the snapshot data is created,
but any metadata is immediately discarded (that is, libvirt does not
treat the snapshot as current, and cannot revert to the snapshot