[PATCH 0/4] Introduce dynamicMemslots attribute for virtio-mem

I couldn't decide whether the new attribute should be in <target/> or <memory/> element. I went with the former, but if anybody feels I should have went with the latter then I can change it. Michal Prívozník (4): conf: Introduce dynamicMemslots attribute for virtio-mem qemu_capabilities: Add QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI_DYNAMIC_MEMSLOTS capability qemu_validate: Check capability for virtio-mem dynamicMemslots qemu_command: Generate cmd line for virtio-mem dynamicMemslots docs/formatdomain.rst | 6 ++++++ src/conf/domain_conf.c | 18 +++++++++++++++++- src/conf/domain_conf.h | 1 + src/conf/schemas/domaincommon.rng | 5 +++++ src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 12 ++++++++++++ src/qemu/qemu_validate.c | 7 +++++++ .../qemucapabilitiesdata/caps_8.2.0_x86_64.xml | 1 + ...emory-hotplug-virtio-mem.x86_64-latest.args | 2 +- .../memory-hotplug-virtio-mem.xml | 2 +- 11 files changed, 54 insertions(+), 3 deletions(-) -- 2.41.0

Introduced in v8.2.0-rc0~74^2~2, QEMU now allows setting .dynamic-memslots attribute for virtio-mem-pci devices. When turned on, it allows memory exposed to guest to be split into multiple memslots and thus smaller memory footprint (see the original commit for detailed explanation). Therefore, introduce new <target/> attribute which will control that QEMU knob. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.rst | 6 ++++++ src/conf/domain_conf.c | 18 +++++++++++++++++- src/conf/domain_conf.h | 1 + src/conf/schemas/domaincommon.rng | 5 +++++ .../memory-hotplug-virtio-mem.xml | 2 +- 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 96e03a3807..57974de9f4 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8395,6 +8395,12 @@ Example: usage of the memory devices The ``node`` subelement configures the guest NUMA node to attach the memory to. The element shall be used only if the guest has NUMA nodes configured. + For ``virtio-mem`` optional attribute ``dynamicMemslots`` can be specified + (accepted values "yes"/"no") which allows hypervisor to spread memory into + multiple memory slots (allocate them dynamically based on the amount of + memory exposed to the guest), resulting in smaller memory footprint. + :since:`Since 10.0.0 and QEMU 8.2.0` + The following optional elements may be used: ``label`` diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 82672b30a0..c53e72210c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -13499,6 +13499,10 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node, &def->target.virtio_mem.requestedsize, false, false) < 0) return -1; + if (virXMLPropTristateBool(node, "dynamicMemslots", VIR_XML_PROP_NONE, + &def->target.virtio_mem.dynamicMemslots) < 0) + return -1; + addrNode = virXPathNode("./address", ctxt); addr = &def->target.virtio_mem.address; break; @@ -21174,6 +21178,12 @@ virDomainMemoryDefCheckABIStability(virDomainMemoryDef *src, src->target.virtio_mem.address); return false; } + + if (src->target.virtio_mem.dynamicMemslots != dst->target.virtio_mem.dynamicMemslots) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Target memory device 'dynamicMemslots' property doesn't match source memory device")); + return false; + } break; case VIR_DOMAIN_MEMORY_MODEL_DIMM: @@ -25375,6 +25385,7 @@ virDomainMemoryTargetDefFormat(virBuffer *buf, unsigned int flags) { g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; virBufferAsprintf(&childBuf, "<size unit='KiB'>%llu</size>\n", def->size); if (def->targetNode >= 0) @@ -25414,6 +25425,11 @@ virDomainMemoryTargetDefFormat(virBuffer *buf, if (def->target.virtio_mem.address) virBufferAsprintf(&childBuf, "<address base='0x%llx'/>\n", def->target.virtio_mem.address); + + if (def->target.virtio_mem.dynamicMemslots) { + virBufferAsprintf(&attrBuf, " dynamicMemslots='%s'", + virTristateBoolTypeToString(def->target.virtio_mem.dynamicMemslots)); + } break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: @@ -25423,7 +25439,7 @@ virDomainMemoryTargetDefFormat(virBuffer *buf, break; } - virXMLFormatElement(buf, "target", NULL, &childBuf); + virXMLFormatElement(buf, "target", &attrBuf, &childBuf); } static int diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 14901b37ba..6e45b7fb6e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2674,6 +2674,7 @@ struct _virDomainMemoryDef { unsigned long long currentsize; /* kibibytes, valid for an active domain only and parsed */ unsigned long long address; /* address where memory is mapped */ + virTristateBool dynamicMemslots; } virtio_mem; struct { } sgx_epc; diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index f318c06797..08c408e138 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -7260,6 +7260,11 @@ <define name="memorydev-target"> <element name="target"> + <optional> + <attribute name="dynamicMemslots"> + <ref name="virYesNo"/> + </attribute> + </optional> <interleave> <element name="size"> <ref name="scaledInteger"/> diff --git a/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.xml b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.xml index c578209d8a..359ece7a77 100644 --- a/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.xml +++ b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.xml @@ -60,7 +60,7 @@ <nodemask>1-3</nodemask> <pagesize unit='KiB'>2048</pagesize> </source> - <target> + <target dynamicMemslots='yes'> <size unit='KiB'>2097152</size> <node>0</node> <block unit='KiB'>2048</block> -- 2.41.0

Starting from v8.2.0-rc0~74^2~2 QEMU has .dynamic-memslots attribute for virtio-mem-pci device. Introduce a capability which reflects that. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml | 1 + 3 files changed, 4 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 83119e871a..37b989b251 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -698,6 +698,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 450 */ "run-with.async-teardown", /* QEMU_CAPS_RUN_WITH_ASYNC_TEARDOWN */ "virtio-blk-vhost-vdpa", /* QEMU_CAPS_DEVICE_VIRTIO_BLK_VHOST_VDPA */ + "virtio-mem-pci.dynamic-memslots", /* QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI_DYNAMIC_MEMSLOTS */ ); @@ -1516,6 +1517,7 @@ static struct virQEMUCapsDevicePropsFlags virQEMUCapsDevicePropsVhostUserFS[] = static struct virQEMUCapsDevicePropsFlags virQEMUCapsDevicePropsVirtioMemPCI[] = { { "prealloc", QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI_PREALLOC, NULL }, + { "dynamic-memslots", QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI_DYNAMIC_MEMSLOTS, NULL }, }; static struct virQEMUCapsDevicePropsFlags virQEMUCapsDevicePropsVirtioIOMMU[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 3c4f7f625b..97022eab91 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -677,6 +677,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 450 */ QEMU_CAPS_RUN_WITH_ASYNC_TEARDOWN, /* asynchronous teardown -run-with async-teardown=on|off */ QEMU_CAPS_DEVICE_VIRTIO_BLK_VHOST_VDPA, /* virtio-blk-vhost-vdpa block driver */ + QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI_DYNAMIC_MEMSLOTS, /* -device virtio-mem-pci.dynamic-memslots= */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml index ee52952702..f976a8d2df 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml @@ -199,6 +199,7 @@ <flag name='qcow2-discard-no-unref'/> <flag name='run-with.async-teardown'/> <flag name='virtio-blk-vhost-vdpa'/> + <flag name='virtio-mem-pci.dynamic-memslots'/> <version>8002000</version> <microcodeVersion>43100246</microcodeVersion> <package>v8.2.0</package> -- 2.41.0

The QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI_DYNAMIC_MEMSLOTS reflects whether QEMU is capable of .dynamic-memslots for virtio-mem. Use it when validating domain configuration. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_validate.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 9e50c2f45b..3b0dfec2b4 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -4971,6 +4971,13 @@ qemuValidateDomainDeviceDefMemory(virDomainMemoryDef *mem, _("virtio-mem isn't supported by this QEMU binary")); return -1; } + + if (mem->target.virtio_mem.dynamicMemslots == VIR_TRISTATE_BOOL_YES && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI_DYNAMIC_MEMSLOTS)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("virtio-mem does not support dynamicMemslots")); + return -1; + } break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: -- 2.41.0

This is straightforward, pretty much. The only odd thing is: .dynamic-memslots=true requires .unplugged-inaccessible="on". While the latter is currently the default, it's not guaranteed to stay that way. Play it safe and explicitly set both. Resolves: https://issues.redhat.com/browse/RHEL-15316 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 12 ++++++++++++ .../memory-hotplug-virtio-mem.x86_64-latest.args | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index bc285c0b6f..5c79fa0836 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3608,6 +3608,8 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, unsigned long long requestedsize = 0; unsigned long long address = 0; bool prealloc = false; + bool dynamicMemslots = false; + const char *unpluggedInacessible = NULL; if (!mem->info.alias) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -3649,6 +3651,14 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, blocksize = mem->target.virtio_mem.blocksize; requestedsize = mem->target.virtio_mem.requestedsize; address = mem->target.virtio_mem.address; + dynamicMemslots = mem->target.virtio_mem.dynamicMemslots; + if (dynamicMemslots) { + /* Currently, .dynamic-memslots=true requires + * .unplugged-inaccessible="on" (see QEMU commit + * v8.2.0-rc0~74^2~2). And while the latter is the default + * (currently), let's not rely on that. */ + unpluggedInacessible = "on"; + } break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: @@ -3671,6 +3681,8 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, "s:memdev", memdev, "B:prealloc", prealloc, "P:memaddr", address, + "B:dynamic-memslots", dynamicMemslots, + "S:unplugged-inaccessible", unpluggedInacessible, "s:id", mem->info.alias, NULL) < 0) return NULL; diff --git a/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.x86_64-latest.args b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.x86_64-latest.args index 607ce9b0e8..ae23504c32 100644 --- a/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.x86_64-latest.args +++ b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.x86_64-latest.args @@ -32,7 +32,7 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \ -object '{"qom-type":"memory-backend-ram","id":"memvirtiomem0","reserve":false,"size":1073741824}' \ -device '{"driver":"virtio-mem-pci","node":0,"block-size":2097152,"requested-size":536870912,"memdev":"memvirtiomem0","id":"virtiomem0","bus":"pci.0","addr":"0x2"}' \ -object '{"qom-type":"memory-backend-file","id":"memvirtiomem1","mem-path":"/dev/hugepages2M/libvirt/qemu/-1-QEMUGuest1","reserve":false,"size":2147483648,"host-nodes":[1,2,3],"policy":"bind"}' \ --device '{"driver":"virtio-mem-pci","node":0,"block-size":2097152,"requested-size":1073741824,"memdev":"memvirtiomem1","prealloc":true,"memaddr":5637144576,"id":"virtiomem1","bus":"pci.1","addr":"0x1"}' \ +-device '{"driver":"virtio-mem-pci","node":0,"block-size":2097152,"requested-size":1073741824,"memdev":"memvirtiomem1","prealloc":true,"memaddr":5637144576,"dynamic-memslots":true,"unplugged-inaccessible":"on","id":"virtiomem1","bus":"pci.1","addr":"0x1"}' \ -blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \ -blockdev '{"node-name":"libvirt-1-format","read-only":false,"driver":"raw","file":"libvirt-1-storage"}' \ -device '{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-format","id":"ide0-0-0","bootindex":1}' \ -- 2.41.0
participants (1)
-
Michal Privoznik