libvirt-11.10.0-10.7.el10nv

- conf: Support EGM memory device model (VOYAGER-13)
- qemu: Add cgroup, namespace, and seclabel setup for EGM memory device model (VOYAGER-13)
- qemu: Add qemu CLI support for EGM (VOYAGER-13)
- tests: Add qemuxmlconftest for ACPI EGM memory device (VOYAGER-13)

Resolves: VOYAGER-13
This commit is contained in:
Pavel Hrdina 2026-05-18 12:04:04 +02:00
parent f61b15baa2
commit dd91c3be50
6 changed files with 1506 additions and 11 deletions

View File

@ -1,10 +0,0 @@
# recipients: libvirt-qe
--- !Policy
product_versions:
- rhel-10
decision_context: osci_compose_gate
subject_type: brew-build
rules:
- !PassingTestCaseRule {test_case_name: libvirt-ci.libvirt.brew-build.gating.x86_64.tier1.functional}
- !PassingTestCaseRule {test_case_name: libvirt-ci.libvirt-python.brew-build.gating.x86_64.tier1.functional}
- !PassingTestCaseRule {test_case_name: libvirt-ci.libvirt.brew-build.gating.s390x.tier1.functional}

View File

@ -0,0 +1,275 @@
From 8049e03589d633edba613c6775dcd5656d851460 Mon Sep 17 00:00:00 2001
Message-ID: <8049e03589d633edba613c6775dcd5656d851460.1779098642.git.phrdina@redhat.com>
From: Pavel Hrdina <phrdina@redhat.com>
Date: Tue, 25 Nov 2025 11:17:01 -0800
Subject: [PATCH] conf: Support EGM memory device model
From: Nathan Chen via Devel <devel@lists.libvirt.org>
Add support for EGM memory device model with
'path' source attribute and 'pciDev' target
attribute to denote host EGM device backing path
and PCI device alias to associate the vEGM with,
respectively.
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
Resolves: https://redhat.atlassian.net/browse/VOYAGER-13
---
docs/formatdomain.rst | 18 +++++++++++++++++-
src/conf/domain_conf.c | 29 +++++++++++++++++++++++++++++
src/conf/domain_conf.h | 7 +++++++
src/conf/domain_postparse.c | 1 +
src/conf/domain_validate.c | 15 +++++++++++++++
src/conf/schemas/domaincommon.rng | 6 ++++++
6 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 44f9b6e197..4fde1534d6 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -9119,6 +9119,16 @@ Example: usage of the memory devices
<size unit='KiB'>16384</size>
</target>
</memory>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm0</path>
+ </source>
+ <target>
+ <size unit='KiB'>524288</size>
+ <node>0</node>
+ <pciDev>ua-hostdev0</pciDev>
+ </target>
+ </memory>
</devices>
...
@@ -9130,7 +9140,8 @@ Example: usage of the memory devices
persistent memory device. :since:`Since 7.1.0` Provide ``virtio-mem`` model
to add paravirtualized memory device. :since:`Since 7.9.0` Provide
``sgx-epc`` model to add a SGX enclave page cache (EPC) memory to the guest.
- :since:`Since 8.10.0 and QEMU 7.0.0`
+ :since:`Since 8.10.0 and QEMU 7.0.0` Provide ``egm`` model to add a EGM
+ (Extended GPU Memory) device.
``access``
An optional attribute ``access`` ( :since:`since 3.2.0` ) that provides
@@ -9265,6 +9276,11 @@ Example: usage of the memory devices
The physical address in memory, where device is mapped.
:since:`Since 9.4.0`
+ ``pciDev``
+ For ``egm`` only.
+ The PCI device that is enabled to access the system memory via
+ association with the EGM device.
+
IOMMU devices
~~~~~~~~~~~~~
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 06790e0962..038476edd7 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1522,6 +1522,7 @@ VIR_ENUM_IMPL(virDomainMemoryModel,
"virtio-pmem",
"virtio-mem",
"sgx-epc",
+ "egm",
);
VIR_ENUM_IMPL(virDomainShmemModel,
@@ -3638,6 +3639,9 @@ void virDomainMemoryDefFree(virDomainMemoryDef *def)
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
virBitmapFree(def->source.sgx_epc.nodes);
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ g_free(def->source.egm.path);
+ g_free(def->target.egm.pciDev);
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -14216,6 +14220,10 @@ virDomainMemorySourceDefParseXML(xmlNodePtr node,
}
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ def->source.egm.path = virXPathString("string(./path)", ctxt);
+ break;
+
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -14292,6 +14300,10 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node,
addr = &def->target.virtio_pmem.address;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ def->target.egm.pciDev = virXPathString("string(./pciDev)", ctxt);
+ break;
+
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
@@ -14513,6 +14525,7 @@ virDomainMemoryIsVirtioModel(const virDomainMemoryDef *def)
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
}
@@ -16415,6 +16428,12 @@ virDomainMemoryFindByDefInternal(virDomainDef *def,
continue;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ if (STRNEQ(tmp->source.egm.path, mem->source.egm.path))
+ continue;
+ if (STRNEQ(tmp->target.egm.pciDev, mem->target.egm.pciDev))
+ continue;
+
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -22430,6 +22449,7 @@ virDomainMemoryDefCheckABIStability(virDomainMemoryDef *src,
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -26998,6 +27018,10 @@ virDomainMemorySourceDefFormat(virBuffer *buf,
}
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ virBufferEscapeString(&childBuf, "<path>%s</path>\n", def->source.egm.path);
+ break;
+
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -27060,6 +27084,11 @@ virDomainMemoryTargetDefFormat(virBuffer *buf,
}
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ if (def->target.egm.pciDev)
+ virBufferAsprintf(&childBuf, "<pciDev>%s</pciDev>\n", def->target.egm.pciDev);
+ break;
+
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 06e03deafe..4d03521245 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2755,6 +2755,7 @@ typedef enum {
VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM, /* virtio-pmem memory device */
VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM, /* virtio-mem memory device */
VIR_DOMAIN_MEMORY_MODEL_SGX_EPC, /* SGX enclave page cache */
+ VIR_DOMAIN_MEMORY_MODEL_EGM, /* Extended GPU memory */
VIR_DOMAIN_MEMORY_MODEL_LAST
} virDomainMemoryModel;
@@ -2787,6 +2788,9 @@ struct _virDomainMemoryDef {
struct {
virBitmap *nodes; /* source NUMA nodes */
} sgx_epc;
+ struct {
+ char *path;
+ } egm;
} source;
union {
@@ -2812,6 +2816,9 @@ struct _virDomainMemoryDef {
} virtio_mem;
struct {
} sgx_epc;
+ struct {
+ char *pciDev;
+ } egm;
} target;
virDomainDeviceInfo info;
diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c
index 38e731348d..0181d21f0e 100644
--- a/src/conf/domain_postparse.c
+++ b/src/conf/domain_postparse.c
@@ -632,6 +632,7 @@ virDomainMemoryDefPostParse(virDomainMemoryDef *mem,
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index f243b119a4..34906ddc84 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -2525,6 +2525,7 @@ virDomainMemoryDefCheckConflict(const virDomainMemoryDef *mem,
}
break;
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -2571,6 +2572,7 @@ virDomainMemoryDefCheckConflict(const virDomainMemoryDef *mem,
switch (other->model) {
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
continue;
break;
@@ -2751,6 +2753,19 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem,
}
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ if (!mem->source.egm.path) {
+ virReportError(VIR_ERR_XML_DETAIL, "%s",
+ _("path is required for model 'egm'"));
+ return -1;
+ }
+ if (!mem->target.egm.pciDev) {
+ virReportError(VIR_ERR_XML_DETAIL, "%s",
+ _("pciDev is required for model 'egm'"));
+ return -1;
+ }
+ break;
+
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
default:
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index 839a144da8..123e4057b7 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -7561,6 +7561,7 @@
<value>virtio-pmem</value>
<value>virtio-mem</value>
<value>sgx-epc</value>
+ <value>egm</value>
</choice>
</attribute>
<optional>
@@ -7692,6 +7693,11 @@
</attribute>
</element>
</optional>
+ <optional>
+ <element name="pciDev">
+ <data type="string"/>
+ </element>
+ </optional>
</interleave>
</element>
</define>
--
2.54.0

View File

@ -0,0 +1,166 @@
From d1f3b404a08e097e6ddac10452b4ed142e35a89b Mon Sep 17 00:00:00 2001
Message-ID: <d1f3b404a08e097e6ddac10452b4ed142e35a89b.1779098642.git.phrdina@redhat.com>
From: Pavel Hrdina <phrdina@redhat.com>
Date: Tue, 25 Nov 2025 11:17:02 -0800
Subject: [PATCH] qemu: Add cgroup, namespace, and seclabel setup for EGM
memory device model
From: Nathan Chen via Devel <devel@lists.libvirt.org>
Implement proper isolation and access control for EGM memory devices:
- Add device to cgroup for access control
- Set up namespace mappings for device access
- Ensure proper permissions in containerized environments
- Allow EGM device path access to bypass SELinux, AppArmor,
and DAC permissions
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
Resolves: https://redhat.atlassian.net/browse/VOYAGER-13
---
src/qemu/qemu_cgroup.c | 10 ++++++++++
src/qemu/qemu_namespace.c | 3 +++
src/security/apparmor/usr.sbin.libvirtd.in | 3 +++
src/security/security_apparmor.c | 2 ++
src/security/security_dac.c | 8 ++++++++
src/security/security_selinux.c | 6 ++++++
src/security/virt-aa-helper.c | 4 ++++
7 files changed, 36 insertions(+)
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 0e1815f571..ee3795329a 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -580,6 +580,11 @@ qemuSetupMemoryDevicesCgroup(virDomainObj *vm,
VIR_CGROUP_DEVICE_RW, false) < 0)
return -1;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ if (qemuCgroupAllowDevicePath(vm, mem->source.egm.path,
+ VIR_CGROUP_DEVICE_RW, false) < 0)
+ return -1;
+ break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
@@ -618,6 +623,11 @@ qemuTeardownMemoryDevicesCgroup(virDomainObj *vm,
VIR_CGROUP_DEVICE_RW, false) < 0)
return -1;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ if (qemuCgroupDenyDevicePath(vm, mem->source.egm.path,
+ VIR_CGROUP_DEVICE_RWM, false) < 0)
+ return -1;
+ break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c
index 4a063064f1..f17a59545b 100644
--- a/src/qemu/qemu_namespace.c
+++ b/src/qemu/qemu_namespace.c
@@ -397,6 +397,9 @@ qemuDomainSetupMemory(virDomainMemoryDef *mem,
*paths = g_slist_prepend(*paths, g_strdup(QEMU_DEV_SGX_VEPVC));
*paths = g_slist_prepend(*paths, g_strdup(QEMU_DEV_SGX_PROVISION));
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ *paths = g_slist_prepend(*paths, g_strdup(mem->source.egm.path));
+ break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
diff --git a/src/security/apparmor/usr.sbin.libvirtd.in b/src/security/apparmor/usr.sbin.libvirtd.in
index 6267e4f737..2a6a4b979c 100644
--- a/src/security/apparmor/usr.sbin.libvirtd.in
+++ b/src/security/apparmor/usr.sbin.libvirtd.in
@@ -47,6 +47,9 @@ profile libvirtd @sbindir@/libvirtd flags=(attach_disconnected) {
mount options=(rw, move) /{,var/}run/libvirt/qemu/*{,/} -> /dev/**,
umount /{,var/}run/libvirt/qemu/*{,/},
+ # Allow bind mounting EGM devices into qemu namespaces
+ mount options=(rw, bind) /dev/egm* -> /{,var/}run/libvirt/qemu/**,
+
network inet stream,
network inet dgram,
network inet6 stream,
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index e53486ee0c..4d8b1e20d3 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -631,6 +631,8 @@ AppArmorSetMemoryLabel(virSecurityManager *mgr,
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ path = mem->source.egm.path;
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
}
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index b891f6f121..bff0e03f35 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1909,6 +1909,9 @@ virSecurityDACRestoreMemoryLabel(virSecurityManager *mgr,
* don't need to restore anything. */
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ return virSecurityDACRestoreFileLabel(mgr, mem->source.egm.path);
+
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
@@ -2140,6 +2143,11 @@ virSecurityDACSetMemoryLabel(virSecurityManager *mgr,
return -1;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ return virSecurityDACSetOwnership(mgr, NULL,
+ mem->source.egm.path,
+ user, group, true);
+
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 2b801aecd5..fd7d5ff703 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -1666,6 +1666,9 @@ virSecuritySELinuxSetMemoryLabel(virSecurityManager *mgr,
seclabel->imagelabel, true) < 0)
return -1;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ path = mem->source.egm.path;
+ break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
@@ -1709,6 +1712,9 @@ virSecuritySELinuxRestoreMemoryLabel(virSecurityManager *mgr,
if (virSecuritySELinuxRestoreFileLabel(mgr, DEV_SGX_PROVISION, true, false) < 0)
ret = -1;
return ret;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ path = mem->source.egm.path;
+ break;
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index af95a64c42..0a62a30da3 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -1196,6 +1196,10 @@ get_files(vahControl * ctl)
return -1;
}
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ if (vah_add_file(&buf, mem->source.egm.path, "rw") != 0)
+ return -1;
+ break;
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
--
2.54.0

View File

@ -0,0 +1,528 @@
From 9965f1b7b0fb1810fe32498f7892aa549a754d19 Mon Sep 17 00:00:00 2001
Message-ID: <9965f1b7b0fb1810fe32498f7892aa549a754d19.1779098642.git.phrdina@redhat.com>
From: Pavel Hrdina <phrdina@redhat.com>
Date: Tue, 25 Nov 2025 11:17:03 -0800
Subject: [PATCH] qemu: Add qemu CLI support for EGM
From: Nathan Chen via Devel <devel@lists.libvirt.org>
Add qemu CLI support for EGM memory device model:
- Specify EGM device path to memory-backend-file object
- Support acpi-egm-memory object with id, pci-dev, and
node attributes
- Consolidate all acpi-egm-memory objects' memory into
a single memory-backend-file per EGM chardev
specified.
Signed-off-by: Ian May <ianm@nvidia.com>
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
Resolves: https://redhat.atlassian.net/browse/VOYAGER-13
---
src/qemu/qemu_alias.c | 7 +-
src/qemu/qemu_capabilities.c | 2 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 158 ++++++++++++++++++++++++++++++---
src/qemu/qemu_domain.c | 13 ++-
src/qemu/qemu_domain_address.c | 3 +
src/qemu/qemu_driver.c | 1 +
src/qemu/qemu_hotplug.c | 1 +
src/qemu/qemu_monitor_json.c | 1 +
src/qemu/qemu_postparse.c | 1 +
src/qemu/qemu_process.c | 2 +
src/qemu/qemu_validate.c | 6 ++
12 files changed, 180 insertions(+), 16 deletions(-)
diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index 400ce73283..719224e1ba 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -504,7 +504,8 @@ qemuDeviceMemoryGetAliasID(virDomainDef *def,
* valid */
if (mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM &&
mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM &&
- mem->model != VIR_DOMAIN_MEMORY_MODEL_SGX_EPC)
+ mem->model != VIR_DOMAIN_MEMORY_MODEL_SGX_EPC &&
+ mem->model != VIR_DOMAIN_MEMORY_MODEL_EGM)
return mem->info.addr.dimm.slot;
for (i = 0; i < def->nmems; i++) {
@@ -553,6 +554,10 @@ qemuAssignDeviceMemoryAlias(virDomainDef *def,
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
prefix = "epc";
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM: {
+ prefix = "egm";
+ break;
+ }
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
default:
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index ed6aa86da2..010933bc4e 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -760,6 +760,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
/* 490 */
"iommufd", /* QEMU_CAPS_OBJECT_IOMMUFD */
+ "acpi-egm-memory", /* QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY */
);
@@ -1468,6 +1469,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
{ "tpm-passthrough", QEMU_CAPS_DEVICE_TPM_PASSTHROUGH },
{ "acpi-generic-initiator", QEMU_CAPS_ACPI_GENERIC_INITIATOR },
{ "iommufd", QEMU_CAPS_OBJECT_IOMMUFD },
+ { "acpi-egm-memory", QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY },
};
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index f7c8680f94..85615b4524 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -734,6 +734,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
/* 490 */
QEMU_CAPS_OBJECT_IOMMUFD, /* -object iommufd */
+ QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY, /* For using extended GPU memory */
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a76f504e6f..63fd9885b7 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -135,6 +135,21 @@ VIR_ENUM_IMPL(qemuACPITableSIG,
"SLIC",
"MSDM");
+typedef struct _qemuEGMBackendInfo {
+ char *alias;
+ unsigned long long totalSize;
+ bool created;
+ virDomainMemoryDef *firstMem; /* Pointer to first device for this path */
+} qemuEGMBackendInfo;
+
+static void
+qemuEGMBackendInfoFree(qemuEGMBackendInfo *info)
+{
+ if (!info)
+ return;
+ g_free(info->alias);
+ g_free(info);
+}
const char *
qemuAudioDriverTypeToString(virDomainAudioType type)
@@ -992,6 +1007,7 @@ qemuBuildVirtioDevGetConfigDev(const virDomainDeviceDef *device,
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -3166,6 +3182,7 @@ qemuBuildMemoryGetPagesize(virQEMUDriverConfig *cfg,
nvdimmPath = mem->source.virtio_pmem.path;
break;
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -3366,6 +3383,9 @@ qemuBuildMemoryBackendProps(virJSONValue **backendProps,
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
nvdimmPath = mem->source.virtio_pmem.path;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ nvdimmPath = mem->source.egm.path;
+ break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -3577,12 +3597,17 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd,
virDomainMemoryDef *mem,
virDomainDef *def,
virQEMUDriverConfig *cfg,
- qemuDomainObjPrivate *priv)
+ qemuDomainObjPrivate *priv,
+ GHashTable *egmBackends)
{
g_autoptr(virJSONValue) props = NULL;
g_autoptr(virJSONValue) tcProps = NULL;
virBitmap *nodemask = NULL;
g_autofree char *alias = NULL;
+ unsigned long long originalSize = 0;
+ bool isEGM = (mem->model == VIR_DOMAIN_MEMORY_MODEL_EGM);
+ bool shouldCreateBackend = true;
+ qemuEGMBackendInfo *egmInfo = NULL;
if (!mem->info.alias) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -3592,19 +3617,65 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd,
alias = g_strdup_printf("mem%s", mem->info.alias);
- if (qemuBuildMemoryBackendProps(&props, alias, cfg, priv,
- def, mem, true, false, &nodemask) < 0)
- return -1;
+ /* Handle EGM shared backend logic */
+ if (isEGM && egmBackends) {
+ const char *egmPath = mem->source.egm.path;
+ egmInfo = g_hash_table_lookup(egmBackends, egmPath);
- if (qemuBuildThreadContextProps(&tcProps, &props, def, priv, nodemask) < 0)
- return -1;
+ if (egmInfo) {
+ alias = g_strdup(egmInfo->alias);
+ if (egmInfo->created) {
+ /* Backend already created, skip backend creation */
+ shouldCreateBackend = false;
+ } else {
+ /* First device for this path - temporarily use accumulated size */
+ originalSize = mem->size;
+ mem->size = egmInfo->totalSize;
+ egmInfo->created = true;
+ }
+ }
+ }
- if (tcProps &&
- qemuBuildObjectCommandlineFromJSON(cmd, tcProps) < 0)
- return -1;
+ if (shouldCreateBackend) {
+ /* Use existing function unchanged */
+ if (qemuBuildMemoryBackendProps(&props, alias, cfg, priv,
+ def, mem, true, false, &nodemask) < 0) {
+ if (originalSize > 0)
+ mem->size = originalSize; /* Restore on error */
+ return -1;
+ }
- if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0)
- return -1;
+ /* Restore original size after backend props are built */
+ if (originalSize > 0)
+ mem->size = originalSize;
+
+ if (qemuBuildThreadContextProps(&tcProps, &props, def, priv, nodemask) < 0)
+ return -1;
+
+ if (tcProps &&
+ qemuBuildObjectCommandlineFromJSON(cmd, tcProps) < 0)
+ return -1;
+
+ if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0)
+ return -1;
+ }
+
+ if (isEGM) {
+ g_autofree char *egmObjStr = NULL;
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, "acpi-egm-memory,id=%s", mem->info.alias);
+
+ if (mem->target.egm.pciDev)
+ virBufferAsprintf(&buf, ",pci-dev=%s", mem->target.egm.pciDev);
+
+ if (mem->targetNode >= 0)
+ virBufferAsprintf(&buf, ",node=%d", mem->targetNode);
+
+ egmObjStr = virBufferContentAndReset(&buf);
+
+ virCommandAddArgList(cmd, "-object", egmObjStr, NULL);
+ }
return 0;
}
@@ -3675,6 +3746,7 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg,
dynamicMemslots = mem->target.virtio_mem.dynamicMemslots;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
@@ -7193,6 +7265,7 @@ qemuAppendDomainMemoryMachineParams(virBuffer *buf,
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -7910,6 +7983,8 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
size_t ncells = virDomainNumaGetNodeCount(def->numa);
ssize_t masterInitiator = -1;
int rc;
+ g_autoptr(GHashTable) egmBackends = NULL;
+ size_t egmBackendCount = 0;
if (!virDomainNumatuneNodesetIsAvailable(def->numa, priv->autoNodeset))
goto cleanup;
@@ -7924,6 +7999,37 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
hmat = true;
}
+ /* Pre-scan EGM devices to group by path and calculate total sizes */
+ egmBackends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify)qemuEGMBackendInfoFree);
+
+ for (i = 0; i < def->nmems; i++) {
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) {
+ const char *egmPath = def->mems[i]->source.egm.path;
+ qemuEGMBackendInfo *info = g_hash_table_lookup(egmBackends, egmPath);
+
+ if (!info) {
+ info = g_new0(qemuEGMBackendInfo, 1);
+ info->alias = g_strdup_printf("memegm%zu", egmBackendCount);
+ egmBackendCount++;
+ info->totalSize = def->mems[i]->size;
+ info->created = false;
+ info->firstMem = def->mems[i];
+ g_hash_table_insert(egmBackends, g_strdup(egmPath), info);
+ } else {
+ info->totalSize += def->mems[i]->size;
+ }
+ }
+ }
+
+ /* Build the actual backend and device objects */
+ for (i = 0; i < def->nmems; i++) {
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) {
+ if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv, egmBackends) < 0)
+ goto cleanup;
+ }
+ }
+
nodeBackends = g_new0(virJSONValue *, ncells);
nodemask = g_new0(virBitmap *, ncells);
@@ -7959,8 +8065,18 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
for (i = 0; i < ncells; i++) {
ssize_t initiator = virDomainNumaGetNodeInitiator(def->numa, i);
unsigned long long memSize = virDomainNumaGetNodeMemorySize(def->numa, i);
+ bool egmBacked = false;
+ size_t k;
- if (needBackend && memSize > 0) {
+ for (k = 0; k < def->nmems; k++) {
+ if (def->mems[k]->model == VIR_DOMAIN_MEMORY_MODEL_EGM &&
+ def->mems[k]->targetNode == (int)i) {
+ egmBacked = true;
+ break;
+ }
+ }
+
+ if (needBackend && memSize > 0 && !egmBacked) {
g_autoptr(virJSONValue) tcProps = NULL;
if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i],
@@ -7990,7 +8106,15 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
if (memSize > 0) {
if (needBackend) {
- virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
+ if (egmBacked) {
+ /* Look up the actual backend alias for EGM */
+ const char *egmPath = def->mems[k]->source.egm.path;
+ qemuEGMBackendInfo *egmInfo = g_hash_table_lookup(egmBackends, egmPath);
+ const char *backendAlias = egmInfo ? egmInfo->alias : def->mems[k]->info.alias;
+ virBufferAsprintf(&buf, ",memdev=%s", backendAlias);
+ } else {
+ virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
+ }
} else {
virBufferAsprintf(&buf, ",mem=%llu", memSize / 1024);
}
@@ -8054,7 +8178,10 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd,
for (i = 0; i < def->nmems; i++) {
g_autoptr(virJSONValue) props = NULL;
- if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv) < 0)
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM)
+ continue;
+
+ if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv, NULL) < 0)
return -1;
switch (def->mems[i]->model) {
@@ -8074,6 +8201,9 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd,
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
break;
+ /* EGM memory backing is via memory-backend-file object */
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 495cbd4f7d..c5e3d09360 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -7266,6 +7266,7 @@ qemuDomainUpdateMemoryDeviceInfo(virDomainObj *vm,
break;
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -7500,7 +7501,8 @@ qemuDomainAlignMemorySizes(virDomainDef *def)
def->mems[i]->size = VIR_ROUND_UP(def->mems[i]->size, align);
}
- hotplugmem += def->mems[i]->size;
+ if (def->mems[i]->model != VIR_DOMAIN_MEMORY_MODEL_EGM)
+ hotplugmem += def->mems[i]->size;
if (def->mems[i]->size > maxmemkb) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -7988,6 +7990,12 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDomainMemoryDef *mem,
virDomainMemoryModelTypeToString(mem->model));
return -1;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("hotplug is not supported for the %1$s device"),
+ virDomainMemoryModelTypeToString(mem->model));
+ return -1;
+
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
return -1;
@@ -8046,6 +8054,7 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def,
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
break;
@@ -8093,6 +8102,8 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def,
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
/* sgx epc memory does not support hotplug, skip this check */
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ /* egm memory does not support hotplug, skip this check */
case VIR_DOMAIN_MEMORY_MODEL_LAST:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
break;
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 7233df888c..97e533bf9a 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -3124,6 +3124,7 @@ qemuDomainAssignMemoryDeviceSlot(virDomainObj *vm,
return qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev);
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -3151,6 +3152,7 @@ qemuDomainReleaseMemoryDeviceSlot(virDomainObj *vm,
break;
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -3185,6 +3187,7 @@ qemuDomainAssignMemorySlots(virDomainDef *def)
/* handled in qemuDomainAssignPCIAddresses() */
break;
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5e63614b4a..247c98d84e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6712,6 +6712,7 @@ qemuDomainAttachMemoryConfig(virDomainDef *vmdef,
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 8944062aa4..de47702bc5 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -7417,6 +7417,7 @@ qemuDomainChangeMemoryLiveValidateChange(const virDomainMemoryDef *oldDef,
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("cannot modify memory of model '%1$s'"),
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 45f690d9e2..2bf9bb885e 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -7285,6 +7285,7 @@ qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitor *mon,
switch ((virDomainMemoryModel) model) {
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
/* While 'id' attribute is marked as optional in QEMU's QAPI
diff --git a/src/qemu/qemu_postparse.c b/src/qemu/qemu_postparse.c
index 840d6a1174..c74824322a 100644
--- a/src/qemu/qemu_postparse.c
+++ b/src/qemu/qemu_postparse.c
@@ -1839,6 +1839,7 @@ qemuDomainDefNumaAutoAdd(virDomainDef *def,
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
}
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 10a4a70f1c..8132f13791 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4158,6 +4158,7 @@ qemuProcessDomainMemoryDefNeedHugepagesPath(const virDomainMemoryDef *mem,
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
pagesize = mem->source.virtio_mem.pagesize;
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
@@ -4247,6 +4248,7 @@ qemuProcessNeedMemoryBackingPath(virDomainDef *def,
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
/* Backed by user provided path. Not stored in memory
* backing dir anyway. */
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index c39d8c869f..e03da3e27e 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -5892,6 +5892,12 @@ qemuValidateDomainDeviceDefMemory(const virDomainMemoryDef *mem,
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM:
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("ACPI EGM memory device is not supported with this QEMU binary"));
+ return -1;
+ }
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
--
2.54.0

View File

@ -0,0 +1,526 @@
From 980f098c11773796a35b8e2cb6ae9a1c2296c8b4 Mon Sep 17 00:00:00 2001
Message-ID: <980f098c11773796a35b8e2cb6ae9a1c2296c8b4.1779098642.git.phrdina@redhat.com>
From: Pavel Hrdina <phrdina@redhat.com>
Date: Tue, 25 Nov 2025 11:17:04 -0800
Subject: [PATCH] tests: Add qemuxmlconftest for ACPI EGM memory device
From: Ian May <ianm@nvidia.com>
Add test coverage for the ACPI EGM memory device feature:
- Add test case to qemuxmlconftest.c for aarch64 architecture
- Add acpi-egm-memory capability to QEMU 10.0.0 aarch64 capabilities
- Create test input XML with EGM device configuration
- Generate expected output XML and QEMU command line args
- Update validation to skip filesystem checks during tests
The test validates XML parsing, formatting, device validation, and
QEMU command line generation for the EGM device.
Signed-off-by: Ian May <ianm@nvidia.com>
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
Resolves: https://redhat.atlassian.net/browse/VOYAGER-13
---
src/conf/domain_conf.c | 5 +-
src/conf/domain_postparse.c | 5 +-
src/qemu/qemu_domain.c | 2 +
src/util/virfile.h | 2 +-
tests/meson.build | 1 +
tests/qemuegmmock.c | 67 ++++++++++
.../acpi-egm-memory.aarch64-latest.args | 47 +++++++
.../acpi-egm-memory.aarch64-latest.xml | 124 ++++++++++++++++++
tests/qemuxmlconfdata/acpi-egm-memory.xml | 124 ++++++++++++++++++
tests/qemuxmlconftest.c | 8 +-
10 files changed, 381 insertions(+), 4 deletions(-)
create mode 100644 tests/qemuegmmock.c
create mode 100644 tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args
create mode 100644 tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml
create mode 100644 tests/qemuxmlconfdata/acpi-egm-memory.xml
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 038476edd7..d3236b7425 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -8930,8 +8930,11 @@ virDomainDefGetMemoryInitial(const virDomainDef *def)
size_t i;
unsigned long long ret = def->mem.total_memory;
- for (i = 0; i < def->nmems; i++)
+ for (i = 0; i < def->nmems; i++) {
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM)
+ continue;
ret -= def->mems[i]->size;
+ }
return ret;
}
diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c
index 0181d21f0e..bb4a61b7d8 100644
--- a/src/conf/domain_postparse.c
+++ b/src/conf/domain_postparse.c
@@ -44,8 +44,11 @@ virDomainDefPostParseMemory(virDomainDef *def,
numaMemory = virDomainNumaGetMemorySize(def->numa);
/* calculate the sizes of hotplug memory */
- for (i = 0; i < def->nmems; i++)
+ for (i = 0; i < def->nmems; i++) {
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM)
+ continue;
hotplugMemory += def->mems[i]->size;
+ }
if (numaMemory) {
/* update the sizes in XML if nothing was set in the XML or ABI update
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index c5e3d09360..d1bc9aa621 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -8085,6 +8085,8 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def,
}
for (i = 0; i < def->nmems; i++) {
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM)
+ continue;
hotplugMemory += def->mems[i]->size;
switch (def->mems[i]->model) {
diff --git a/src/util/virfile.h b/src/util/virfile.h
index ce2ffb8ed4..5203ef4425 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -167,7 +167,7 @@ int virFileReadHeaderQuiet(const char *path, int maxlen, char **buf)
int virFileReadLimFD(int fd, int maxlen, char **buf)
G_GNUC_WARN_UNUSED_RESULT ATTRIBUTE_NONNULL(3);
int virFileReadAll(const char *path, int maxlen, char **buf)
- G_GNUC_WARN_UNUSED_RESULT ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
+ G_GNUC_WARN_UNUSED_RESULT ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_MOCKABLE;
int virFileReadAllQuiet(const char *path, int maxlen, char **buf)
G_GNUC_WARN_UNUSED_RESULT ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
int virFileReadBufQuiet(const char *file, char *buf, int len)
diff --git a/tests/meson.build b/tests/meson.build
index bb6ee6b4ee..28ee8591a3 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -174,6 +174,7 @@ if conf.has('WITH_QEMU')
{ 'name': 'qemucaps2xmlmock' },
{ 'name': 'qemucapsprobemock', 'link_with': [ test_qemu_driver_lib ] },
{ 'name': 'qemucpumock' },
+ { 'name': 'qemuegmmock' },
{ 'name': 'qemuhotplugmock', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_lib, test_utils_lib ] },
{ 'name': 'qemuxml2argvmock' },
{ 'name': 'virhostidmock' },
diff --git a/tests/qemuegmmock.c b/tests/qemuegmmock.c
new file mode 100644
index 0000000000..c915212f45
--- /dev/null
+++ b/tests/qemuegmmock.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <config.h>
+#include <unistd.h>
+
+#include "internal.h"
+#include "virfile.h"
+#include "virmock.h"
+
+static bool (*real_virFileExists)(const char *path);
+static int (*real_access)(const char *path, int mode);
+static int (*real_virFileReadAll)(const char *path, int maxlen, char **buf);
+
+static void
+init_syms(void)
+{
+ if (real_virFileExists && real_access && real_virFileReadAll)
+ return;
+
+ VIR_MOCK_REAL_INIT(virFileExists);
+ VIR_MOCK_REAL_INIT(access);
+ VIR_MOCK_REAL_INIT(virFileReadAll);
+}
+
+bool
+virFileExists(const char *path)
+{
+ init_syms();
+
+ /* Mock EGM device paths for testing */
+ if (g_str_has_prefix(path, "/dev/egm") ||
+ g_str_has_prefix(path, "/sys/class/egm/"))
+ return true;
+
+ return real_virFileExists(path);
+}
+
+int
+access(const char *path, int mode)
+{
+ init_syms();
+
+ /* Mock EGM device paths for testing */
+ if (g_str_has_prefix(path, "/dev/egm") ||
+ g_str_has_prefix(path, "/sys/class/egm/"))
+ return 0; /* success */
+
+ return real_access(path, mode);
+}
+
+int
+virFileReadAll(const char *path, int maxlen, char **buf)
+{
+ init_syms();
+
+ /* Mock EGM GPU device file for testing */
+ if (g_str_has_prefix(path, "/sys/class/egm/") &&
+ g_str_has_suffix(path, "/gpu_devices")) {
+ *buf = g_strdup("0000:01:00.0\n");
+ return strlen(*buf);
+ }
+
+ return real_virFileReadAll(path, maxlen, buf);
+}
diff --git a/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args
new file mode 100644
index 0000000000..41d1fcc026
--- /dev/null
+++ b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args
@@ -0,0 +1,47 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/var/lib/libvirt/qemu/domain--1-egm \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-egm/.local/share \
+XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-egm/.cache \
+XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-egm/.config \
+/usr/bin/qemu-system-aarch64 \
+-name guest=egm,debug-threads=on \
+-S \
+-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-egm/master-key.aes"}' \
+-machine virt,usb=off,gic-version=3,dump-guest-core=off,acpi=off \
+-accel kvm \
+-cpu host \
+-m size=524288k,maxmem=524288k \
+-overcommit mem-lock=off \
+-smp 4,sockets=2,dies=1,clusters=1,cores=2,threads=1 \
+-object '{"qom-type":"memory-backend-file","id":"memegm0","mem-path":"/dev/egm4","share":true,"size":268435456}' \
+-object acpi-egm-memory,id=egm0,pci-dev=ua-hostdev0,node=0 \
+-object acpi-egm-memory,id=egm1,pci-dev=ua-hostdev1,node=0 \
+-object '{"qom-type":"memory-backend-file","id":"memegm1","mem-path":"/dev/egm5","share":true,"size":268435456}' \
+-object acpi-egm-memory,id=egm2,pci-dev=ua-hostdev2,node=1 \
+-object acpi-egm-memory,id=egm3,pci-dev=ua-hostdev3,node=1 \
+-numa node,nodeid=0,cpus=0-1,memdev=memegm0 \
+-numa node,nodeid=1,cpus=2-3,memdev=memegm1 \
+-uuid 00010203-0405-4607-8809-0a0b0c0d0e0f \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-boot strict=on \
+-device '{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}' \
+-device '{"driver":"pcie-root-port","port":9,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x1.0x1"}' \
+-device '{"driver":"pcie-root-port","port":10,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x2"}' \
+-device '{"driver":"pcie-root-port","port":11,"chassis":4,"id":"pci.4","bus":"pcie.0","addr":"0x3"}' \
+-device '{"driver":"pcie-root-port","port":12,"chassis":5,"id":"pci.5","bus":"pcie.0","addr":"0x4"}' \
+-audiodev '{"id":"audio1","driver":"none"}' \
+-device '{"driver":"vfio-pci","host":"0000:01:00.0","id":"ua-hostdev0","bus":"pci.1","addr":"0x0"}' \
+-device '{"driver":"vfio-pci","host":"0000:02:00.0","id":"ua-hostdev1","bus":"pci.3","addr":"0x0"}' \
+-device '{"driver":"vfio-pci","host":"0000:03:00.0","id":"ua-hostdev2","bus":"pci.4","addr":"0x0"}' \
+-device '{"driver":"vfio-pci","host":"0000:04:00.0","id":"ua-hostdev3","bus":"pci.5","addr":"0x0"}' \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml
new file mode 100644
index 0000000000..bd73d613e5
--- /dev/null
+++ b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml
@@ -0,0 +1,124 @@
+<domain type='kvm'>
+ <name>egm</name>
+ <uuid>00010203-0405-4607-8809-0a0b0c0d0e0f</uuid>
+ <maxMemory unit='KiB'>524288</maxMemory>
+ <memory unit='KiB'>524288</memory>
+ <currentMemory unit='KiB'>524288</currentMemory>
+ <vcpu placement='static'>4</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <gic version='3'/>
+ </features>
+ <cpu mode='host-passthrough' check='none'>
+ <topology sockets='2' dies='1' clusters='1' cores='2' threads='1'/>
+ <numa>
+ <cell id='0' cpus='0-1' memory='262144' unit='KiB'/>
+ <cell id='1' cpus='2-3' memory='262144' unit='KiB'/>
+ </numa>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-aarch64</emulator>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='1' port='0x8'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='2' port='0x9'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='pci' index='3' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='3' port='0xa'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </controller>
+ <controller type='pci' index='4' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='4' port='0xb'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </controller>
+ <controller type='pci' index='5' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='5' port='0xc'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </controller>
+ <audio id='1' type='none'/>
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </source>
+ <alias name='ua-hostdev0'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </hostdev>
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </source>
+ <alias name='ua-hostdev1'/>
+ <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </hostdev>
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </source>
+ <alias name='ua-hostdev2'/>
+ <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
+ </hostdev>
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
+ </source>
+ <alias name='ua-hostdev3'/>
+ <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
+ </hostdev>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm4</path>
+ </source>
+ <target>
+ <size unit='KiB'>131072</size>
+ <node>0</node>
+ <pciDev>ua-hostdev0</pciDev>
+ </target>
+ </memory>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm4</path>
+ </source>
+ <target>
+ <size unit='KiB'>131072</size>
+ <node>0</node>
+ <pciDev>ua-hostdev1</pciDev>
+ </target>
+ </memory>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm5</path>
+ </source>
+ <target>
+ <size unit='KiB'>131072</size>
+ <node>1</node>
+ <pciDev>ua-hostdev2</pciDev>
+ </target>
+ </memory>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm5</path>
+ </source>
+ <target>
+ <size unit='KiB'>131072</size>
+ <node>1</node>
+ <pciDev>ua-hostdev3</pciDev>
+ </target>
+ </memory>
+ </devices>
+</domain>
diff --git a/tests/qemuxmlconfdata/acpi-egm-memory.xml b/tests/qemuxmlconfdata/acpi-egm-memory.xml
new file mode 100644
index 0000000000..bd73d613e5
--- /dev/null
+++ b/tests/qemuxmlconfdata/acpi-egm-memory.xml
@@ -0,0 +1,124 @@
+<domain type='kvm'>
+ <name>egm</name>
+ <uuid>00010203-0405-4607-8809-0a0b0c0d0e0f</uuid>
+ <maxMemory unit='KiB'>524288</maxMemory>
+ <memory unit='KiB'>524288</memory>
+ <currentMemory unit='KiB'>524288</currentMemory>
+ <vcpu placement='static'>4</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <gic version='3'/>
+ </features>
+ <cpu mode='host-passthrough' check='none'>
+ <topology sockets='2' dies='1' clusters='1' cores='2' threads='1'/>
+ <numa>
+ <cell id='0' cpus='0-1' memory='262144' unit='KiB'/>
+ <cell id='1' cpus='2-3' memory='262144' unit='KiB'/>
+ </numa>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-aarch64</emulator>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='1' port='0x8'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='2' port='0x9'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='pci' index='3' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='3' port='0xa'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </controller>
+ <controller type='pci' index='4' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='4' port='0xb'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </controller>
+ <controller type='pci' index='5' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='5' port='0xc'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </controller>
+ <audio id='1' type='none'/>
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </source>
+ <alias name='ua-hostdev0'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </hostdev>
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </source>
+ <alias name='ua-hostdev1'/>
+ <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </hostdev>
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </source>
+ <alias name='ua-hostdev2'/>
+ <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
+ </hostdev>
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
+ </source>
+ <alias name='ua-hostdev3'/>
+ <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
+ </hostdev>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm4</path>
+ </source>
+ <target>
+ <size unit='KiB'>131072</size>
+ <node>0</node>
+ <pciDev>ua-hostdev0</pciDev>
+ </target>
+ </memory>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm4</path>
+ </source>
+ <target>
+ <size unit='KiB'>131072</size>
+ <node>0</node>
+ <pciDev>ua-hostdev1</pciDev>
+ </target>
+ </memory>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm5</path>
+ </source>
+ <target>
+ <size unit='KiB'>131072</size>
+ <node>1</node>
+ <pciDev>ua-hostdev2</pciDev>
+ </target>
+ </memory>
+ <memory model='egm' access='shared'>
+ <source>
+ <path>/dev/egm5</path>
+ </source>
+ <target>
+ <size unit='KiB'>131072</size>
+ <node>1</node>
+ <pciDev>ua-hostdev3</pciDev>
+ </target>
+ </memory>
+ </devices>
+</domain>
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index 26287e1f8d..4c13dca6d0 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -3275,6 +3275,10 @@ mymain(void)
DO_TEST_CAPS_LATEST("devices-acpi-index");
+ DO_TEST_CAPS_ARCH_LATEST_FULL("acpi-egm-memory", "aarch64",
+ ARG_QEMU_CAPS, QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY,
+ ARG_END);
+
DO_TEST_CAPS_ARCH_LATEST_FULL("hvf-x86_64-q35-headless", "x86_64", ARG_CAPS_VARIANT, "+hvf", ARG_END);
DO_TEST_CAPS_ARCH_LATEST_FULL("hvf-aarch64-virt-headless", "aarch64", ARG_CAPS_VARIANT, "+hvf", ARG_END);
/* HVF guests should not work on Linux with KVM */
@@ -3381,7 +3385,9 @@ VIR_TEST_MAIN_PRELOAD(mymain,
VIR_TEST_MOCK("domaincaps"),
VIR_TEST_MOCK("virrandom"),
VIR_TEST_MOCK("qemucpu"),
- VIR_TEST_MOCK("virnuma"))
+ VIR_TEST_MOCK("virnuma"),
+ VIR_TEST_MOCK("virpci"),
+ VIR_TEST_MOCK("qemuegm"))
#else
--
2.54.0

View File

@ -294,7 +294,7 @@
Summary: Library providing a simple virtualization API
Name: libvirt
Version: 11.10.0
Release: 10.6%{?dist}%{?extra_release}
Release: 10.7%{?dist}%{?extra_release}
License: GPL-2.0-or-later AND LGPL-2.1-only AND LGPL-2.1-or-later AND OFL-1.1
URL: https://libvirt.org/
@ -406,6 +406,10 @@ Patch101: libvirt-qemu-Implement-iommufd-fdgroup.patch
Patch102: libvirt-tests-Add-iommufd-fdgroup-test.patch
Patch103: libvirt-hypervisor-Call-virWaitForDevices-after-detaching-host-devices.patch
Patch104: libvirt-util-Fix-max-socket-calculation.patch
Patch105: libvirt-conf-Support-EGM-memory-device-model.patch
Patch106: libvirt-qemu-Add-cgroup-namespace-and-seclabel-setup-for-EGM-memory-device-model.patch
Patch107: libvirt-qemu-Add-qemu-CLI-support-for-EGM.patch
Patch108: libvirt-tests-Add-qemuxmlconftest-for-ACPI-EGM-memory-device.patch
Requires: libvirt-daemon = %{version}-%{release}
@ -2797,6 +2801,12 @@ exit 0
%endif
%changelog
* Mon May 18 2026 Pavel Hrdina <phrdina@redhat.com> - 11.10.0-10.7
- conf: Support EGM memory device model (VOYAGER-13)
- qemu: Add cgroup, namespace, and seclabel setup for EGM memory device model (VOYAGER-13)
- qemu: Add qemu CLI support for EGM (VOYAGER-13)
- tests: Add qemuxmlconftest for ACPI EGM memory device (VOYAGER-13)
* Sat Mar 28 2026 Pavel Hrdina <phrdina@redhat.com> - 11.10.0-10.6
- util: Fix max socket calculation (VOYAGER-338)