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