[libvirt] [PATCHv4 39/51] snapshot: allow halting after snapshot

Eric Blake eblake at redhat.com
Fri Sep 2 04:25:16 UTC 2011


Since a snapshot is fully recoverable, it is useful to have a
snapshot as a means of hibernating a guest, then reverting to
the snapshot to wake the guest up.  This mode of usage is
similar to 'virsh save/virsh restore', except that virsh
save uses an external file while virsh snapshot keeps the
vm state internal to a qcow2 file.  However, it only works on
persistent domains.

In the usage pattern of snapshot/revert for hibernating a guest,
there is no need to keep the guest running between the two points
in time, especially since that would generate runtime state that
would just be discarded.  Add a flag to make it possible to
stop the domain after the snapshot has completed.

* include/libvirt/libvirt.h.in (VIR_DOMAIN_SNAPSHOT_CREATE_HALT):
New flag.
* src/libvirt.c (virDomainSnapshotCreateXML): Document it.
* src/qemu/qemu_driver.c (qemuDomainSnapshotCreateXML)
(qemuDomainSnapshotCreateActive): Implement it.
---
 include/libvirt/libvirt.h.in |    2 ++
 src/libvirt.c                |   12 ++++++++++++
 src/qemu/qemu_driver.c       |   33 +++++++++++++++++++++++++++++----
 3 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 64441d9..b35042c 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2565,6 +2565,8 @@ typedef enum {
                                                           snapshot current */
     VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA = (1 << 2), /* Make snapshot without
                                                           remembering it */
+    VIR_DOMAIN_SNAPSHOT_CREATE_HALT        = (1 << 3), /* Stop running guest
+                                                          after snapshot */
 } virDomainSnapshotCreateFlags;

 /* Take a snapshot of the current VM state */
diff --git a/src/libvirt.c b/src/libvirt.c
index 9b3d2b6..0ae6cc2 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -15632,6 +15632,12 @@ error:
  * the just-created snapshot has its metadata deleted.  This flag is
  * incompatible with VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE.
  *
+ * If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_HALT, then the domain
+ * will be inactive after the snapshot completes, regardless of whether
+ * it was active before; otherwise, a running domain will still be
+ * running after the snapshot.  This flag is invalid on transient domains,
+ * and is incompatible with VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE.
+ *
  * Returns an (opaque) virDomainSnapshotPtr on success, NULL on failure.
  */
 virDomainSnapshotPtr
@@ -15675,6 +15681,12 @@ virDomainSnapshotCreateXML(virDomainPtr domain,
                    _("redefine and no metadata flags are mutually exclusive"));
         goto error;
     }
+    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
+        (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
+        virLibDomainError(VIR_ERR_INVALID_ARG,
+                   _("redefine and halt flags are mutually exclusive"));
+        goto error;
+    }

     if (conn->driver->domainSnapshotCreateXML) {
         virDomainSnapshotPtr ret;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 3aefaef..d3968cf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8678,7 +8678,8 @@ static int
 qemuDomainSnapshotCreateActive(virConnectPtr conn,
                                struct qemud_driver *driver,
                                virDomainObjPtr *vmptr,
-                               virDomainSnapshotObjPtr snap)
+                               virDomainSnapshotObjPtr snap,
+                               unsigned int flags)
 {
     virDomainObjPtr vm = *vmptr;
     qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -8708,6 +8709,24 @@ qemuDomainSnapshotCreateActive(virConnectPtr conn,
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
     ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
     qemuDomainObjExitMonitorWithDriver(driver, vm);
+    if (ret < 0)
+        goto cleanup;
+
+    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
+        virDomainEventPtr event;
+
+        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+        qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+        virDomainAuditStop(vm, "from-snapshot");
+        /* We already filtered the _HALT flag for persistent domains
+         * only, so this end job never drops the last reference.  */
+        ignore_value(qemuDomainObjEndJob(driver, vm));
+        resume = false;
+        vm = NULL;
+        if (event)
+            qemuDomainEventQueue(driver, event);
+    }

 cleanup:
     if (resume && virDomainObjIsActive(vm) &&
@@ -8719,7 +8738,7 @@ cleanup:
                         _("resuming after snapshot failed"));
     }

-    if (qemuDomainObjEndJob(driver, vm) == 0) {
+    if (vm && qemuDomainObjEndJob(driver, vm) == 0) {
         /* Only possible if a transient vm quit while our locks were down,
          * in which case we don't want to save snapshot metadata.  */
         *vmptr = NULL;
@@ -8746,7 +8765,8 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,

     virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                   VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
-                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
+                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
+                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT, NULL);

     if (((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
          !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
@@ -8769,6 +8789,11 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
                         "%s", _("domain is marked for auto destroy"));
         goto cleanup;
     }
+    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                        _("cannot halt after transient domain snapshot"));
+        goto cleanup;
+    }

     if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
                                                 QEMU_EXPECTED_VIRT_TYPES,
@@ -8841,7 +8866,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
             goto cleanup;
     } else {
         if (qemuDomainSnapshotCreateActive(domain->conn, driver,
-                                           &vm, snap) < 0)
+                                           &vm, snap, flags) < 0)
             goto cleanup;
     }

-- 
1.7.4.4




More information about the libvir-list mailing list