[libvirt] [PATCH 33/26] snapshot: support extra state in snapshots

Eric Blake eblake at redhat.com
Fri Aug 19 00:07:45 UTC 2011


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.
* 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.
(cmdList): Translate state output.
* 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                      |   82 +++++++++++++++++++---
 docs/schemas/domainsnapshot.rng                  |   15 ++++-
 include/libvirt/libvirt.h.in                     |   14 ++++-
 src/conf/domain_conf.c                           |   26 +++++--
 src/conf/domain_conf.h                           |    3 +-
 src/libvirt_private.syms                         |    2 +
 tests/domainsnapshotxml2xmlout/disk_snapshot.xml |   35 +++++++++
 tools/virsh.c                                    |   10 ++-
 8 files changed, 165 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..21c83a0 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
@@ -35,15 +91,21 @@
       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" 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
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 5903f65..d5784e1 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_LAST+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,
         virBufferAsprintf(&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");
         virBufferAsprintf(&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..863d64f 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1312,7 +1312,7 @@ struct _virDomainSnapshotDef {
     char *description;
     char *parent;
     long long creationTime; /* in seconds */
-    int state;
+    int state; /* enum virDomainSnapshotState */
     virDomainDefPtr dom;

     /* Internal use.  */
@@ -1739,6 +1739,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 49ce814..27d0d6f 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -920,7 +920,7 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
         vshPrint(ctl, "%3d %-20s %s\n",
                  virDomainGetID(dom),
                  virDomainGetName(dom),
-                 vshDomainStateToString(vshDomainState(ctl, dom, NULL)));
+                 _(vshDomainStateToString(vshDomainState(ctl, dom, NULL))));
         virDomainFree(dom);
     }
     for (i = 0; i < maxname; i++) {
@@ -935,7 +935,7 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
         vshPrint(ctl, "%3s %-20s %s\n",
                  "-",
                  names[i],
-                 vshDomainStateToString(vshDomainState(ctl, dom, NULL)));
+                 _(vshDomainStateToString(vshDomainState(ctl, dom, NULL))));

         virDomainFree(dom);
         VIR_FREE(names[i]);
@@ -14521,6 +14521,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");
@@ -14535,6 +14537,7 @@ vshDomainStateToString(int state)
     case VIR_DOMAIN_CRASHED:
         return N_("crashed");
     case VIR_DOMAIN_NOSTATE:
+    default:
         ;/*FALLTHROUGH*/
     }
     return N_("no state");  /* = dom0 state */
@@ -14636,6 +14639,9 @@ vshDomainStateReasonToString(int state, int reason)
             ;
         }
         break;
+
+    default:
+        ;
     }

     return N_("unknown");
-- 
1.7.4.4




More information about the libvir-list mailing list