From: Marc-André Lureau <marcandre.lureau(a)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(a)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