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