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