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 <i...@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