[libvirt] [PATCH 11/23] qemu: add dbus-vmstate helper migration support

marcandre.lureau at redhat.com marcandre.lureau at redhat.com
Mon Jul 8 07:07:35 UTC 2019


From: Marc-André Lureau <marcandre.lureau at redhat.com>

Helper processes may have their state migrated with QEMU data stream
thanks to the proposed object "dbus-vmstate".

libvirt knows what helpers should be migrated. The "dbus-vmstate" is
added when required, and given the list of helper Ids that must be
present during migration (save & load).

See QEMU "Add dbus-vmstate object" patch for further documentation on
the helper expected behaviour.

Signed-off-by: Marc-André Lureau <marcandre.lureau at redhat.com>
---
 src/qemu/qemu_alias.c        |  7 +++
 src/qemu/qemu_alias.h        |  2 +
 src/qemu/qemu_command.c      | 65 ++++++++++++++++++++++++++++
 src/qemu/qemu_command.h      |  3 ++
 src/qemu/qemu_dbus.c         | 14 ++++++
 src/qemu/qemu_dbus.h         |  4 ++
 src/qemu/qemu_domain.c       |  8 ++++
 src/qemu/qemu_domain.h       |  5 +++
 src/qemu/qemu_hotplug.c      | 82 ++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_hotplug.h      |  8 ++++
 src/qemu/qemu_migration.c    | 51 ++++++++++++++++++++++
 src/qemu/qemu_monitor.c      | 22 ++++++++++
 src/qemu/qemu_monitor.h      |  3 ++
 src/qemu/qemu_monitor_json.c | 15 +++++++
 src/qemu/qemu_monitor_json.h |  5 +++
 15 files changed, 294 insertions(+)

diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index 585cc972ba..a901932034 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -843,3 +843,10 @@ qemuDomainGetUnmanagedPRAlias(const char *parentalias)
 
     return ret;
 }
+
+
+const char *
+qemuDomainGetDBusVMStateAlias(void)
+{
+    return "dbus-vmstate0";
+}
diff --git a/src/qemu/qemu_alias.h b/src/qemu/qemu_alias.h
index aaac09a1d1..e3492116c5 100644
--- a/src/qemu/qemu_alias.h
+++ b/src/qemu/qemu_alias.h
@@ -95,3 +95,5 @@ char *qemuAliasChardevFromDevAlias(const char *devAlias)
 const char *qemuDomainGetManagedPRAlias(void);
 
 char *qemuDomainGetUnmanagedPRAlias(const char *parentalias);
+
+const char *qemuDomainGetDBusVMStateAlias(void);
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 688dc324c6..040e8e2b12 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -24,6 +24,7 @@
 #include "qemu_command.h"
 #include "qemu_hostdev.h"
 #include "qemu_capabilities.h"
+#include "qemu_dbus.h"
 #include "qemu_interface.h"
 #include "qemu_alias.h"
 #include "qemu_security.h"
@@ -10406,6 +10407,67 @@ qemuBuildManagedPRCommandLine(virCommandPtr cmd,
 }
 
 
+static virJSONValuePtr
+qemuBuildDBusVMStateInfoPropsInternal(const char *alias,
+                                      const char *addr)
+{
+    virJSONValuePtr ret = NULL;
+
+    if (qemuMonitorCreateObjectProps(&ret,
+                                     "dbus-vmstate", alias,
+                                     "s:addr", addr, NULL) < 0)
+        return NULL;
+
+    return ret;
+}
+
+
+virJSONValuePtr
+qemuBuildDBusVMStateInfoProps(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm)
+{
+    VIR_AUTOFREE(char *) addr = qemuDBusGetAddress(driver, vm);
+
+    if (!addr)
+        return NULL;
+
+    return qemuBuildDBusVMStateInfoPropsInternal(qemuDomainGetDBusVMStateAlias(),
+                                                 addr);
+}
+
+
+static int
+qemuBuildDBusVMStateCommandLine(virCommandPtr cmd,
+                                virQEMUDriverPtr driver,
+                                virDomainObjPtr vm)
+{
+    VIR_AUTOCLEAN(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+    VIR_AUTOPTR(virJSONValue) props = NULL;
+    qemuDomainObjPrivatePtr priv = QEMU_DOMAIN_PRIVATE(vm);
+
+    if (virStringListLength((const char **)priv->dbusVMStateIds) == 0)
+        return 0;
+
+    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
+        VIR_INFO("dbus-vmstate object is not supported by this QEMU binary");
+        return 0;
+    }
+
+    if (!(props = qemuBuildDBusVMStateInfoProps(driver, vm)))
+        return -1;
+
+    if (virQEMUBuildObjectCommandlineFromJSON(&buf, props) < 0)
+        return -1;
+
+    virCommandAddArg(cmd, "-object");
+    virCommandAddArgBuffer(cmd, &buf);
+
+    priv->dbusVMState = true;
+
+    return 0;
+}
+
+
 /**
  * qemuBuildCommandLineValidate:
  *
@@ -10650,6 +10712,9 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
     if (qemuBuildMasterKeyCommandLine(cmd, priv) < 0)
         goto error;
 
+    if (qemuBuildDBusVMStateCommandLine(cmd, driver, vm) < 0)
+        goto error;
+
     if (qemuBuildManagedPRCommandLine(cmd, def, priv) < 0)
         goto error;
 
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 8695832c16..8bb941e2bc 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -58,6 +58,9 @@ virCommandPtr qemuBuildCommandLine(virQEMUDriverPtr driver,
 virJSONValuePtr qemuBuildPRManagerInfoProps(virStorageSourcePtr src);
 virJSONValuePtr qemuBuildPRManagedManagerInfoProps(qemuDomainObjPrivatePtr priv);
 
+virJSONValuePtr qemuBuildDBusVMStateInfoProps(virQEMUDriverPtr driver,
+                                              virDomainObjPtr vm);
+
 /* Generate the object properties for a secret */
 int qemuBuildSecretInfoProps(qemuDomainSecretInfoPtr secinfo,
                              virJSONValuePtr *propsret);
diff --git a/src/qemu/qemu_dbus.c b/src/qemu/qemu_dbus.c
index bf24c85910..729be09069 100644
--- a/src/qemu/qemu_dbus.c
+++ b/src/qemu/qemu_dbus.c
@@ -368,3 +368,17 @@ end:
     dbus_error_free(&error);
     return ret;
 }
+
+
+int
+qemuDBusVMStateAdd(virDomainObjPtr vm, const char *id)
+{
+    return virStringListAdd(&QEMU_DOMAIN_PRIVATE(vm)->dbusVMStateIds, id);
+}
+
+
+void
+qemuDBusVMStateRemove(virDomainObjPtr vm, const char *id)
+{
+    virStringListRemove(&QEMU_DOMAIN_PRIVATE(vm)->dbusVMStateIds, id);
+}
diff --git a/src/qemu/qemu_dbus.h b/src/qemu/qemu_dbus.h
index 8728824bd7..e86134b2a1 100644
--- a/src/qemu/qemu_dbus.h
+++ b/src/qemu/qemu_dbus.h
@@ -38,3 +38,7 @@ void qemuDBusStop(virQEMUDriverPtr driver,
 int qemuDBusSetupCgroup(virQEMUDriverPtr driver,
                         virDomainDefPtr def,
                         virCgroupPtr cgroup);
+
+int qemuDBusVMStateAdd(virDomainObjPtr vm, const char *id);
+
+void qemuDBusVMStateRemove(virDomainObjPtr vm, const char *id);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 192aceb605..b7fcaab186 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -2056,6 +2056,9 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivatePtr priv)
         dbus_connection_unref(priv->dbusConn);
         priv->dbusConn = NULL;
     }
+
+    virStringListFree(priv->dbusVMStateIds);
+    priv->dbusVMStateIds = NULL;
 }
 
 
@@ -2487,6 +2490,9 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf,
     if (priv->dbusDaemonRunning)
         virBufferAddLit(buf, "<dbusDaemon/>\n");
 
+    if (priv->dbusVMState)
+        virBufferAddLit(buf, "<dbusVMState/>\n");
+
     if (priv->namespaces) {
         ssize_t ns = -1;
 
@@ -2920,6 +2926,8 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
 
     priv->dbusDaemonRunning = virXPathBoolean("boolean(./dbusDaemon)", ctxt) > 0;
 
+    priv->dbusVMState = virXPathBoolean("boolean(./dbusVMState)", ctxt) > 0;
+
     if ((node = virXPathNode("./namespaces", ctxt))) {
         xmlNodePtr next;
 
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 9d14163c21..20c5fbec09 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -391,6 +391,11 @@ struct _qemuDomainObjPrivate {
     /* true if dbus-daemon is running */
     bool dbusDaemonRunning;
     DBusConnection *dbusConn;
+
+    /* list of Ids to migrate */
+    char **dbusVMStateIds;
+    /* true if -object dbus-vmstate was added */
+    bool dbusVMState;
 };
 
 #define QEMU_DOMAIN_PRIVATE(vm) \
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 7e9c1a1649..ccff9a79d7 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -325,6 +325,88 @@ qemuDomainChangeMediaLegacy(virQEMUDriverPtr driver,
 }
 
 
+/**
+ * qemuHotplugAttachDBusVMState:
+ * @driver: QEMU driver object
+ * @vm: domain object
+ * @asyncJob: asynchronous job identifier
+ *
+ * Add -object dbus-vmstate if necessary.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int
+qemuHotplugAttachDBusVMState(virQEMUDriverPtr driver,
+                             virDomainObjPtr vm,
+                             qemuDomainAsyncJob asyncJob)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    VIR_AUTOPTR(virJSONValue) props = NULL;
+    int ret;
+
+    if (priv->dbusVMState)
+        return 0;
+
+    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
+        VIR_INFO("dbus-vmstate object is not supported by this QEMU binary");
+        return 0;
+    }
+
+    if (!(props = qemuBuildDBusVMStateInfoProps(driver, vm)))
+        return -1;
+
+    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+        return -1;
+
+    ret = qemuMonitorAddObject(priv->mon, &props, NULL);
+
+    if (ret == 0)
+        priv->dbusVMState = true;
+
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
+        return -1;
+
+    return ret;
+}
+
+
+/**
+ * qemuHotplugRemoveDBusVMState:
+ * @driver: QEMU driver object
+ * @vm: domain object
+ * @asyncJob: asynchronous job identifier
+ *
+ * Remove -object dbus-vmstate from @vm if the configuration does not require
+ * it any more.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int
+qemuHotplugRemoveDBusVMState(virQEMUDriverPtr driver,
+                             virDomainObjPtr vm,
+                             qemuDomainAsyncJob asyncJob)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    int ret;
+
+    if (!priv->dbusVMState)
+        return 0;
+
+    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+        return -1;
+
+    ret = qemuMonitorDelObject(priv->mon, qemuDomainGetDBusVMStateAlias());
+
+    if (ret == 0)
+        priv->dbusVMState = false;
+
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
+        return -1;
+
+    return ret;
+}
+
+
 /**
  * qemuHotplugAttachManagedPR:
  * @driver: QEMU driver object
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 896e6c7b98..10896976be 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -150,3 +150,11 @@ int qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
                               virDomainDefPtr persistentDef,
                               virBitmapPtr vcpus,
                               bool state);
+
+int qemuHotplugAttachDBusVMState(virQEMUDriverPtr driver,
+                                 virDomainObjPtr vm,
+                                 qemuDomainAsyncJob asyncJob);
+
+int qemuHotplugRemoveDBusVMState(virQEMUDriverPtr driver,
+                                 virDomainObjPtr vm,
+                                 qemuDomainAsyncJob asyncJob);
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 2436f5051b..a11c6f1a9f 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1112,10 +1112,18 @@ qemuMigrationSrcIsAllowed(virQEMUDriverPtr driver,
                           bool remote,
                           unsigned int flags)
 {
+    qemuDomainObjPrivatePtr priv = vm->privateData;
     int nsnapshots;
     int pauseReason;
     size_t i;
 
+    if (virStringListLength((const char **)priv->dbusVMStateIds) &&
+        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("cannot migrate this domain without dbus-vmstate support"));
+        return false;
+    }
+
     /* perform these checks only when migrating to remote hosts */
     if (remote) {
         nsnapshots = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0);
@@ -1846,8 +1854,14 @@ qemuMigrationDstRun(virQEMUDriverPtr driver,
     if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
         return -1;
 
+    rv = qemuMonitorSetDBusVMStateIdList(priv->mon,
+                                         (const char **)priv->dbusVMStateIds);
+    if (rv < 0)
+        goto exit_monitor;
+
     rv = qemuMonitorMigrateIncoming(priv->mon, uri);
 
+ exit_monitor:
     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rv < 0)
         goto cleanup;
 
@@ -3352,6 +3366,37 @@ qemuMigrationSrcContinue(virQEMUDriverPtr driver,
 }
 
 
+static int
+qemuMigrationSetDBusVMState(virQEMUDriverPtr driver,
+                            virDomainObjPtr vm)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+
+    if (virStringListLength((const char **)priv->dbusVMStateIds) > 0) {
+        int rv;
+
+        if (qemuHotplugAttachDBusVMState(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
+            return -1;
+
+        if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
+            return -1;
+
+        rv = qemuMonitorSetDBusVMStateIdList(priv->mon,
+                                             (const char **)priv->dbusVMStateIds);
+
+        if (qemuDomainObjExitMonitor(driver, vm) < 0)
+            rv = -1;
+
+        return rv;
+    } else {
+        if (qemuHotplugRemoveDBusVMState(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
 static int
 qemuMigrationSrcRun(virQEMUDriverPtr driver,
                     virDomainObjPtr vm,
@@ -3502,6 +3547,9 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver,
         }
     }
 
+    if (qemuMigrationSetDBusVMState(driver, vm) < 0)
+        goto exit_monitor;
+
     /* Before EnterMonitor, since already qemuProcessStopCPUs does that */
     if (!(flags & VIR_MIGRATE_LIVE) &&
         virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
@@ -5207,6 +5255,9 @@ qemuMigrationSrcToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
     char *errbuf = NULL;
     virErrorPtr orig_err = NULL;
 
+    if (qemuMigrationSetDBusVMState(driver, vm) < 0)
+        return -1;
+
     /* Increase migration bandwidth to unlimited since target is a file.
      * Failure to change migration speed is not fatal. */
     if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 731be2e5a6..ea57bad9f5 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include "qemu_alias.h"
 #include "qemu_monitor.h"
 #include "qemu_monitor_text.h"
 #include "qemu_monitor_json.h"
@@ -2478,6 +2479,27 @@ qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
 }
 
 
+int
+qemuMonitorSetDBusVMStateIdList(qemuMonitorPtr mon,
+                                const char **list)
+{
+    VIR_AUTOFREE(char *) path = NULL;
+
+    VIR_DEBUG("list=%p", list);
+
+    if (virStringListLength(list) == 0)
+        return 0;
+
+    if (virAsprintf(&path, "/objects/%s",
+                    qemuDomainGetDBusVMStateAlias()) < 0)
+        return -1;
+
+    QEMU_CHECK_MONITOR(mon);
+
+    return qemuMonitorJSONSetDBusVMStateIdList(mon, path, list);
+}
+
+
 int
 qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon,
                              unsigned long bandwidth)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index c41428b048..fcb029f97f 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -685,6 +685,9 @@ int qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
                                   size_t length,
                                   const char *path);
 
+int qemuMonitorSetDBusVMStateIdList(qemuMonitorPtr mon,
+                                    const char **list);
+
 int qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon,
                                  unsigned long bandwidth);
 
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 8723ff49c7..239005dbad 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2304,6 +2304,21 @@ qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon,
 }
 
 
+int
+qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
+                                    const char *vmstatepath,
+                                    const char **list)
+{
+    VIR_AUTOFREE(char *) str = virStringListJoin(list, ",");
+    qemuMonitorJSONObjectProperty prop = {
+        .type = QEMU_MONITOR_OBJECT_PROPERTY_STRING,
+        .val.str = str,
+    };
+
+    return qemuMonitorJSONSetObjectProperty(mon, vmstatepath, "id-list", &prop);
+}
+
+
 /* qemuMonitorJSONQueryBlock:
  * @mon: Monitor pointer
  *
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index d0b519c88e..1ed2b005e4 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -605,3 +605,8 @@ int qemuMonitorJSONMergeBitmaps(qemuMonitorPtr mon,
 int qemuMonitorJSONDeleteBitmap(qemuMonitorPtr mon,
                                 const char *node,
                                 const char *bitmap);
+
+int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
+                                        const char *vmstatepath,
+                                        const char **list)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-- 
2.22.0.214.g8dca754b1e




More information about the libvir-list mailing list