[libvirt] [PATCH 01/10] qemu: Implement migration job phases

Jiri Denemark jdenemar at redhat.com
Tue Jul 19 00:27:30 UTC 2011


This patch introduces several helper methods to deal with jobs and
phases during migration in a simpler manner.
---
 src/qemu/MIGRATION.txt    |   55 +++++++++++++++++++++++++++
 src/qemu/qemu_domain.c    |    5 ++
 src/qemu/qemu_migration.c |   91 +++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_migration.h |   37 ++++++++++++++++++
 4 files changed, 188 insertions(+), 0 deletions(-)
 create mode 100644 src/qemu/MIGRATION.txt

diff --git a/src/qemu/MIGRATION.txt b/src/qemu/MIGRATION.txt
new file mode 100644
index 0000000..6c32998
--- /dev/null
+++ b/src/qemu/MIGRATION.txt
@@ -0,0 +1,55 @@
+    QEMU Migration Locking Rules
+    ============================
+
+Migration is a complicated beast which may span across several APIs on both
+source and destination side and we need to keep the domain we are migrating in
+a consistent state during the whole process.
+
+To avoid anyone from changing the domain in the middle of migration we need to
+keep MIGRATION_OUT job active during migration from Begin to Confirm on the
+source side and MIGRATION_IN job has to be active from Prepare to Finish on
+the destination side.
+
+For this purpose we introduce several helper methods to deal with locking
+primitives (described in THREADS.txt) in the right way:
+
+* qemuMigrationJobStart
+
+* qemuMigrationJobContinue
+
+* qemuMigrationJobStartPhase
+
+* qemuMigrationJobSetPhase
+
+* qemuMigrationJobFinish
+
+The sequence of calling qemuMigrationJob* helper methods is as follows:
+
+- The first API of a migration protocol (Prepare or Perform/Begin depending on
+  migration type and version) has to start migration job and keep it active:
+
+      qemuMigrationJobStart(driver, vm, QEMU_JOB_MIGRATION_{IN,OUT});
+      qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_*);
+      ...do work...
+      qemuMigrationJobContinue(vm);
+
+- All consequent phases except for the last one have to keep the job active:
+
+      if (!qemuMigrationJobIsActive(vm, QEMU_JOB_MIGRATION_{IN,OUT}))
+          return;
+      qemuMigrationJobStartPhase(driver, vm, QEMU_MIGRATION_PHASE_*);
+      ...do work...
+      qemuMigrationJobContinue(vm);
+
+- The last migration phase finally finishes the migration job:
+
+      if (!qemuMigrationJobIsActive(vm, QEMU_JOB_MIGRATION_{IN,OUT}))
+          return;
+      qemuMigrationJobStartPhase(driver, vm, QEMU_MIGRATION_PHASE_*);
+      ...do work...
+      qemuMigrationJobFinish(driver, vm);
+
+While migration job is running (i.e., after qemuMigrationJobStart* but before
+qemuMigrationJob{Continue,Finish}), migration phase can be advanced using
+
+      qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_*);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index f9755a4..fee562d 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -26,6 +26,7 @@
 #include "qemu_domain.h"
 #include "qemu_command.h"
 #include "qemu_capabilities.h"
+#include "qemu_migration.h"
 #include "memory.h"
 #include "logging.h"
 #include "virterror_internal.h"
@@ -72,6 +73,8 @@ qemuDomainAsyncJobPhaseToString(enum qemuDomainAsyncJob job,
     switch (job) {
     case QEMU_ASYNC_JOB_MIGRATION_OUT:
     case QEMU_ASYNC_JOB_MIGRATION_IN:
+        return qemuMigrationJobPhaseTypeToString(phase);
+
     case QEMU_ASYNC_JOB_SAVE:
     case QEMU_ASYNC_JOB_DUMP:
     case QEMU_ASYNC_JOB_NONE:
@@ -92,6 +95,8 @@ qemuDomainAsyncJobPhaseFromString(enum qemuDomainAsyncJob job,
     switch (job) {
     case QEMU_ASYNC_JOB_MIGRATION_OUT:
     case QEMU_ASYNC_JOB_MIGRATION_IN:
+        return qemuMigrationJobPhaseTypeFromString(phase);
+
     case QEMU_ASYNC_JOB_SAVE:
     case QEMU_ASYNC_JOB_DUMP:
     case QEMU_ASYNC_JOB_NONE:
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index dfa80e3..9659e8d 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -46,6 +46,19 @@
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
+VIR_ENUM_IMPL(qemuMigrationJobPhase, QEMU_MIGRATION_PHASE_LAST,
+              "none",
+              "preform2",
+              "begin3",
+              "perform3",
+              "perform3_done",
+              "confirm3_cancelled",
+              "confirm3",
+              "prepare",
+              "finish2",
+              "finish3",
+);
+
 enum qemuMigrationCookieFlags {
     QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS,
     QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE,
@@ -2770,3 +2783,81 @@ cleanup:
     }
     return ret;
 }
+
+int
+qemuMigrationJobStart(struct qemud_driver *driver,
+                      virDomainObjPtr vm,
+                      enum qemuDomainAsyncJob job)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+
+    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm, job) < 0)
+        return -1;
+
+    if (job == QEMU_ASYNC_JOB_MIGRATION_IN)
+        qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_NONE);
+    else
+        qemuDomainObjSetAsyncJobMask(vm, DEFAULT_JOB_MASK);
+
+    priv->job.info.type = VIR_DOMAIN_JOB_UNBOUNDED;
+
+    return 0;
+}
+
+void
+qemuMigrationJobSetPhase(struct qemud_driver *driver,
+                         virDomainObjPtr vm,
+                         enum qemuMigrationJobPhase phase)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+
+    if (phase < priv->job.phase) {
+        VIR_ERROR(_("migration protocol going backwards %s => %s"),
+                  qemuMigrationJobPhaseTypeToString(priv->job.phase),
+                  qemuMigrationJobPhaseTypeToString(phase));
+        return;
+    }
+
+    qemuDomainObjSetJobPhase(driver, vm, phase);
+}
+
+void
+qemuMigrationJobStartPhase(struct qemud_driver *driver,
+                           virDomainObjPtr vm,
+                           enum qemuMigrationJobPhase phase)
+{
+    virDomainObjRef(vm);
+    qemuMigrationJobSetPhase(driver, vm, phase);
+}
+
+int
+qemuMigrationJobContinue(virDomainObjPtr vm)
+{
+    return virDomainObjUnref(vm);
+}
+
+bool
+qemuMigrationJobIsActive(virDomainObjPtr vm,
+                         enum qemuDomainAsyncJob job)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+
+    if (priv->job.asyncJob != job) {
+        const char *msg;
+
+        if (job == QEMU_ASYNC_JOB_MIGRATION_IN)
+            msg = _("domain '%s' is not processing incoming migration");
+        else
+            msg = _("domain '%s' is not being migrated");
+
+        qemuReportError(VIR_ERR_OPERATION_INVALID, msg, vm->def->name);
+        return false;
+    }
+    return true;
+}
+
+int
+qemuMigrationJobFinish(struct qemud_driver *driver, virDomainObjPtr vm)
+{
+    return qemuDomainObjEndAsyncJob(driver, vm);
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 3a9b94e..005e415 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -23,6 +23,7 @@
 # define __QEMU_MIGRATION_H__
 
 # include "qemu_conf.h"
+# include "qemu_domain.h"
 
 /* All supported qemu migration flags.  */
 # define QEMU_MIGRATION_FLAGS                   \
@@ -35,6 +36,42 @@
      VIR_MIGRATE_NON_SHARED_DISK |              \
      VIR_MIGRATE_NON_SHARED_INC)
 
+enum qemuMigrationJobPhase {
+    QEMU_MIGRATION_PHASE_NONE = 0,
+    QEMU_MIGRATION_PHASE_PERFORM2,
+    QEMU_MIGRATION_PHASE_BEGIN3,
+    QEMU_MIGRATION_PHASE_PERFORM3,
+    QEMU_MIGRATION_PHASE_PERFORM3_DONE,
+    QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED,
+    QEMU_MIGRATION_PHASE_CONFIRM3,
+    QEMU_MIGRATION_PHASE_PREPARE,
+    QEMU_MIGRATION_PHASE_FINISH2,
+    QEMU_MIGRATION_PHASE_FINISH3,
+
+    QEMU_MIGRATION_PHASE_LAST
+};
+VIR_ENUM_DECL(qemuMigrationJobPhase)
+
+int qemuMigrationJobStart(struct qemud_driver *driver,
+                          virDomainObjPtr vm,
+                          enum qemuDomainAsyncJob job)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+void qemuMigrationJobSetPhase(struct qemud_driver *driver,
+                              virDomainObjPtr vm,
+                              enum qemuMigrationJobPhase phase)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+void qemuMigrationJobStartPhase(struct qemud_driver *driver,
+                                virDomainObjPtr vm,
+                                enum qemuMigrationJobPhase phase)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMigrationJobContinue(virDomainObjPtr obj)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+bool qemuMigrationJobIsActive(virDomainObjPtr vm,
+                              enum qemuDomainAsyncJob job)
+    ATTRIBUTE_NONNULL(1);
+int qemuMigrationJobFinish(struct qemud_driver *driver, virDomainObjPtr obj)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+
 bool qemuMigrationIsAllowed(virDomainDefPtr def)
     ATTRIBUTE_NONNULL(1);
 int qemuMigrationSetOffline(struct qemud_driver *driver,
-- 
1.7.6




More information about the libvir-list mailing list