In order to distinguish disk snapshots from system checkpoints, a
new state value that is only valid for snapshots is helpful.
* include/libvirt/libvirt.h.in (VIR_DOMAIN_LAST): New placeholder.
* src/conf/domain_conf.h (virDomainSnapshotState): New enum mapping.
(VIR_DOMAIN_DISK_SNAPSHOT): New internal enum value.
* src/conf/domain_conf.c (virDomainState): Use placeholder.
(virDomainSnapshotState): Extend mapping by one for use in snapshot.
(virDomainSnapshotDefParseString, virDomainSnapshotDefFormat):
Handle new state.
(virDomainObjSetState, virDomainStateReasonToString)
(virDomainStateReasonFromString): Avoid compiler warnings.
* tools/virsh.c (vshDomainState, vshDomainStateReasonToString):
Likewise.
* src/libvirt_private.syms (domain_conf.h): Export new functions.
* docs/schemas/domainsnapshot.rng: Tighten state definition.
* docs/formatsnapshot.html.in: Document it.
* tests/domainsnapshotxml2xmlout/disk_snapshot.xml: New test.
---
docs/formatsnapshot.html.in | 87 +++++++++++++++++++---
docs/schemas/domainsnapshot.rng | 15 ++++-
include/libvirt/libvirt.h.in | 14 +++-
src/conf/domain_conf.c | 26 +++++--
src/conf/domain_conf.h | 8 ++-
src/libvirt_private.syms | 2 +
tests/domainsnapshotxml2xmlout/disk_snapshot.xml | 35 +++++++++
tools/virsh.c | 6 ++
8 files changed, 171 insertions(+), 22 deletions(-)
create mode 100644 tests/domainsnapshotxml2xmlout/disk_snapshot.xml
diff --git a/docs/formatsnapshot.html.in b/docs/formatsnapshot.html.in
index edf20e8..4158a63 100644
--- a/docs/formatsnapshot.html.in
+++ b/docs/formatsnapshot.html.in
@@ -7,6 +7,61 @@
<h2><a name="SnapshotAttributes">Snapshot
XML</a></h2>
<p>
+ There are several types of snapshots:
+ </p>
+ <dl>
+ <dt>disk snapshot</dt>
+ <dd>Contents of disks (whether a subset or all disks associated
+ with the domain) are saved at a given point of time, and can
+ be restored back to that state. On a running guest, a disk
+ snapshot is likely to be only crash-consistent rather than
+ clean (that is, it represents the state of the disk on a
+ sudden power outage, and may need fsck or journal replays to
+ be made consistent); on an inactive guest, a disk snapshot is
+ clean if the disks were clean when the guest was last shut
+ down.</dd>
+ <dt>VM state</dt>
+ <dd>Tracks only the state of RAM and all other resources in use
+ by the VM. If the disks are unmodified between the time a VM
+ state snapshot is taken and restored, then the guest will
+ resume in a consistent state; but if the disks are modified
+ externally in the meantime, this is likely to lead to data
+ corruption.</dd>
+ <dt>system checkpoint</dt>
+ <dd>A combination of disk snapshots for all disks as well as VM
+ state, which can be used to resume the guest from where it
+ left off with symptoms similar to hibernation (that is, TCP
+ connections in the guest may have timed out, but no files or
+ processes are lost).</dd>
+ </dl>
+
+ <p>
+ Libvirt can manage all three types of snapshots. For now, VM
+ state snapshots are created only by
+ the <code>virDomainSave()</code>,
<code>virDomainSaveFlags</code>,
+ and <code>virDomainManagedSave()</code> functions, and restored
+ via the <code>virDomainRestore()</code>,
+ <code>virDomainRestoreFlags()</code>,
<code>virDomainCreate()</code>,
+ and <code>virDomainCreateWithFlags()</code> functions (as well
+ as via domain autostart). With managed snapshots, libvirt
+ tracks all information internally; with save images, the user
+ tracks the snapshot file, but libvirt provides functions such
+ as <code>virDomainSaveImageGetXMLDesc()</code> to work with
+ those files.
+ </p>
+ <p>System checkpoints are created
+ by <code>virDomainSnapshotCreateXML()</code> with no flags, and
+ disk snapshots are created by the same function with
+ the <code>VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY</code> flag; in
+ both cases, they are restored by
+ the <code>virDomainRevertToSnapshot()</code> function. For
+ these types of snapshots, libvirt tracks each snapshot as a
+ separate <code>virDomainSnapshotPtr</code> object, and maintains
+ a tree relationship of which snapshots descended from an earlier
+ point in time.
+ </p>
+
+ <p>
Attributes of libvirt snapshots are stored as child elements of
the <code>domainsnapshot</code> element. At snapshot creation
time, only the <code>name</code> and
<code>description</code>
@@ -21,9 +76,10 @@
<dl>
<dt><code>name</code></dt>
<dd>The name for this snapshot. If the name is specified when
- initially creating the snapshot, then the snapshot will have
- that particular name. If the name is omitted when initially
- creating the snapshot, then libvirt will make up a name for the snapshot.
+ initially creating the snapshot, then the snapshot will have
+ that particular name. If the name is omitted when initially
+ creating the snapshot, then libvirt will make up a name for the
+ snapshot, based on the time when it was created.
</dd>
<dt><code>description</code></dt>
<dd>A human-readable description of the snapshot. If the
@@ -32,18 +88,25 @@
</dd>
<dt><code>creationTime</code></dt>
<dd>The time this snapshot was created. The time is specified
- in seconds since the Epoch, UTC (i.e. Unix time). Readonly.
+ in seconds since the Epoch, UTC (i.e. Unix time). Readonly.
</dd>
<dt><code>state</code></dt>
- <dd>The state of the domain at the time this snapshot was
- taken. When the domain is reverted to this snapshot, the domain's state
- will be set to whatever is in this field. Readonly.
+ <dd>The state of the domain at the time this snapshot was taken.
+ If the snapshot was created as a system checkpoint, then this
+ is the state of the domain at that time; when the domain is
+ reverted to this snapshot, the domain's state will default to
+ whatever is in this field unless additional flags are passed
+ to <code>virDomainRevertToSnapshot()</code>. Additionally,
+ this field can be the value "disk-snapshot"
+ (<span class="since">since 0.9.5</span>) when it
represents
+ only a disk snapshot (no VM state), and reverting to this
+ snapshot will default to an inactive guest. Readonly.
</dd>
<dt><code>parent</code></dt>
- <dd>The parent of this snapshot. This element contains exactly
- one child element, name. This specifies the name of the parent
- snapshot of this snapshot, and is used to represent trees of
- snapshots. Readonly.
+ <dd>The parent of this snapshot. If present, this element
+ contains exactly one child element, name. This specifies the
+ name of the parent snapshot of this snapshot, and is used to
+ represent trees of snapshots. Readonly.
</dd>
<dt><code>domain</code></dt>
<dd>The domain that this snapshot was taken against. Older
@@ -53,7 +116,7 @@
created in, and requires the use of the
<code>VIR_DOMAIN_SNAPSHOT_REVERT_FORCE</code> flag
in <code>virDomainRevertToSnapshot()</code>. Newer versions
- of libvirt store the entire
+ of libvirt (<span class="since">since 0.9.5</span>) store
the entire
inactive <a href="formatdomain.html">domain
configuration</a>
at the time of the snapshot. Readonly.
</dd>
diff --git a/docs/schemas/domainsnapshot.rng b/docs/schemas/domainsnapshot.rng
index a16d731..130dad9 100644
--- a/docs/schemas/domainsnapshot.rng
+++ b/docs/schemas/domainsnapshot.rng
@@ -22,7 +22,7 @@
</optional>
<optional>
<element name='state'>
- <text/>
+ <ref name='state'/>
</element>
</optional>
<optional>
@@ -59,4 +59,17 @@
</element>
</define>
+ <define name='state'>
+ <choice>
+ <value>nostate</value>
+ <value>running</value>
+ <value>blocked</value>
+ <value>paused</value>
+ <value>shutdown</value>
+ <value>shutoff</value>
+ <value>crashed</value>
+ <value>disk-snapshot</value>
+ </choice>
+ </define>
+
</grammar>
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index e07dc20..c62577d 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -86,7 +86,14 @@ typedef enum {
VIR_DOMAIN_PAUSED = 3, /* the domain is paused by user */
VIR_DOMAIN_SHUTDOWN= 4, /* the domain is being shut down */
VIR_DOMAIN_SHUTOFF = 5, /* the domain is shut off */
- VIR_DOMAIN_CRASHED = 6 /* the domain is crashed */
+ VIR_DOMAIN_CRASHED = 6, /* the domain is crashed */
+
+ /*
+ * NB: this enum value will increase over time as new events are
+ * added to the libvirt API. It reflects the last state supported
+ * by this version of the libvirt API.
+ */
+ VIR_DOMAIN_LAST
} virDomainState;
typedef enum {
@@ -1893,6 +1900,11 @@ typedef enum {
VIR_KEYCODE_SET_USB = 7,
VIR_KEYCODE_SET_WIN32 = 8,
+ /*
+ * NB: this enum value will increase over time as new events are
+ * added to the libvirt API. It reflects the last keycode set supported
+ * by this version of the libvirt API.
+ */
VIR_KEYCODE_SET_LAST,
} virKeycodeSet;
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index df0e921..0713a25 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -420,7 +420,7 @@ VIR_ENUM_IMPL(virDomainHostdevSubsys,
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST,
"usb",
"pci")
-VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1,
+VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_LAST,
"nostate",
"running",
"blocked",
@@ -429,6 +429,17 @@ VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1,
"shutoff",
"crashed")
+/* virDomainSnapshotState is really virDomainState plus one extra state */
+VIR_ENUM_IMPL(virDomainSnapshotState, VIR_DOMAIN_DISK_SNAPSHOT+1,
+ "nostate",
+ "running",
+ "blocked",
+ "paused",
+ "shutdown",
+ "shutoff",
+ "crashed",
+ "disk-snapshot")
+
#define VIR_DOMAIN_NOSTATE_LAST (VIR_DOMAIN_NOSTATE_UNKNOWN + 1)
VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST,
"unknown")
@@ -11052,7 +11063,7 @@ virDomainSnapshotDefParseString(const char *xmlStr,
_("missing state from existing snapshot"));
goto cleanup;
}
- def->state = virDomainStateTypeFromString(state);
+ def->state = virDomainSnapshotStateTypeFromString(state);
if (def->state < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("Invalid state '%s' in domain snapshot
XML"),
@@ -11120,7 +11131,7 @@ char *virDomainSnapshotDefFormat(char *domain_uuid,
virBufferEscapeString(&buf, "
<description>%s</description>\n",
def->description);
virBufferAsprintf(&buf, " <state>%s</state>\n",
- virDomainStateTypeToString(def->state));
+ virDomainSnapshotStateTypeToString(def->state));
if (def->parent) {
virBufferAddLit(&buf, " <parent>\n");
virBufferEscapeString(&buf, " <name>%s</name>\n",
def->parent);
@@ -11712,6 +11723,7 @@ virDomainObjSetState(virDomainObjPtr dom, virDomainState state,
int reason)
case VIR_DOMAIN_SHUTDOWN: last = VIR_DOMAIN_SHUTDOWN_LAST; break;
case VIR_DOMAIN_SHUTOFF: last = VIR_DOMAIN_SHUTOFF_LAST; break;
case VIR_DOMAIN_CRASHED: last = VIR_DOMAIN_CRASHED_LAST; break;
+ default: last = -1;
}
if (last < 0) {
@@ -11745,9 +11757,9 @@ virDomainStateReasonToString(virDomainState state, int reason)
return virDomainShutoffReasonTypeToString(reason);
case VIR_DOMAIN_CRASHED:
return virDomainCrashedReasonTypeToString(reason);
+ default:
+ return NULL;
}
-
- return NULL;
}
@@ -11769,9 +11781,9 @@ virDomainStateReasonFromString(virDomainState state, const char
*reason)
return virDomainShutoffReasonTypeFromString(reason);
case VIR_DOMAIN_CRASHED:
return virDomainCrashedReasonTypeFromString(reason);
+ default:
+ return -1;
}
-
- return -1;
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 7dbf353..ea8194a 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -226,6 +226,11 @@ enum virDomainDiskSnapshot {
VIR_DOMAIN_DISK_SNAPSHOT_LAST
};
+enum virDomainSnapshotState {
+ /* Inherit the VIR_DOMAIN_* states from virDomainState. */
+ VIR_DOMAIN_DISK_SNAPSHOT = VIR_DOMAIN_LAST,
+};
+
/* Stores the virtual disk configuration */
typedef struct _virDomainDiskDef virDomainDiskDef;
typedef virDomainDiskDef *virDomainDiskDefPtr;
@@ -1312,7 +1317,7 @@ struct _virDomainSnapshotDef {
char *description;
char *parent;
long long creationTime; /* in seconds */
- int state;
+ int state; /* enum virDomainSnapshotState */
virDomainDefPtr dom;
/* Internal use. */
@@ -1739,6 +1744,7 @@ VIR_ENUM_DECL(virDomainGraphicsSpicePlaybackCompression)
VIR_ENUM_DECL(virDomainGraphicsSpiceStreamingMode)
VIR_ENUM_DECL(virDomainGraphicsSpiceClipboardCopypaste)
VIR_ENUM_DECL(virDomainNumatuneMemMode)
+VIR_ENUM_DECL(virDomainSnapshotState)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 9530567..034443c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -392,6 +392,8 @@ virDomainSnapshotHasChildren;
virDomainSnapshotObjListGetNames;
virDomainSnapshotObjListNum;
virDomainSnapshotObjListRemove;
+virDomainSnapshotStateTypeFromString;
+virDomainSnapshotStateTypeToString;
virDomainSoundDefFree;
virDomainSoundModelTypeFromString;
virDomainSoundModelTypeToString;
diff --git a/tests/domainsnapshotxml2xmlout/disk_snapshot.xml
b/tests/domainsnapshotxml2xmlout/disk_snapshot.xml
new file mode 100644
index 0000000..391bb57
--- /dev/null
+++ b/tests/domainsnapshotxml2xmlout/disk_snapshot.xml
@@ -0,0 +1,35 @@
+<domainsnapshot>
+ <name>my snap name</name>
+ <description>!@#$%^</description>
+ <parent>
+ <name>earlier_snap</name>
+ </parent>
+ <state>disk-snapshot</state>
+ <creationTime>1272917631</creationTime>
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
+ <active>1</active>
+</domainsnapshot>
diff --git a/tools/virsh.c b/tools/virsh.c
index d4cbbf7..d4581f7 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -14537,6 +14537,8 @@ vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason)
static const char *
vshDomainStateToString(int state)
{
+ /* Can't use virDomainStateTypeToString, because we want to mark
+ * strings for translation. */
switch ((virDomainState) state) {
case VIR_DOMAIN_RUNNING:
return N_("running");
@@ -14551,6 +14553,7 @@ vshDomainStateToString(int state)
case VIR_DOMAIN_CRASHED:
return N_("crashed");
case VIR_DOMAIN_NOSTATE:
+ default:
;/*FALLTHROUGH*/
}
return N_("no state"); /* = dom0 state */
@@ -14652,6 +14655,9 @@ vshDomainStateReasonToString(int state, int reason)
;
}
break;
+
+ default:
+ ;
}
return N_("unknown");
--
1.7.4.4