]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Finish completed unattended migration
authorJiri Denemark <jdenemar@redhat.com>
Tue, 10 May 2022 13:20:25 +0000 (15:20 +0200)
committerJiri Denemark <jdenemar@redhat.com>
Tue, 7 Jun 2022 15:40:20 +0000 (17:40 +0200)
So far migration could only be completed while a migration API was
running and waiting for the migration to finish. In case such API could
not be called (the connection that initiated the migration is broken)
the migration would just be aborted or left in a "don't know what to do"
state. But this will change soon and we will be able to successfully
complete such migration once we get the corresponding event from QEMU.
This is specific to post-copy migration when vCPUs are already running
on the destination and we're only waiting for all memory pages to be
transferred. Such post-copy migration (which no-one is actively
watching) is called unattended migration.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
src/qemu/qemu_domain.c
src/qemu/qemu_domain.h
src/qemu/qemu_driver.c
src/qemu/qemu_migration.c
src/qemu/qemu_migration.h
src/qemu/qemu_process.c

index 6ad337d4a81b402a96642f28cf9e82db1b003133..941cf7e0e40f3d3a59eabd7dbed52f048f95342e 100644 (file)
@@ -11114,6 +11114,7 @@ qemuProcessEventFree(struct qemuProcessEvent *event)
         qemuMonitorMemoryDeviceSizeChangeFree(event->data);
         break;
     case QEMU_PROCESS_EVENT_PR_DISCONNECT:
+    case QEMU_PROCESS_EVENT_UNATTENDED_MIGRATION:
     case QEMU_PROCESS_EVENT_LAST:
         break;
     }
index ce2dba499c9593db9f908b61586a1aba275b19ae..153dfe3a23e535ab480155d1b9868931139c9851 100644 (file)
@@ -426,6 +426,7 @@ typedef enum {
     QEMU_PROCESS_EVENT_RDMA_GID_STATUS_CHANGED,
     QEMU_PROCESS_EVENT_GUEST_CRASHLOADED,
     QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE,
+    QEMU_PROCESS_EVENT_UNATTENDED_MIGRATION,
 
     QEMU_PROCESS_EVENT_LAST
 } qemuProcessEventType;
index 3ac9da37ddcde68e1dba77854f81edc4983c652e..bc8f5c34db813beaeb99b9a2fd7a38ef78a341eb 100644 (file)
@@ -4312,6 +4312,11 @@ static void qemuProcessEventHandler(void *data, void *opaque)
     case QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE:
         processMemoryDeviceSizeChange(driver, vm, processEvent->data);
         break;
+    case QEMU_PROCESS_EVENT_UNATTENDED_MIGRATION:
+        qemuMigrationProcessUnattended(driver, vm,
+                                       processEvent->action,
+                                       processEvent->status);
+        break;
     case QEMU_PROCESS_EVENT_LAST:
         break;
     }
index d0ce17b9e4a6b9c75d533b23793fa8681503882f..7839874f506cdb43cebcab648d90a30677405daf 100644 (file)
@@ -5811,8 +5811,11 @@ qemuMigrationDstComplete(virQEMUDriver *driver,
 
     qemuDomainSaveStatus(vm);
 
-    /* Guest is successfully running, so cancel previous auto destroy */
-    qemuProcessAutoDestroyRemove(driver, vm);
+    /* Guest is successfully running, so cancel previous auto destroy. There's
+     * nothing to remove when we are resuming post-copy migration.
+     */
+    if (!virDomainObjIsFailedPostcopy(vm))
+        qemuProcessAutoDestroyRemove(driver, vm);
 
     /* Remove completed stats for post-copy, everything but timing fields
      * is obsolete anyway.
@@ -6179,6 +6182,42 @@ qemuMigrationDstFinish(virQEMUDriver *driver,
 }
 
 
+void
+qemuMigrationProcessUnattended(virQEMUDriver *driver,
+                               virDomainObj *vm,
+                               virDomainAsyncJob job,
+                               qemuMonitorMigrationStatus status)
+{
+    qemuDomainObjPrivate *priv = vm->privateData;
+    qemuMigrationJobPhase phase;
+
+    if (!qemuMigrationJobIsActive(vm, job) ||
+        status != QEMU_MONITOR_MIGRATION_STATUS_COMPLETED)
+        return;
+
+    VIR_DEBUG("Unattended %s migration of domain %s successfully finished",
+              job == VIR_ASYNC_JOB_MIGRATION_IN ? "incoming" : "outgoing",
+              vm->def->name);
+
+    if (job == VIR_ASYNC_JOB_MIGRATION_IN)
+        phase = QEMU_MIGRATION_PHASE_FINISH3;
+    else
+        phase = QEMU_MIGRATION_PHASE_CONFIRM3;
+
+    qemuMigrationJobStartPhase(vm, phase);
+
+    if (job == VIR_ASYNC_JOB_MIGRATION_IN)
+        qemuMigrationDstComplete(driver, vm, true, job, &priv->job);
+    else
+        qemuMigrationSrcComplete(driver, vm, job);
+
+    qemuMigrationJobFinish(vm);
+
+    if (!virDomainObjIsActive(vm))
+        qemuDomainRemoveInactive(driver, vm);
+}
+
+
 /* Helper function called while vm is active.  */
 int
 qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
index c099cf99cf2667c122ebbbb389f294b88c1d87fe..eeb69a52bfb64964dd308e4efc1f3135f04cdaaa 100644 (file)
@@ -211,6 +211,12 @@ qemuMigrationSrcComplete(virQEMUDriver *driver,
                          virDomainObj *vm,
                          virDomainAsyncJob asyncJob);
 
+void
+qemuMigrationProcessUnattended(virQEMUDriver *driver,
+                               virDomainObj *vm,
+                               virDomainAsyncJob job,
+                               qemuMonitorMigrationStatus status);
+
 bool
 qemuMigrationSrcIsAllowed(virQEMUDriver *driver,
                           virDomainObj *vm,
index d3769de4961a1b88cd8491a9737cff289ef7d189..97d84893be669d848c0734aee982f0220371d245 100644 (file)
@@ -1549,12 +1549,22 @@ qemuProcessHandleMigrationStatus(qemuMonitor *mon G_GNUC_UNUSED,
         }
         break;
 
+    case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
+        /* A post-copy migration marked as failed when reconnecting to a domain
+         * with running migration may actually still be running, but we're not
+         * watching it in any thread. Let's make sure the migration is properly
+         * finished in case we get a "completed" event.
+         */
+        if (virDomainObjIsFailedPostcopy(vm) && priv->job.asyncOwner == 0)
+            qemuProcessEventSubmit(vm, QEMU_PROCESS_EVENT_UNATTENDED_MIGRATION,
+                                   priv->job.asyncJob, status, NULL);
+        break;
+
     case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
     case QEMU_MONITOR_MIGRATION_STATUS_SETUP:
     case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
     case QEMU_MONITOR_MIGRATION_STATUS_PRE_SWITCHOVER:
     case QEMU_MONITOR_MIGRATION_STATUS_DEVICE:
-    case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
     case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
     case QEMU_MONITOR_MIGRATION_STATUS_CANCELLING:
     case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED: