[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 02/14] qemu: Add support for compressed migration



---
 src/qemu/qemu_migration.c    |  59 ++++++++++++++++++++--
 src/qemu/qemu_migration.h    |   3 +-
 src/qemu/qemu_monitor.c      |  43 ++++++++++++++++
 src/qemu/qemu_monitor.h      |  13 +++++
 src/qemu/qemu_monitor_json.c | 118 +++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor_json.h |   5 ++
 6 files changed, 237 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 11d7d6c..de8dfec 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1150,6 +1150,47 @@ qemuMigrationSetOffline(virQEMUDriverPtr driver,
 
 
 static int
+qemuMigrationSetCompression(virQEMUDriverPtr driver,
+                            virDomainObjPtr vm,
+                            enum qemuDomainAsyncJob job)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    int ret;
+
+    if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0)
+        return -1;
+
+    ret = qemuMonitorGetMigrationCapability(
+                priv->mon,
+                QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);
+
+    if (ret < 0) {
+        goto cleanup;
+    } else if (ret == 0) {
+        if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("Compressed migration is not supported by "
+                             "target QEMU binary"));
+        } else {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("Compressed migration is not supported by "
+                             "source QEMU binary"));
+        }
+        ret = -1;
+        goto cleanup;
+    }
+
+    ret = qemuMonitorSetMigrationCapability(
+                priv->mon,
+                QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);
+
+cleanup:
+    qemuDomainObjExitMonitor(driver, vm);
+    return ret;
+}
+
+
+static int
 qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              const char *job,
@@ -1704,13 +1745,16 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
         if (virFDStreamOpen(st, dataFD[1]) < 0) {
             virReportSystemError(errno, "%s",
                                  _("cannot pass pipe for tunnelled migration"));
-            virDomainAuditStart(vm, "migrated", false);
-            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
-            goto endjob;
+            goto stop;
         }
         dataFD[1] = -1; /* 'st' owns the FD now & will close it */
     }
 
+    if (flags & VIR_MIGRATE_COMPRESSED &&
+        qemuMigrationSetCompression(driver, vm,
+                                    QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
+        goto stop;
+
     if (mig->lockState) {
         VIR_DEBUG("Received lockstate %s", mig->lockState);
         VIR_FREE(priv->lockState);
@@ -1776,6 +1820,10 @@ cleanup:
     virObjectUnref(caps);
     return ret;
 
+stop:
+    virDomainAuditStart(vm, "migrated", false);
+    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
+
 endjob:
     if (!qemuMigrationJobFinish(driver, vm)) {
         vm = NULL;
@@ -2255,6 +2303,11 @@ qemuMigrationRun(virQEMUDriverPtr driver,
             goto cleanup;
     }
 
+    if (flags & VIR_MIGRATE_COMPRESSED &&
+        qemuMigrationSetCompression(driver, vm,
+                                    QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
+        goto cleanup;
+
     if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                        QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
         goto cleanup;
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 1729d73..505e911 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -37,7 +37,8 @@
      VIR_MIGRATE_NON_SHARED_INC |               \
      VIR_MIGRATE_CHANGE_PROTECTION |            \
      VIR_MIGRATE_UNSAFE |                       \
-     VIR_MIGRATE_OFFLINE)
+     VIR_MIGRATE_OFFLINE |                      \
+     VIR_MIGRATE_COMPRESSED)
 
 enum qemuMigrationJobPhase {
     QEMU_MIGRATION_PHASE_NONE = 0,
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 7af571d..631ff92 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -101,6 +101,10 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus,
               QEMU_MONITOR_MIGRATION_STATUS_LAST,
               "inactive", "active", "completed", "failed", "cancelled")
 
+VIR_ENUM_IMPL(qemuMonitorMigrationCaps,
+              QEMU_MONITOR_MIGRATION_CAPS_LAST,
+              "xbzrle")
+
 VIR_ENUM_IMPL(qemuMonitorVMStatus,
               QEMU_MONITOR_VM_STATUS_LAST,
               "debug", "inmigrate", "internal-error", "io-error", "paused",
@@ -3383,3 +3387,42 @@ char *qemuMonitorGetTargetArch(qemuMonitorPtr mon)
 
     return qemuMonitorJSONGetTargetArch(mon);
 }
+
+
+int qemuMonitorGetMigrationCapability(qemuMonitorPtr mon,
+                                      qemuMonitorMigrationCaps capability)
+{
+    VIR_DEBUG("mon=%p capability=%d", mon, capability);
+
+    if (!mon) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("monitor must not be NULL"));
+        return -1;
+    }
+
+    /* No capability is supported without JSON monitor */
+    if (!mon->json)
+        return 0;
+
+    return qemuMonitorJSONGetMigrationCapability(mon, capability);
+}
+
+int qemuMonitorSetMigrationCapability(qemuMonitorPtr mon,
+                                      qemuMonitorMigrationCaps capability)
+{
+    VIR_DEBUG("mon=%p capability=%d", mon, capability);
+
+    if (!mon) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("monitor must not be NULL"));
+        return -1;
+    }
+
+    if (!mon->json) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("JSON monitor is required"));
+        return -1;
+    }
+
+    return qemuMonitorJSONSetMigrationCapability(mon, capability);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index ac77158..e3a4568 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -347,6 +347,19 @@ int qemuMonitorGetSpiceMigrationStatus(qemuMonitorPtr mon,
                                        bool *spice_migrated);
 
 typedef enum {
+    QEMU_MONITOR_MIGRATION_CAPS_XBZRLE,
+
+    QEMU_MONITOR_MIGRATION_CAPS_LAST
+} qemuMonitorMigrationCaps;
+
+VIR_ENUM_DECL(qemuMonitorMigrationCaps);
+
+int qemuMonitorGetMigrationCapability(qemuMonitorPtr mon,
+                                      qemuMonitorMigrationCaps capability);
+int qemuMonitorSetMigrationCapability(qemuMonitorPtr mon,
+                                      qemuMonitorMigrationCaps capability);
+
+typedef enum {
   QEMU_MONITOR_MIGRATE_BACKGROUND	= 1 << 0,
   QEMU_MONITOR_MIGRATE_NON_SHARED_DISK  = 1 << 1, /* migration with non-shared storage with full disk copy */
   QEMU_MONITOR_MIGRATE_NON_SHARED_INC   = 1 << 2, /* migration with non-shared storage with incremental copy */
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index a86d90c..545d4d4 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4359,3 +4359,121 @@ cleanup:
     virJSONValueFree(reply);
     return ret;
 }
+
+
+int
+qemuMonitorJSONGetMigrationCapability(qemuMonitorPtr mon,
+                                      qemuMonitorMigrationCaps capability)
+{
+    int ret;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    virJSONValuePtr caps;
+    int i;
+
+    if (!(cmd = qemuMonitorJSONMakeCommand("query-migrate-capabilities",
+                                           NULL)))
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0) {
+        if (qemuMonitorJSONHasError(reply, "CommandNotFound"))
+            goto cleanup;
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+    }
+
+    if (ret < 0)
+        goto cleanup;
+
+    ret = -1;
+
+    caps = virJSONValueObjectGet(reply, "return");
+    if (!caps || caps->type != VIR_JSON_TYPE_ARRAY) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("missing migration capabilities"));
+        goto cleanup;
+    }
+
+    for (i = 0; i < virJSONValueArraySize(caps); i++) {
+        virJSONValuePtr cap = virJSONValueArrayGet(caps, i);
+        const char *name;
+
+        if (!cap || cap->type != VIR_JSON_TYPE_OBJECT) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing entry in migration capabilities list"));
+            goto cleanup;
+        }
+
+        if (!(name = virJSONValueObjectGetString(cap, "capability"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing migration capability name"));
+            goto cleanup;
+        }
+
+        if (qemuMonitorMigrationCapsTypeFromString(name) == capability) {
+            ret = 1;
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+
+cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int
+qemuMonitorJSONSetMigrationCapability(qemuMonitorPtr mon,
+                                      qemuMonitorMigrationCaps capability)
+{
+    int ret = -1;
+
+    virJSONValuePtr cmd = NULL;
+    virJSONValuePtr reply = NULL;
+    virJSONValuePtr cap = NULL;
+    virJSONValuePtr caps;
+
+    if (!(caps = virJSONValueNewArray()))
+        goto cleanup;
+
+    if (!(cap = virJSONValueNewObject()))
+        goto no_memory;
+
+    if (virJSONValueObjectAppendString(
+                cap, "capability",
+                qemuMonitorMigrationCapsTypeToString(capability)) < 0)
+        goto no_memory;
+
+    if (virJSONValueObjectAppendBoolean(cap, "state", 1) < 0)
+        goto no_memory;
+
+    if (virJSONValueArrayAppend(caps, cap) < 0)
+        goto no_memory;
+
+    cap = NULL;
+
+    cmd = qemuMonitorJSONMakeCommand("migrate-set-capabilities",
+                                     "a:capabilities", caps,
+                                     NULL);
+    if (!cmd)
+        goto cleanup;
+
+    if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+        goto cleanup;
+
+    ret = qemuMonitorJSONCheckError(cmd, reply);
+
+cleanup:
+    virJSONValueFree(cap);
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+
+no_memory:
+    virReportOOMError();
+    goto cleanup;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 925d937..356c10a 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -126,6 +126,11 @@ int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon,
                                       unsigned long long *remaining,
                                       unsigned long long *total);
 
+int qemuMonitorJSONGetMigrationCapability(qemuMonitorPtr mon,
+                                          qemuMonitorMigrationCaps capability);
+int qemuMonitorJSONSetMigrationCapability(qemuMonitorPtr mon,
+                                          qemuMonitorMigrationCaps capability);
+
 int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
                            unsigned int flags,
                            const char *uri);
-- 
1.8.1.2


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]