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);