[libvirt] [PATCH 7/7] qemu: snapshot: Correctly revert snapshots in PMSUSPENDED state

Peter Krempa pkrempa at redhat.com
Fri Jul 18 16:11:57 UTC 2014


PMSUSPENDED state implies the qemu process running, so we should treat
it that way. This increases the possible state space of transitions that
may happen during the snapshot revert so this patch documents them as
well.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1079162
---
 src/qemu/qemu_driver.c | 67 ++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 48 insertions(+), 19 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1f98f4a..f93e0fd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -14052,22 +14052,29 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
     virDomainDefPtr config = NULL;
     virQEMUDriverConfigPtr cfg = NULL;
     virCapsPtr caps = NULL;
-    int oldState = vm->state.state;
+    int oldState;

     virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
                   VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                   VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);

     /* We have the following transitions, which create the following events:
-     * 1. inactive -> inactive: none
-     * 2. inactive -> running:  EVENT_STARTED
-     * 3. inactive -> paused:   EVENT_STARTED, EVENT_PAUSED
-     * 4. running  -> inactive: EVENT_STOPPED
-     * 5. running  -> running:  none
-     * 6. running  -> paused:   EVENT_PAUSED
-     * 7. paused   -> inactive: EVENT_STOPPED
-     * 8. paused   -> running:  EVENT_RESUMED
-     * 9. paused   -> paused:   none
+     * 1.  inactive    -> inactive:    none
+     * 2.  inactive    -> running:     EVENT_STARTED
+     * 3.  inactive    -> paused:      EVENT_STARTED, EVENT_PAUSED
+     * 4.  running     -> inactive:    EVENT_STOPPED
+     * 5.  running     -> running:     none
+     * 6.  running     -> paused:      EVENT_PAUSED
+     * 7.  paused      -> inactive:    EVENT_STOPPED
+     * 8.  paused      -> running:     EVENT_RESUMED
+     * 9.  paused      -> paused:      none
+     * 10. pmsuspended -> pmsuspended: none
+     * 11. pmsuspended -> inactive:    EVENT_STOPPED
+     * 12. pmsuspended -> running:     EVENT_RESUMED
+     * 13. pmsuspended -> paused:      EVENT_PAUSED
+     * 14. inactive    -> pmsuspended: EVENT_STARTED, EVENT_PMSUSPENDED
+     * 15. paused      -> pmsuspended: EVENT_PMSUSPENDED
+     * 16. running     -> pmsuspended: EVENT_PMSUSPENDED
      * Also, several transitions occur even if we fail partway through,
      * and use of FORCE can cause multiple transitions.
      */
@@ -14075,6 +14082,8 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
     if (!(vm = qemuDomObjFromSnapshot(snapshot)))
         return -1;

+    oldState = vm->state.state;
+
     cfg = virQEMUDriverGetConfig(driver);

     if (virDomainRevertToSnapshotEnsureACL(snapshot->domain->conn, vm->def) < 0)
@@ -14127,6 +14136,14 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
         }
     }

+    if (snap->def->state == VIR_DOMAIN_PMSUSPENDED &&
+        (flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING ||
+         flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("snapshot of a VM in PMSUSPENDED state cannot be "
+                         "reverted to a running or paused state"));
+        goto cleanup;
+    }

     if (vm->current_snapshot) {
         vm->current_snapshot->def->current = false;
@@ -14156,14 +14173,17 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
     switch ((virDomainState) snap->def->state) {
     case VIR_DOMAIN_RUNNING:
     case VIR_DOMAIN_PAUSED:
-        /* Transitions 2, 3, 5, 6, 8, 9 */
+    case VIR_DOMAIN_PMSUSPENDED:
+        /* New state of the domain requires a running qemu process */
+        /* Transitions 2, 3, 5, 6, 8, 9, 10, 12, 13, 14, 15, 16 */
+
         /* When using the loadvm monitor command, qemu does not know
          * whether to pause or run the reverted domain, and just stays
          * in the same state as before the monitor command, whether
          * that is paused or running.  We always pause before loadvm,
          * to have finer control.  */
         if (virDomainObjIsActive(vm)) {
-            /* Transitions 5, 6, 8, 9 */
+            /* Transitions 5, 6, 8, 9, 10, 12, 13, 15, 16 */
             /* Check for ABI compatibility. We need to do this check against
              * the migratable XML or it will always fail otherwise */
             if (config && !qemuDomainDefCheckABIStability(driver, vm->def, config)) {
@@ -14189,7 +14209,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,

             priv = vm->privateData;
             if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
-                /* Transitions 5, 6 */
+                /* Transitions 5, 6, 16*/
                 if (qemuProcessStopCPUs(driver, vm,
                                         VIR_DOMAIN_PAUSED_FROM_SNAPSHOT,
                                         QEMU_ASYNC_JOB_NONE) < 0)
@@ -14212,7 +14232,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
             if (config)
                 virDomainObjAssignDef(vm, config, false, NULL);
         } else {
-            /* Transitions 2, 3 */
+            /* Transitions 2, 3, 14 */
         load:
             if (config)
                 virDomainObjAssignDef(vm, config, false, NULL);
@@ -14234,6 +14254,16 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
             /* Transitions 3, 6, 9 */
             virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                                  VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
+        } else if (snap->def->state == VIR_DOMAIN_PMSUSPENDED) {
+            /* actually start the CPUs, as they are suspended differently */
+            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
+                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
+                                      QEMU_ASYNC_JOB_NONE);
+            if (rc < 0)
+                goto endjob;
+            /* now fix up the state to suspended */
+            virDomainObjSetState(vm, VIR_DOMAIN_PMSUSPENDED,
+                                 VIR_DOMAIN_PMSUSPENDED_FROM_SNAPSHOT);
         } else {
             /* Transitions 2, 5, 8 */
             if (!virDomainObjIsActive(vm)) {
@@ -14252,16 +14282,15 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
     case VIR_DOMAIN_SHUTDOWN:
     case VIR_DOMAIN_SHUTOFF:
     case VIR_DOMAIN_CRASHED:
-        /* XXX: The following one is clearly wrong! */
-    case VIR_DOMAIN_PMSUSPENDED:
-        /* Transitions 1, 4, 7 */
+        /* qemu will not run after the snapshot revertion */
+        /* Transitions 1, 4, 7, 11 */
+
         /* Newer qemu -loadvm refuses to revert to the state of a snapshot
          * created by qemu-img snapshot -c.  If the domain is running, we
          * must take it offline; then do the revert using qemu-img.
          */
-
         if (virDomainObjIsActive(vm)) {
-            /* Transitions 4, 7 */
+            /* Transitions 4, 7, 11 */
             qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
             virDomainAuditStop(vm, "from-snapshot");
             qemuDomainSnapshotEmitLifecycleEvent(driver, vm, vm->state.state,
-- 
2.0.0




More information about the libvir-list mailing list