Implement validation logic for ACPI EGM memory device configuration:
- Validate PCI device reference exists and is properly configured
- Check NUMA node assignment is valid
- Verify device paths exist and are accessible
- Ensure proper permissions on device files
Signed-off-by: Ian May <ianm(a)nvidia.com>
---
src/conf/domain_validate.c | 22 +++++++++
src/qemu/qemu_validate.c | 99 ++++++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+)
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 88e61fb878..3cbfe867dc 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -3203,6 +3203,26 @@ virDomainPstoreDefValidate(const virDomainPstoreDef *pstore)
return 0;
}
+static int
+virDomainAcpiEgmDefValidate(const virDomainAcpiEgmDef *egm)
+{
+ if (egm->pciDev == NULL || egm->pciDev[0] == '\0') {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing pciDev for ACPI EGM device"));
+ return -1;
+ }
+
+ if (egm->numaNode < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("NUMA node must be specified for ACPI EGM device"));
+ return -1;
+ }
+
+ VIR_DEBUG("Validating EGM device: alias=%s pciDev=%s numaNode=%d",
+ egm->alias, egm->pciDev, egm->numaNode);
+
+ return 0;
+}
static int
virDomainDeviceInfoValidate(const virDomainDeviceDef *dev)
@@ -3318,6 +3338,8 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
return virDomainPstoreDefValidate(dev->data.pstore);
case VIR_DOMAIN_DEVICE_EGM:
+ return virDomainAcpiEgmDefValidate(dev->data.egm);
+
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_WATCHDOG:
case VIR_DOMAIN_DEVICE_HUB:
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 57dc4171fe..b7cb0c632b 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -4977,6 +4977,102 @@ qemuValidateDomainDeviceDefPstore(virDomainPstoreDef *pstore,
return 0;
}
+static int
+qemuValidateDomainDeviceDefAcpiEgm(virDomainAcpiEgmDef *egm,
+ const virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ g_autofree char *egm_path = NULL;
+ g_autofree char *egm_pci_path = NULL;
+ g_autofree char *expected_pci = NULL;
+ g_autofree char *gpu_devices_content = NULL;
+ virDomainHostdevDef *hostdev = NULL;
+ size_t i;
+
+ 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;
+ }
+
+ /* Find the referenced PCI hostdev */
+ for (i = 0; i < def->nhostdevs; i++) {
+ virDomainHostdevDef *dev = def->hostdevs[i];
+
+ if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+ dev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ continue;
+
+ if (dev->info && dev->info->alias &&
STREQ(dev->info->alias, egm->pciDev)) {
+ hostdev = dev;
+ break;
+ }
+ }
+
+ if (!hostdev) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Cannot find PCI device '%1$s' referenced by EGM
device"),
+ egm->pciDev);
+ return -1;
+ }
+
+ /* Validate NUMA node if configured */
+ if (egm->numaNode > virDomainNumaGetNodeCount(def->numa)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("NUMA node %1$d for EGM device does not exist"),
+ egm->numaNode);
+ return -1;
+ }
+
+ /* Validate EGM device path exists and is accessible */
+ egm_path = g_strdup_printf("/dev/%s", egm->alias);
+ if (!virFileExists(egm_path)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("EGM device path '%1$s' does not exist"),
+ egm_path);
+ return -1;
+ }
+
+ /* Check if we have proper permissions */
+ if (access(egm_path, R_OK | W_OK) < 0) {
+ virReportSystemError(errno,
+ _("Cannot access EGM device '%1$s'"),
+ egm_path);
+ return -1;
+ }
+
+ /* Validate EGM pci device path */
+ egm_pci_path = g_strdup_printf("/sys/class/egm/%s/gpu_devices",
egm->alias);
+ if (!virFileExists(egm_pci_path)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Cannot find GPU device information for EGM device
'%1$s'"),
+ egm->alias);
+ return -1;
+ }
+
+ /* Read and validate PCI address from gpu_devices file */
+ expected_pci = g_strdup_printf("%04x:%02x:%02x.%x",
+ hostdev->source.subsys.u.pci.addr.domain,
+ hostdev->source.subsys.u.pci.addr.bus,
+ hostdev->source.subsys.u.pci.addr.slot,
+ hostdev->source.subsys.u.pci.addr.function);
+
+ if (virFileReadAll(egm_pci_path, 1024, &gpu_devices_content) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Cannot read GPU device information for EGM device
'%1$s'"),
+ egm->alias);
+ return -1;
+ }
+
+ if (!strstr(gpu_devices_content, expected_pci)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("PCI device '%2$s' is not associated with EGM
device '%1$s'"),
+ egm->alias, expected_pci);
+ return -1;
+ }
+
+ return 0;
+}
static int
qemuSoundCodecTypeToCaps(int type)
@@ -5748,6 +5844,9 @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev,
case VIR_DOMAIN_DEVICE_PSTORE:
return qemuValidateDomainDeviceDefPstore(dev->data.pstore, def, qemuCaps);
+ case VIR_DOMAIN_DEVICE_EGM:
+ return qemuValidateDomainDeviceDefAcpiEgm(dev->data.egm, def, qemuCaps);
+
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_PANIC:
case VIR_DOMAIN_DEVICE_NONE:
--
2.43.0