[PATCH v1 22/26] qemu: Wire up <memory/> live update
Daniel Henrique Barboza
danielhb413 at gmail.com
Mon Nov 30 20:45:45 UTC 2020
On 11/27/20 12:03 PM, Michal Privoznik wrote:
> As advertised in the previous commit, we want' to be able to
Extra ' after "want".
Reviewed-by: Daniel Henrique Barboza <danielhb413 at gmail.com>
> change 'requested-size' attribute of virtio-mem on the fly. This
> commit does exactly that. Changing anything else is checked for
> and forbidden.
>
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
> src/conf/domain_conf.c | 23 +++++
> src/conf/domain_conf.h | 3 +
> src/libvirt_private.syms | 1 +
> src/qemu/qemu_driver.c | 165 ++++++++++++++++++++++++++++++++++-
> src/qemu/qemu_hotplug.c | 18 ++++
> src/qemu/qemu_hotplug.h | 5 ++
> src/qemu/qemu_monitor.c | 13 +++
> src/qemu/qemu_monitor.h | 4 +
> src/qemu/qemu_monitor_json.c | 15 ++++
> src/qemu/qemu_monitor_json.h | 5 ++
> 10 files changed, 251 insertions(+), 1 deletion(-)
>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 0a402f1a51..5db1fee16b 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -18781,6 +18781,29 @@ virDomainMemoryFindInactiveByDef(virDomainDefPtr def,
> }
>
>
> +ssize_t
> +virDomainMemoryFindByDeviceInfo(virDomainDefPtr def,
> + virDomainDeviceInfoPtr info)
> +{
> + size_t i;
> +
> + for (i = 0; i < def->nmems; i++) {
> + virDomainMemoryDefPtr tmp = def->mems[i];
> +
> + if (!virDomainDeviceInfoAddressIsEqual(&tmp->info, info))
> + continue;
> +
> + /* alias, if present */
> + if (STRNEQ_NULLABLE(tmp->info.alias, info->alias))
> + continue;
> +
> + return i;
> + }
> +
> + return -1;
> +}
> +
> +
> /**
> * virDomainMemoryInsert:
> *
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 3f111e994b..31892c4941 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -3580,6 +3580,9 @@ int virDomainMemoryFindByDef(virDomainDefPtr def, virDomainMemoryDefPtr mem)
> int virDomainMemoryFindInactiveByDef(virDomainDefPtr def,
> virDomainMemoryDefPtr mem)
> ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
> +ssize_t virDomainMemoryFindByDeviceInfo(virDomainDefPtr dev,
> + virDomainDeviceInfoPtr info)
> + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
>
> int virDomainShmemDefInsert(virDomainDefPtr def, virDomainShmemDefPtr shmem)
> ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index f581676227..1bed019aac 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -497,6 +497,7 @@ virDomainMemballoonModelTypeFromString;
> virDomainMemballoonModelTypeToString;
> virDomainMemoryDefFree;
> virDomainMemoryFindByDef;
> +virDomainMemoryFindByDeviceInfo;
> virDomainMemoryFindInactiveByDef;
> virDomainMemoryInsert;
> virDomainMemoryModelTypeToString;
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 391596ba11..677f921920 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -7109,6 +7109,158 @@ qemuDomainChangeDiskLive(virDomainObjPtr vm,
> return 0;
> }
>
> +
> +static bool
> +qemuDomainChangeMemoryLiveValidateChange(const virDomainMemoryDef *oldDef,
> + const virDomainMemoryDef *newDef)
> +{
> + /* The only thing that is allowed to change is 'requestedsize' for virtio
> + * model. */
> + if (oldDef->model != newDef->model) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory model from '%s' to '%s'"),
> + virDomainMemoryModelTypeToString(oldDef->model),
> + virDomainMemoryModelTypeToString(newDef->model));
> + return false;
> + }
> +
> + if (oldDef->access != newDef->access) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory access from '%s' to '%s'"),
> + virDomainMemoryAccessTypeToString(oldDef->access),
> + virDomainMemoryAccessTypeToString(newDef->access));
> + return false;
> + }
> +
> + if (oldDef->discard != newDef->discard) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory discard from '%s' to '%s'"),
> + virTristateBoolTypeToString(oldDef->discard),
> + virTristateBoolTypeToString(newDef->discard));
> + return false;
> + }
> +
> + if (oldDef->targetNode != newDef->targetNode) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory targetNode from '%d' to '%d'"),
> + oldDef->targetNode, newDef->targetNode);
> + return false;
> + }
> +
> + if (oldDef->size != newDef->size) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory size from '%llu' to '%llu'"),
> + oldDef->size, newDef->size);
> + return false;
> + }
> +
> + if (oldDef->blocksize != newDef->blocksize) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory block size from '%llu' to '%llu'"),
> + oldDef->blocksize, newDef->blocksize);
> + return false;
> + }
> +
> + /* requestedsize can change */
> +
> + if (oldDef->readonly != newDef->readonly) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("cannot modify memory pmem flag"));
> + return false;
> + }
> +
> + if (virUUIDIsValid(oldDef->uuid) &&
> + memcmp(oldDef->uuid, newDef, VIR_UUID_BUFLEN) != 0) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("cannot modify memory UUID"));
> + return false;
> + }
> +
> + switch (oldDef->model) {
> + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO:
> + if (STRNEQ_NULLABLE(oldDef->s.virtio.path, newDef->s.virtio.path)) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory path from '%s' to '%s'"),
> + NULLSTR(oldDef->s.virtio.path),
> + NULLSTR(newDef->s.virtio.path));
> + return false;
> + }
> +
> + if (oldDef->s.virtio.pmem != newDef->s.virtio.pmem) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("cannot modify memory pmem flag"));
> + return false;
> + }
> +
> + if (!virBitmapEqual(oldDef->s.virtio.sourceNodes,
> + newDef->s.virtio.sourceNodes)) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("cannot modify memory source nodes"));
> + return false;
> + }
> +
> + if (oldDef->s.virtio.pagesize != newDef->s.virtio.pagesize) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory pagesize from '%llu' to '%llu'"),
> + oldDef->s.virtio.pagesize,
> + newDef->s.virtio.pagesize);
> + return false;
> + }
> + break;
> +
> + case VIR_DOMAIN_MEMORY_MODEL_NONE:
> + case VIR_DOMAIN_MEMORY_MODEL_DIMM:
> + case VIR_DOMAIN_MEMORY_MODEL_LAST:
> + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("cannot modify memory of model '%s'"),
> + virDomainMemoryModelTypeToString(oldDef->model));
> + return false;
> + break;
> + }
> +
> + return true;
> +}
> +
> +
> +static int
> +qemuDomainChangeMemoryLive(virQEMUDriverPtr driver G_GNUC_UNUSED,
> + virDomainObjPtr vm,
> + virDomainDeviceDefPtr dev)
> +{
> + virDomainMemoryDefPtr newDef = dev->data.memory;
> + virDomainMemoryDefPtr oldDef = NULL;
> + ssize_t idx;
> +
> + idx = virDomainMemoryFindByDeviceInfo(vm->def, &dev->data.memory->info);
> + if (idx < 0) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("memory '%s' not found"), dev->data.memory->info.alias);
> + return -1;
> + }
> +
> + oldDef = vm->def->mems[idx];
> +
> + if (newDef->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO ||
> + newDef->s.virtio.pmem) {
> + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> + _("changing anything but <requested/> size for virtio-mem is not implemented yet"));
> + return -1;
> + }
> +
> + if (!qemuDomainChangeMemoryLiveValidateChange(oldDef, newDef))
> + return -1;
> +
> + if (qemuDomainChangeMemoryRequestedSize(driver, vm,
> + newDef->info.alias,
> + newDef->requestedsize) < 0)
> + return -1;
> +
> + oldDef->requestedsize = newDef->requestedsize;
> + return 0;
> +}
> +
> +
> static int
> qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
> virDomainDeviceDefPtr dev,
> @@ -7150,6 +7302,18 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
> ret = qemuDomainChangeNet(driver, vm, dev);
> break;
>
> + case VIR_DOMAIN_DEVICE_MEMORY:
> + if ((idx = virDomainMemoryFindByDeviceInfo(vm->def, &dev->data.memory->info)) >= 0) {
> + oldDev.data.memory = vm->def->mems[idx];
> + if (virDomainDefCompatibleDevice(vm->def, dev, &oldDev,
> + VIR_DOMAIN_DEVICE_ACTION_UPDATE,
> + true) < 0)
> + return -1;
> + }
> +
> + ret = qemuDomainChangeMemoryLive(driver, vm, dev);
> + break;
> +
> case VIR_DOMAIN_DEVICE_FS:
> case VIR_DOMAIN_DEVICE_INPUT:
> case VIR_DOMAIN_DEVICE_SOUND:
> @@ -7165,7 +7329,6 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
> case VIR_DOMAIN_DEVICE_HOSTDEV:
> case VIR_DOMAIN_DEVICE_CONTROLLER:
> case VIR_DOMAIN_DEVICE_REDIRDEV:
> - case VIR_DOMAIN_DEVICE_MEMORY:
> case VIR_DOMAIN_DEVICE_CHR:
> case VIR_DOMAIN_DEVICE_NONE:
> case VIR_DOMAIN_DEVICE_TPM:
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index bc5dc02a2f..a18fa6d362 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -6672,3 +6672,21 @@ qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
> virBitmapFree(livevcpus);
> return ret;
> }
> +
> +
> +int
> +qemuDomainChangeMemoryRequestedSize(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + const char *alias,
> + unsigned long long requestedsize)
> +{
> + qemuDomainObjPrivatePtr priv = vm->privateData;
> + int rc;
> +
> + qemuDomainObjEnterMonitor(driver, vm);
> + rc = qemuMonitorChangeMemoryRequestedSize(priv->mon, alias, requestedsize);
> + if (qemuDomainObjExitMonitor(driver, vm) < 0)
> + return -1;
> +
> + return rc;
> +}
> diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
> index 6287c5b5e8..9e551a1f82 100644
> --- a/src/qemu/qemu_hotplug.h
> +++ b/src/qemu/qemu_hotplug.h
> @@ -160,3 +160,8 @@ int qemuHotplugAttachDBusVMState(virQEMUDriverPtr driver,
> int qemuHotplugRemoveDBusVMState(virQEMUDriverPtr driver,
> virDomainObjPtr vm,
> qemuDomainAsyncJob asyncJob);
> +
> +int qemuDomainChangeMemoryRequestedSize(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + const char *alias,
> + unsigned long long requestedsize);
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index f2ed165b22..ace7c889d4 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -4769,3 +4769,16 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
> return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
> bitmap, syncmode);
> }
> +
> +
> +int
> +qemuMonitorChangeMemoryRequestedSize(qemuMonitorPtr mon,
> + const char *alias,
> + unsigned long long requestedsize)
> +{
> + VIR_DEBUG("alias=%s requestedsize=%llu", alias, requestedsize);
> +
> + QEMU_CHECK_MONITOR(mon);
> +
> + return qemuMonitorJSONChangeMemoryRequestedSize(mon, alias, requestedsize);
> +}
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index d301568e40..c792c95c46 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -1527,3 +1527,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
> const char *target,
> const char *bitmap,
> qemuMonitorTransactionBackupSyncMode syncmode);
> +
> +int qemuMonitorChangeMemoryRequestedSize(qemuMonitorPtr mon,
> + const char *alias,
> + unsigned long long requestedsize);
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 723bdb4426..3d94181afb 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -9635,3 +9635,18 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
> return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
> migratable);
> }
> +
> +
> +int
> +qemuMonitorJSONChangeMemoryRequestedSize(qemuMonitorPtr mon,
> + const char *alias,
> + unsigned long long requestedsize)
> +{
> + g_autofree char *path = g_strdup_printf("/machine/peripheral/%s", alias);
> + qemuMonitorJSONObjectProperty prop = {
> + .type = QEMU_MONITOR_OBJECT_PROPERTY_ULONG,
> + .val.ul = requestedsize * 1024, /* monitor needs bytes */
> + };
> +
> + return qemuMonitorJSONSetObjectProperty(mon, path, "requested-size", &prop);
> +}
> diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
> index b588722d90..dcf101a165 100644
> --- a/src/qemu/qemu_monitor_json.h
> +++ b/src/qemu/qemu_monitor_json.h
> @@ -710,3 +710,8 @@ int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
> int
> qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
> bool *migratable);
> +
> +int
> +qemuMonitorJSONChangeMemoryRequestedSize(qemuMonitorPtr mon,
> + const char *alias,
> + unsigned long long requestedsize);
>
More information about the libvir-list
mailing list