9c6c51
From 69532ea0b55b307884add6d95d70b998adcea60a Mon Sep 17 00:00:00 2001
9c6c51
Message-Id: <69532ea0b55b307884add6d95d70b998adcea60a@dist-git>
9c6c51
From: Jiri Denemark <jdenemar@redhat.com>
9c6c51
Date: Wed, 12 Sep 2018 14:34:33 +0200
9c6c51
Subject: [PATCH] qemu: Avoid duplicate resume events and state changes
9c6c51
MIME-Version: 1.0
9c6c51
Content-Type: text/plain; charset=UTF-8
9c6c51
Content-Transfer-Encoding: 8bit
9c6c51
9c6c51
The only place where VIR_DOMAIN_EVENT_RESUMED should be generated is the
9c6c51
RESUME event handler to make sure we don't generate duplicate events or
9c6c51
state changes. In the worse case the duplicity can revert or cover
9c6c51
changes done by other event handlers.
9c6c51
9c6c51
For example, after QEMU sent RESUME, BLOCK_IO_ERROR, and STOP events
9c6c51
we could happily mark the domain as running and report
9c6c51
VIR_DOMAIN_EVENT_RESUMED to registered clients.
9c6c51
9c6c51
https://bugzilla.redhat.com/show_bug.cgi?id=1612943
9c6c51
9c6c51
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9c6c51
Reviewed-by: John Ferlan <jferlan@redhat.com>
9c6c51
(cherry picked from commit e6d77a75c4bf0c017d62b717b75e4bb6aa7a456b)
9c6c51
9c6c51
https://bugzilla.redhat.com/show_bug.cgi?id=1634758
9c6c51
https://bugzilla.redhat.com/show_bug.cgi?id=1634759
9c6c51
9c6c51
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9c6c51
Reviewed-by: Ján Tomko <jtomko@redhat.com>
9c6c51
---
9c6c51
 src/qemu/qemu_driver.c    | 13 -----------
9c6c51
 src/qemu/qemu_migration.c | 49 ++++++++++++++++-----------------------
9c6c51
 src/qemu/qemu_process.c   | 10 ++++----
9c6c51
 3 files changed, 24 insertions(+), 48 deletions(-)
9c6c51
9c6c51
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
9c6c51
index ec1a43d41d..bafef1e3b5 100644
9c6c51
--- a/src/qemu/qemu_driver.c
9c6c51
+++ b/src/qemu/qemu_driver.c
9c6c51
@@ -1863,7 +1863,6 @@ static int qemuDomainResume(virDomainPtr dom)
9c6c51
     virQEMUDriverPtr driver = dom->conn->privateData;
9c6c51
     virDomainObjPtr vm;
9c6c51
     int ret = -1;
9c6c51
-    virObjectEventPtr event = NULL;
9c6c51
     int state;
9c6c51
     int reason;
9c6c51
     virQEMUDriverConfigPtr cfg = NULL;
9c6c51
@@ -1902,9 +1901,6 @@ static int qemuDomainResume(virDomainPtr dom)
9c6c51
                                "%s", _("resume operation failed"));
9c6c51
             goto endjob;
9c6c51
         }
9c6c51
-        event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
-                                         VIR_DOMAIN_EVENT_RESUMED,
9c6c51
-                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
9c6c51
     }
9c6c51
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
9c6c51
         goto endjob;
9c6c51
@@ -1915,7 +1911,6 @@ static int qemuDomainResume(virDomainPtr dom)
9c6c51
 
9c6c51
  cleanup:
9c6c51
     virDomainObjEndAPI(&vm;;
9c6c51
-    virObjectEventStateQueue(driver->domainEventState, event);
9c6c51
     virObjectUnref(cfg);
9c6c51
     return ret;
9c6c51
 }
9c6c51
@@ -16033,7 +16028,6 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
9c6c51
     virDomainDefPtr config = NULL;
9c6c51
     virQEMUDriverConfigPtr cfg = NULL;
9c6c51
     virCapsPtr caps = NULL;
9c6c51
-    bool was_running = false;
9c6c51
     bool was_stopped = false;
9c6c51
     qemuDomainSaveCookiePtr cookie;
9c6c51
     virCPUDefPtr origCPU = NULL;
9c6c51
@@ -16224,7 +16218,6 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
9c6c51
             priv = vm->privateData;
9c6c51
             if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
9c6c51
                 /* Transitions 5, 6 */
9c6c51
-                was_running = true;
9c6c51
                 if (qemuProcessStopCPUs(driver, vm,
9c6c51
                                         VIR_DOMAIN_PAUSED_FROM_SNAPSHOT,
9c6c51
                                         QEMU_ASYNC_JOB_START) < 0)
9c6c51
@@ -16321,12 +16314,6 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
9c6c51
                 event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
                                                  VIR_DOMAIN_EVENT_STARTED,
9c6c51
                                                  detail);
9c6c51
-            } else if (!was_running) {
9c6c51
-                /* Transition 8 */
9c6c51
-                detail = VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT;
9c6c51
-                event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
-                                                 VIR_DOMAIN_EVENT_RESUMED,
9c6c51
-                                                 detail);
9c6c51
             }
9c6c51
         }
9c6c51
         break;
9c6c51
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
9c6c51
index 825a9d399b..67940330aa 100644
9c6c51
--- a/src/qemu/qemu_migration.c
9c6c51
+++ b/src/qemu/qemu_migration.c
9c6c51
@@ -2982,14 +2982,10 @@ qemuMigrationSrcConfirmPhase(virQEMUDriverPtr driver,
9c6c51
         virFreeError(orig_err);
9c6c51
 
9c6c51
         if (virDomainObjGetState(vm, &reason) == VIR_DOMAIN_PAUSED &&
9c6c51
-            reason == VIR_DOMAIN_PAUSED_POSTCOPY) {
9c6c51
+            reason == VIR_DOMAIN_PAUSED_POSTCOPY)
9c6c51
             qemuMigrationAnyPostcopyFailed(driver, vm);
9c6c51
-        } else if (qemuMigrationSrcRestoreDomainState(driver, vm)) {
9c6c51
-            event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
-                                                      VIR_DOMAIN_EVENT_RESUMED,
9c6c51
-                                                      VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
9c6c51
-            virObjectEventStateQueue(driver->domainEventState, event);
9c6c51
-        }
9c6c51
+        else
9c6c51
+            qemuMigrationSrcRestoreDomainState(driver, vm);
9c6c51
 
9c6c51
         qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
9c6c51
                                  priv->job.migParams, priv->job.apiFlags);
9c6c51
@@ -4624,11 +4620,7 @@ qemuMigrationSrcPerformJob(virQEMUDriverPtr driver,
9c6c51
         qemuMigrationParamsReset(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
9c6c51
                                  priv->job.migParams, priv->job.apiFlags);
9c6c51
 
9c6c51
-    if (qemuMigrationSrcRestoreDomainState(driver, vm)) {
9c6c51
-        event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
-                                         VIR_DOMAIN_EVENT_RESUMED,
9c6c51
-                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
9c6c51
-    }
9c6c51
+    qemuMigrationSrcRestoreDomainState(driver, vm);
9c6c51
 
9c6c51
     qemuMigrationJobFinish(driver, vm);
9c6c51
     if (!virDomainObjIsActive(vm) && ret == 0) {
9c6c51
@@ -4672,7 +4664,6 @@ qemuMigrationSrcPerformPhase(virQEMUDriverPtr driver,
9c6c51
                              unsigned long resource)
9c6c51
 {
9c6c51
     qemuDomainObjPrivatePtr priv = vm->privateData;
9c6c51
-    virObjectEventPtr event = NULL;
9c6c51
     int ret = -1;
9c6c51
 
9c6c51
     /* If we didn't start the job in the begin phase, start it now. */
9c6c51
@@ -4694,11 +4685,7 @@ qemuMigrationSrcPerformPhase(virQEMUDriverPtr driver,
9c6c51
                                         nmigrate_disks, migrate_disks, migParams);
9c6c51
 
9c6c51
     if (ret < 0) {
9c6c51
-        if (qemuMigrationSrcRestoreDomainState(driver, vm)) {
9c6c51
-            event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
-                                                      VIR_DOMAIN_EVENT_RESUMED,
9c6c51
-                                                      VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
9c6c51
-        }
9c6c51
+        qemuMigrationSrcRestoreDomainState(driver, vm);
9c6c51
         goto endjob;
9c6c51
     }
9c6c51
 
9c6c51
@@ -4722,7 +4709,6 @@ qemuMigrationSrcPerformPhase(virQEMUDriverPtr driver,
9c6c51
 
9c6c51
  cleanup:
9c6c51
     virDomainObjEndAPI(&vm;;
9c6c51
-    virObjectEventStateQueue(driver->domainEventState, event);
9c6c51
     return ret;
9c6c51
 }
9c6c51
 
9c6c51
@@ -5074,13 +5060,8 @@ qemuMigrationDstFinish(virQEMUDriverPtr driver,
9c6c51
                 goto endjob;
9c6c51
         }
9c6c51
 
9c6c51
-        if (inPostCopy) {
9c6c51
+        if (inPostCopy)
9c6c51
             doKill = false;
9c6c51
-            event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
-                                        VIR_DOMAIN_EVENT_RESUMED,
9c6c51
-                                        VIR_DOMAIN_EVENT_RESUMED_POSTCOPY);
9c6c51
-            virObjectEventStateQueue(driver->domainEventState, event);
9c6c51
-        }
9c6c51
     }
9c6c51
 
9c6c51
     if (mig->jobInfo) {
9c6c51
@@ -5111,10 +5092,20 @@ qemuMigrationDstFinish(virQEMUDriverPtr driver,
9c6c51
 
9c6c51
     dom = virGetDomain(dconn, vm->def->name, vm->def->uuid, vm->def->id);
9c6c51
 
9c6c51
-    event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
-                                              VIR_DOMAIN_EVENT_RESUMED,
9c6c51
-                                              VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
9c6c51
-    virObjectEventStateQueue(driver->domainEventState, event);
9c6c51
+    if (inPostCopy) {
9c6c51
+        /* The only RESUME event during post-copy migration is triggered by
9c6c51
+         * QEMU when the running domain moves from the source to the
9c6c51
+         * destination host, but then the migration keeps running until all
9c6c51
+         * modified memory is transferred from the source host. This will
9c6c51
+         * result in VIR_DOMAIN_EVENT_RESUMED with RESUMED_POSTCOPY detail.
9c6c51
+         * However, our API documentation says we need to fire another RESUMED
9c6c51
+         * event at the very end of migration with RESUMED_MIGRATED detail.
9c6c51
+         */
9c6c51
+        event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
+                                                  VIR_DOMAIN_EVENT_RESUMED,
9c6c51
+                                                  VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
9c6c51
+        virObjectEventStateQueue(driver->domainEventState, event);
9c6c51
+    }
9c6c51
 
9c6c51
     if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
9c6c51
         virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
9c6c51
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
9c6c51
index 37568165b7..2d51c0fa25 100644
9c6c51
--- a/src/qemu/qemu_process.c
9c6c51
+++ b/src/qemu/qemu_process.c
9c6c51
@@ -436,7 +436,6 @@ qemuProcessFakeReboot(void *opaque)
9c6c51
     virDomainObjPtr vm = opaque;
9c6c51
     qemuDomainObjPrivatePtr priv = vm->privateData;
9c6c51
     virQEMUDriverPtr driver = priv->driver;
9c6c51
-    virObjectEventPtr event = NULL;
9c6c51
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
9c6c51
     virDomainRunningReason reason = VIR_DOMAIN_RUNNING_BOOTED;
9c6c51
     int ret = -1, rc;
9c6c51
@@ -473,9 +472,6 @@ qemuProcessFakeReboot(void *opaque)
9c6c51
         goto endjob;
9c6c51
     }
9c6c51
     priv->gotShutdown = false;
9c6c51
-    event = virDomainEventLifecycleNewFromObj(vm,
9c6c51
-                                     VIR_DOMAIN_EVENT_RESUMED,
9c6c51
-                                     VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
9c6c51
 
9c6c51
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
9c6c51
         VIR_WARN("Unable to save status on vm %s after state change",
9c6c51
@@ -491,7 +487,6 @@ qemuProcessFakeReboot(void *opaque)
9c6c51
     if (ret == -1)
9c6c51
         ignore_value(qemuProcessKill(vm, VIR_QEMU_PROCESS_KILL_FORCE));
9c6c51
     virDomainObjEndAPI(&vm;;
9c6c51
-    virObjectEventStateQueue(driver->domainEventState, event);
9c6c51
     virObjectUnref(cfg);
9c6c51
 }
9c6c51
 
9c6c51
@@ -3073,7 +3068,10 @@ qemuProcessStartCPUs(virQEMUDriverPtr driver, virDomainObjPtr vm,
9c6c51
     if (ret < 0)
9c6c51
         goto release;
9c6c51
 
9c6c51
-    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
9c6c51
+    /* The RESUME event handler will change the domain state with the reason
9c6c51
+     * saved in priv->runningReason and it will also emit corresponding domain
9c6c51
+     * lifecycle event.
9c6c51
+     */
9c6c51
 
9c6c51
  cleanup:
9c6c51
     virObjectUnref(cfg);
9c6c51
-- 
9c6c51
2.19.1
9c6c51