diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am
index d16b315ebc33cfbe293aad507d6d338ea375cd1d..a8f676437e7c62cb2ca6a49077ea9b35cff45fdf 100644
--- a/src/qemu/Makefile.inc.am
+++ b/src/qemu/Makefile.inc.am
@@ -13,6 +13,8 @@ QEMU_DRIVER_SOURCES = \
qemu/qemu_capabilities.h \
qemu/qemu_command.c \
qemu/qemu_command.h \
+ qemu/qemu_dbus.c \
+ qemu/qemu_dbus.h \
qemu/qemu_domain.c \
qemu/qemu_domain.h \
qemu/qemu_domain_address.c \
diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index 216a18d0d98483416eaa5ab47ad398c3883bfaea..d294963d35b9d635a0b861dbb47d7b7726fc1a10 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -841,3 +841,20 @@ qemuDomainGetUnmanagedPRAlias(const char *parentalias)
return ret;
}
+
+char *
+qemuAliasDBusVMStateFromId(const char *id)
+{
+ char *ret;
+ size_t i;
+
+ if (virAsprintf(&ret, "dbus-vms-%s", id) < 0)
+ return NULL;
+
+ for (i = 0; ret[i]; i++) {
+ if (ret[i] == ':')
+ ret[i] = '_';
+ }
+
+ return ret;
+}
diff --git a/src/qemu/qemu_alias.h b/src/qemu/qemu_alias.h
index aaac09a1d105b581c8044005ef0cfb46fe58a1e3..ae2fce16bceaaccc664609d8ed0597551383df68 100644
--- a/src/qemu/qemu_alias.h
+++ b/src/qemu/qemu_alias.h
@@ -95,3 +95,6 @@ char *qemuAliasChardevFromDevAlias(const char *devAlias)
const char *qemuDomainGetManagedPRAlias(void);
char *qemuDomainGetUnmanagedPRAlias(const char *parentalias);
+
+char *qemuAliasDBusVMStateFromId(const char *id)
+ ATTRIBUTE_NONNULL(1);
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 9cd46e8ea7ef31195dbfac70a031d805837eff68..fd1e5cdb47dec42eedc31ba4e3b1a22d96382f96 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -27,6 +27,7 @@
#include "qemu_interface.h"
#include "qemu_alias.h"
#include "qemu_security.h"
+#include "qemu_dbus.h"
#include "qemu_block.h"
#include "cpu/cpu.h"
#include "dirname.h"
@@ -9983,6 +9984,85 @@ 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(const char *id,
+ const char *addr)
+{
+ VIR_AUTOFREE(char *) alias = qemuAliasDBusVMStateFromId(id);
+
+ if (!alias)
+ return NULL;
+
+ return qemuBuildDBusVMStateInfoPropsInternal(alias, addr);
+}
+
+
+typedef struct qemuBuildDBusVMStateCommandLineData {
+ virCommandPtr cmd;
+} qemuBuildDBusVMStateCommandLineData;
+
+
+static int
+qemuBuildDBusVMStateCommandLineEach(void *payload,
+ const void *id,
+ void *user_data)
+{
+ qemuBuildDBusVMStateCommandLineData *data = user_data;
+ qemuDBusVMStatePtr vms = payload;
+ VIR_AUTOCLEAN(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+ VIR_AUTOPTR(virJSONValue) props = NULL;
+
+ if (!(props = qemuBuildDBusVMStateInfoProps(id, vms->addr)))
+ return -1;
+
+ if (virQEMUBuildObjectCommandlineFromJSON(&buf, props) < 0)
+ return -1;
+
+ virCommandAddArg(data->cmd, "-object");
+ virCommandAddArgBuffer(data->cmd, &buf);
+
+ return 0;
+}
+
+static int
+qemuBuildDBusVMStateCommandLine(virCommandPtr cmd,
+ qemuDomainObjPrivatePtr priv)
+{
+ qemuBuildDBusVMStateCommandLineData data = {
+ .cmd = cmd,
+ };
+
+ if (virHashSize(priv->dbusVMStates) == 0)
+ return 0;
+
+ if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("dbus-vmstate object is not supported by this QEMU binary"));
+ return 0;
+ }
+
+ if (virHashForEach(priv->dbusVMStates, qemuBuildDBusVMStateCommandLineEach, &data) < 0)
+ return -1;
+
+ return 0;
+}
+
+
/**
* qemuBuildCommandLineValidate:
*
@@ -10217,6 +10297,9 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
if (qemuBuildMasterKeyCommandLine(cmd, priv) < 0)
return NULL;
+ if (qemuBuildDBusVMStateCommandLine(cmd, priv) < 0)
+ return NULL;
+
if (qemuBuildManagedPRCommandLine(cmd, def, priv) < 0)
return NULL;
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 60f9843b03710c134344d6ff778e61f182dd6fd6..74cb1e76d607a60194c674ab0b4b02262f3dccb8 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -62,6 +62,9 @@ virJSONValuePtr qemuBuildPRManagedManagerInfoProps(qemuDomainObjPrivatePtr priv)
int qemuBuildSecretInfoProps(qemuDomainSecretInfoPtr secinfo,
virJSONValuePtr *propsret);
+virJSONValuePtr qemuBuildDBusVMStateInfoProps(const char *id,
+ const char *addr);
+
/* Generate the object properties for a tls-creds-x509 */
int qemuBuildTLSx509BackendProps(const char *tlspath,
bool isListen,
diff --git a/src/qemu/qemu_dbus.c b/src/qemu/qemu_dbus.c
new file mode 100644
index 0000000000000000000000000000000000000000..15c9bf519e41d4e7eb744eea6e2a2d2af274ca66
--- /dev/null
+++ b/src/qemu/qemu_dbus.c
@@ -0,0 +1,97 @@
+/*
+ * qemu_dbus.c: QEMU DBus-related helpers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#include
+
+#include "qemu_extdevice.h"
+#include "qemu_dbus.h"
+#include "qemu_hotplug.h"
+#include "qemu_security.h"
+
+#include "viralloc.h"
+#include "virlog.h"
+#include "virstring.h"
+#include "virtime.h"
+#include "virpidfile.h"
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+VIR_LOG_INIT("qemu.dbus");
+
+
+qemuDBusVMStatePtr
+qemuDBusVMStateNew(const char *id, const char *addr)
+{
+ VIR_AUTOPTR(qemuDBusVMState) self = NULL;
+
+ if (VIR_ALLOC(self) < 0)
+ return NULL;
+
+ if (VIR_STRDUP(self->id, id) < 0)
+ return NULL;
+
+ if (VIR_STRDUP(self->addr, addr) < 0)
+ return NULL;
+
+ VIR_RETURN_PTR(self);
+}
+
+
+void
+qemuDBusVMStateFree(qemuDBusVMStatePtr self)
+{
+ if (!self)
+ return;
+
+ VIR_FREE(self->id);
+ VIR_FREE(self->addr);
+ VIR_FREE(self);
+}
+
+
+int
+qemuDBusVMStateAdd(virQEMUDriverPtr driver, virDomainObjPtr vm,
+ const char *id, const char *addr, bool hot)
+{
+ qemuDBusVMStatePtr d = qemuDBusVMStateNew(id, addr);
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+ if (virHashAddEntry(priv->dbusVMStates, id, d) < 0) {
+ qemuDBusVMStateFree(d);
+ return -1;
+ }
+
+ if (hot && virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE) &&
+ qemuDomainAttachDBusVMState(driver, vm, id, addr, QEMU_ASYNC_JOB_NONE) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+void
+qemuDBusVMStateRemove(virQEMUDriverPtr driver, virDomainObjPtr vm,
+ const char *id, bool hot)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+ if (virHashRemoveEntry(priv->dbusVMStates, id) < 0 ||
+ (hot && virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE) &&
+ qemuDomainDetachDBusVMState(driver, vm, id, QEMU_ASYNC_JOB_NONE) < 0))
+ VIR_ERROR(_("Failed to remove vmstate id '%s'"), vm->def->name);
+}
diff --git a/src/qemu/qemu_dbus.h b/src/qemu/qemu_dbus.h
new file mode 100644
index 0000000000000000000000000000000000000000..48ea71f7aa3addbd4fa31e2b062aec4068e52134
--- /dev/null
+++ b/src/qemu/qemu_dbus.h
@@ -0,0 +1,42 @@
+/*
+ * qemu_dbus.h: QEMU DBus-related helpers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#pragma once
+
+#include "qemu_conf.h"
+#include "qemu_domain.h"
+
+typedef struct _qemuDBusVMState qemuDBusVMState;
+typedef qemuDBusVMState *qemuDBusVMStatePtr;
+struct _qemuDBusVMState {
+ char *id;
+ char *addr;
+};
+
+
+qemuDBusVMStatePtr qemuDBusVMStateNew(const char *id, const char *addr);
+
+void qemuDBusVMStateFree(qemuDBusVMStatePtr self);
+
+int qemuDBusVMStateAdd(virQEMUDriverPtr driver, virDomainObjPtr vm,
+ const char *id, const char *addr, bool hot);
+
+void qemuDBusVMStateRemove(virQEMUDriverPtr driver, virDomainObjPtr vm,
+ const char *id, bool hot);
+
+VIR_DEFINE_AUTOPTR_FUNC(qemuDBusVMState, qemuDBusVMStateFree);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 2c75a79670123d1d76d2acfcfeb58112622f6125..4a74b2ec8506728f4eab84fbd1826906fe468103 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -26,6 +26,7 @@
#include "qemu_block.h"
#include "qemu_cgroup.h"
#include "qemu_command.h"
+#include "qemu_dbus.h"
#include "qemu_process.h"
#include "qemu_capabilities.h"
#include "qemu_migration.h"
@@ -1959,6 +1960,14 @@ qemuDomainSetPrivatePaths(virQEMUDriverPtr driver,
}
+static void
+dbusVMStateHashFree(void *opaque,
+ const void *name ATTRIBUTE_UNUSED)
+{
+ qemuDBusVMStateFree(opaque);
+}
+
+
static void *
qemuDomainObjPrivateAlloc(void *opaque)
{
@@ -1979,6 +1988,9 @@ qemuDomainObjPrivateAlloc(void *opaque)
if (!(priv->blockjobs = virHashCreate(5, virObjectFreeHashData)))
goto error;
+ if (!(priv->dbusVMStates = virHashCreate(5, dbusVMStateHashFree)))
+ goto error;
+
priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX;
priv->driver = opaque;
@@ -2050,6 +2062,7 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivatePtr priv)
qemuDomainObjResetAsyncJob(priv);
virHashRemoveAll(priv->blockjobs);
+ virHashRemoveAll(priv->dbusVMStates);
}
@@ -2082,6 +2095,7 @@ qemuDomainObjPrivateFree(void *data)
qemuDomainMasterKeyFree(priv);
virHashFree(priv->blockjobs);
+ virHashFree(priv->dbusVMStates);
VIR_FREE(priv);
}
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 33eb501e2a4c6faf1c0a833c0d0db5aa4c868af5..e7c19e7f9ca42421f68192f6626aa6c9004e8891 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -392,6 +392,8 @@ struct _qemuDomainObjPrivate {
/* running block jobs */
virHashTablePtr blockjobs;
+
+ virHashTablePtr dbusVMStates;
};
#define QEMU_DOMAIN_PRIVATE(vm) \
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index a7034fd2986fe37375a71d1b5414c3a7f80cf3b2..71c4afb4a509ff632d27b758a7b03d319c11f155 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -412,6 +412,83 @@ qemuHotplugRemoveManagedPR(virQEMUDriverPtr driver,
}
+/**
+ * qemuDomainAttachDBusVMState:
+ * @driver: QEMU driver object
+ * @vm: domain object
+ * @id
+ * @addr
+ * @asyncJob: asynchronous job identifier
+ *
+ * Add dbus-vmstate object.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int
+qemuDomainAttachDBusVMState(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *id,
+ const char *addr,
+ qemuDomainAsyncJob asyncJob)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ VIR_AUTOPTR(virJSONValue) props = NULL;
+ int ret;
+
+ if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("dbus-vmstate object is not supported by this QEMU binary"));
+ return -1;
+ }
+
+ if (!(props = qemuBuildDBusVMStateInfoProps(id, addr)))
+ return -1;
+
+ if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+ return -1;
+
+ ret = qemuMonitorAddObject(priv->mon, &props, NULL);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ return -1;
+
+ return ret;
+}
+
+
+/**
+ * qemuDomainDetachDBusVMState:
+ * @driver: QEMU driver object
+ * @vm: domain object
+ * @asyncJob: asynchronous job identifier
+ *
+ * Remove dbus-vmstate object from @vm.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int
+qemuDomainDetachDBusVMState(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *id,
+ qemuDomainAsyncJob asyncJob)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ VIR_AUTOFREE(char *) alias = qemuAliasDBusVMStateFromId(id);
+ int ret;
+
+ if (!alias ||
+ qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+ return -1;
+
+ ret = qemuMonitorDelObject(priv->mon, alias);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ return -1;
+
+ return ret;
+}
+
+
/**
* qemuDomainChangeMediaBlockdev:
* @driver: qemu driver structure
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 896e6c7b9807a6ae07f151765f6884e288a2c8a9..6d2cd34dbc984083d4252b2eb7091163c53dcba0 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -150,3 +150,14 @@ int qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
virDomainDefPtr persistentDef,
virBitmapPtr vcpus,
bool state);
+
+int qemuDomainAttachDBusVMState(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *id,
+ const char *addr,
+ qemuDomainAsyncJob asyncJob);
+
+int qemuDomainDetachDBusVMState(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *id,
+ qemuDomainAsyncJob asyncJob);