[PATCH 05/10] qemu: Wire up <memory/> live update

Daniel Henrique Barboza danielhb413 at gmail.com
Fri Jan 22 18:23:16 UTC 2021



On 1/22/21 9:50 AM, Michal Privoznik wrote:
> As advertised in one of previous commits, 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.
> 
> Once guest has changed the allocation, QEMU emits an event which
> we will use to track the allocation. In the next commit.
> 
> 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       | 175 ++++++++++++++++++++++++++++++++++-
>   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, 261 insertions(+), 1 deletion(-)
> 
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index f8c5a40b24..b6fe5e4436 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -17297,6 +17297,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 5d89ecfe9d..ef52328a6f 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -3609,6 +3609,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 962d82680e..2e7f92bcfe 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -494,6 +494,7 @@ virDomainMemballoonModelTypeFromString;
>   virDomainMemballoonModelTypeToString;
>   virDomainMemoryDefFree;
>   virDomainMemoryFindByDef;
> +virDomainMemoryFindByDeviceInfo;
>   virDomainMemoryFindInactiveByDef;
>   virDomainMemoryInsert;
>   virDomainMemoryModelTypeToString;
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index ed966cf7e3..fadf0240fc 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -7087,6 +7087,168 @@ 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 (!virBitmapEqual(oldDef->sourceNodes,
> +                        newDef->sourceNodes)) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("cannot modify memory source nodes"));
> +        return false;
> +    }
> +
> +    if (oldDef->pagesize != newDef->pagesize) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("cannot modify memory pagesize from '%llu' to '%llu'"),
> +                       oldDef->pagesize,
> +                       newDef->pagesize);
> +        return false;
> +    }
> +
> +    if (STRNEQ_NULLABLE(oldDef->nvdimmPath, newDef->nvdimmPath)) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("cannot modify memory path from '%s' to '%s'"),
> +                       NULLSTR(oldDef->nvdimmPath),
> +                       NULLSTR(newDef->nvdimmPath));
> +        return false;
> +    }
> +
> +    if (oldDef->alignsize != newDef->alignsize) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("cannot modify memory align size from '%llu' to '%llu'"),
> +                       oldDef->alignsize, newDef->alignsize);
> +        return false;
> +    }
> +
> +    if (oldDef->nvdimmPmem != newDef->nvdimmPmem) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("cannot modify memory pmem from '%d' to '%d'"),
> +                       oldDef->nvdimmPmem, newDef->nvdimmPmem);
> +        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->labelsize != newDef->labelsize) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("cannot modify memory label size from '%llu' to '%llu'"),
> +                       oldDef->labelsize, newDef->labelsize);
> +        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 ((oldDef->uuid || newDef->uuid) &&
> +        !(oldDef->uuid && newDef->uuid &&
> +          memcmp(oldDef->uuid, newDef->uuid, 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_MEM:
> +        break;
> +
> +    case VIR_DOMAIN_MEMORY_MODEL_NONE:
> +    case VIR_DOMAIN_MEMORY_MODEL_DIMM:
> +    case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
> +    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
> +    case VIR_DOMAIN_MEMORY_MODEL_LAST:
> +        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 (!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,
> @@ -7128,6 +7290,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:
> @@ -7143,7 +7317,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 882e5d2384..88213a53f7 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -6702,3 +6702,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 09b8617097..6b3c1c2f5e 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -4713,3 +4713,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 a07617ec28..443ddddf9b 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -1516,3 +1516,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 8a75a2734e..0ab4264522 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -9452,3 +9452,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 ba1531fee8..53af2b4022 100644
> --- a/src/qemu/qemu_monitor_json.h
> +++ b/src/qemu/qemu_monitor_json.h
> @@ -705,3 +705,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