mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 07:17:44 +00:00
qemu: add dbus-vmstate helper migration support
Helper processes may have their state migrated with QEMU data stream thanks to the QEMU "dbus-vmstate". libvirt maintains the list of helpers to be migrated. The "dbus-vmstate" is added when required, and given the list of helper Ids that must be migrated, on save & load sides. See also: https://git.qemu.org/?p=qemu.git;a=blob;f=docs/interop/dbus-vmstate.rst Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
db670b8d67
commit
6077ae7b40
@ -829,3 +829,10 @@ qemuDomainGetUnmanagedPRAlias(const char *parentalias)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
qemuDomainGetDBusVMStateAlias(void)
|
||||
{
|
||||
return "dbus-vmstate0";
|
||||
}
|
||||
|
@ -95,3 +95,5 @@ char *qemuAliasChardevFromDevAlias(const char *devAlias)
|
||||
const char *qemuDomainGetManagedPRAlias(void);
|
||||
|
||||
char *qemuDomainGetUnmanagedPRAlias(const char *parentalias);
|
||||
|
||||
const char *qemuDomainGetDBusVMStateAlias(void);
|
||||
|
@ -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"
|
||||
@ -9570,6 +9571,56 @@ qemuBuildPflashBlockdevCommandLine(virCommandPtr cmd,
|
||||
}
|
||||
|
||||
|
||||
virJSONValuePtr
|
||||
qemuBuildDBusVMStateInfoProps(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm)
|
||||
{
|
||||
virJSONValuePtr ret = NULL;
|
||||
const char *alias = qemuDomainGetDBusVMStateAlias();
|
||||
g_autofree char *addr = qemuDBusGetAddress(driver, vm);
|
||||
|
||||
if (!addr)
|
||||
return NULL;
|
||||
|
||||
qemuMonitorCreateObjectProps(&ret,
|
||||
"dbus-vmstate", alias,
|
||||
"s:addr", addr, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuBuildDBusVMStateCommandLine(virCommandPtr cmd,
|
||||
virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm)
|
||||
{
|
||||
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
||||
g_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:
|
||||
*
|
||||
@ -9801,6 +9852,9 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
|
||||
if (qemuBuildMasterKeyCommandLine(cmd, priv) < 0)
|
||||
return NULL;
|
||||
|
||||
if (qemuBuildDBusVMStateCommandLine(cmd, driver, vm) < 0)
|
||||
return NULL;
|
||||
|
||||
if (qemuBuildManagedPRCommandLine(cmd, def, priv) < 0)
|
||||
return NULL;
|
||||
|
||||
|
@ -59,6 +59,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);
|
||||
|
@ -273,3 +273,17 @@ qemuDBusStart(virQEMUDriverPtr driver,
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -31,3 +31,7 @@ int qemuDBusStart(virQEMUDriverPtr driver,
|
||||
|
||||
void qemuDBusStop(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm);
|
||||
|
||||
int qemuDBusVMStateAdd(virDomainObjPtr vm, const char *id);
|
||||
|
||||
void qemuDBusVMStateRemove(virDomainObjPtr vm, const char *id);
|
||||
|
@ -2297,6 +2297,13 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivatePtr priv)
|
||||
|
||||
/* reset node name allocator */
|
||||
qemuDomainStorageIdReset(priv);
|
||||
|
||||
priv->dbusDaemonRunning = false;
|
||||
|
||||
virStringListFree(priv->dbusVMStateIds);
|
||||
priv->dbusVMStateIds = NULL;
|
||||
|
||||
priv->dbusVMState = false;
|
||||
}
|
||||
|
||||
|
||||
@ -2974,6 +2981,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;
|
||||
|
||||
@ -3761,6 +3771,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;
|
||||
|
||||
|
@ -423,6 +423,11 @@ struct _qemuDomainObjPrivate {
|
||||
virDomainBackupDefPtr backup;
|
||||
|
||||
bool dbusDaemonRunning;
|
||||
|
||||
/* list of Ids to migrate */
|
||||
char **dbusVMStateIds;
|
||||
/* true if -object dbus-vmstate was added */
|
||||
bool dbusVMState;
|
||||
};
|
||||
|
||||
#define QEMU_DOMAIN_PRIVATE(vm) \
|
||||
|
@ -311,6 +311,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;
|
||||
g_autoptr(virJSONValue) props = NULL;
|
||||
int ret;
|
||||
|
||||
if (priv->dbusVMState)
|
||||
return 0;
|
||||
|
||||
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
|
||||
VIR_DEBUG("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(), true);
|
||||
|
||||
if (ret == 0)
|
||||
priv->dbusVMState = false;
|
||||
|
||||
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuHotplugAttachManagedPR:
|
||||
* @driver: QEMU driver object
|
||||
|
@ -152,3 +152,11 @@ int qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
|
||||
bool state);
|
||||
|
||||
unsigned long long qemuDomainGetUnplugTimeout(virDomainObjPtr vm);
|
||||
|
||||
int qemuHotplugAttachDBusVMState(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
qemuDomainAsyncJob asyncJob);
|
||||
|
||||
int qemuHotplugRemoveDBusVMState(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
qemuDomainAsyncJob asyncJob);
|
||||
|
@ -1169,6 +1169,7 @@ qemuMigrationSrcIsAllowed(virQEMUDriverPtr driver,
|
||||
bool remote,
|
||||
unsigned int flags)
|
||||
{
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
int nsnapshots;
|
||||
int pauseReason;
|
||||
size_t i;
|
||||
@ -1283,6 +1284,13 @@ qemuMigrationSrcIsAllowed(virQEMUDriverPtr driver,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (virStringListLength((const char **)priv->dbusVMStateIds) > 0 &&
|
||||
!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
||||
_("cannot migrate this domain without dbus-vmstate support"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1948,8 +1956,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)
|
||||
return -1;
|
||||
|
||||
@ -3420,6 +3434,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,
|
||||
@ -3572,6 +3617,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) {
|
||||
@ -5257,6 +5305,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) {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "qemu_alias.h"
|
||||
#include "qemu_monitor.h"
|
||||
#include "qemu_monitor_text.h"
|
||||
#include "qemu_monitor_json.h"
|
||||
@ -2361,6 +2362,26 @@ qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuMonitorSetDBusVMStateIdList(qemuMonitorPtr mon,
|
||||
const char **list)
|
||||
{
|
||||
g_autofree char *path = NULL;
|
||||
|
||||
VIR_DEBUG("list=%p", list);
|
||||
|
||||
if (virStringListLength(list) == 0)
|
||||
return 0;
|
||||
|
||||
path = g_strdup_printf("/objects/%s",
|
||||
qemuDomainGetDBusVMStateAlias());
|
||||
|
||||
QEMU_CHECK_MONITOR(mon);
|
||||
|
||||
return qemuMonitorJSONSetDBusVMStateIdList(mon, path, list);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon,
|
||||
unsigned long bandwidth)
|
||||
|
@ -737,6 +737,9 @@ int qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
|
||||
unsigned long long length,
|
||||
const char *path);
|
||||
|
||||
int qemuMonitorSetDBusVMStateIdList(qemuMonitorPtr mon,
|
||||
const char **list);
|
||||
|
||||
int qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon,
|
||||
unsigned long bandwidth);
|
||||
|
||||
|
@ -2361,6 +2361,21 @@ qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
|
||||
const char *vmstatepath,
|
||||
const char **list)
|
||||
{
|
||||
g_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
|
||||
*
|
||||
|
@ -686,3 +686,8 @@ qemuMonitorJSONTransactionBackup(virJSONValuePtr actions,
|
||||
const char *target,
|
||||
const char *bitmap,
|
||||
qemuMonitorTransactionBackupSyncMode syncmode);
|
||||
|
||||
int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
|
||||
const char *vmstatepath,
|
||||
const char **list)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
|
||||
|
Loading…
Reference in New Issue
Block a user