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