:p
atchew
Login
This is a rebased version of: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/VWR67LTU4Z5TQHDWVTPEVOGIS53FTJYK/ which doesn't apply cleanly anymore due to recent changes to qemu_capabilities.c. Michal Prívozník (5): qemu_capabilities: Introduce QEMU_CAPS_DEVICE_ACPI_ERST conf: Introduce pstore device qemu: Build cmd line for pstore device security: Set seclabels for pstore device NEWS: Document pstore device addition NEWS.rst | 7 + docs/formatdomain.rst | 32 ++++ src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 153 ++++++++++++++++++ src/conf/domain_conf.h | 19 +++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 30 ++++ src/conf/schemas/domaincommon.rng | 25 +++ src/conf/virconftypes.h | 2 + src/hyperv/hyperv_driver.c | 1 + src/libvirt_private.syms | 2 + src/libxl/libxl_driver.c | 6 + src/lxc/lxc_driver.c | 6 + src/qemu/qemu_alias.c | 10 ++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 52 ++++++ src/qemu/qemu_domain.c | 3 + src/qemu/qemu_domain_address.c | 11 ++ src/qemu/qemu_driver.c | 3 + src/qemu/qemu_hotplug.c | 5 + src/qemu/qemu_validate.c | 26 +++ src/security/security_dac.c | 10 ++ src/security/security_selinux.c | 9 ++ src/security/virt-aa-helper.c | 4 + .../caps_7.0.0_aarch64+hvf.xml | 1 + .../caps_7.0.0_aarch64.xml | 1 + .../qemucapabilitiesdata/caps_7.0.0_ppc64.xml | 1 + .../caps_7.0.0_x86_64.xml | 1 + .../qemucapabilitiesdata/caps_7.1.0_ppc64.xml | 1 + .../caps_7.1.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml | 1 + .../caps_7.2.0_x86_64+hvf.xml | 1 + .../caps_7.2.0_x86_64.xml | 1 + .../caps_8.0.0_x86_64.xml | 1 + .../caps_8.1.0_x86_64.xml | 1 + .../caps_8.2.0_aarch64.xml | 1 + .../caps_8.2.0_armv7l.xml | 1 + .../caps_8.2.0_loongarch64.xml | 1 + .../caps_8.2.0_x86_64.xml | 1 + .../caps_9.0.0_x86_64.xml | 1 + .../caps_9.1.0_x86_64.xml | 1 + .../pstore-acpi-erst.x86_64-latest.args | 38 +++++ .../pstore-acpi-erst.x86_64-latest.xml | 1 + tests/qemuxmlconfdata/pstore-acpi-erst.xml | 53 ++++++ tests/qemuxmlconftest.c | 1 + 46 files changed, 531 insertions(+) create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args create mode 120000 tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.xml -- 2.44.2
This capability tracks whether QEMU has acpi-erst device. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml | 1 + tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml | 1 + tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml | 1 + tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml | 1 + tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml | 1 + tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml | 1 + 19 files changed, 20 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virQEMUCaps, /* 460 */ "sev-snp-guest", /* QEMU_CAPS_SEV_SNP_GUEST */ "netdev.user", /* QEMU_CAPS_NETDEV_USER */ + "acpi-erst", /* QEMU_CAPS_DEVICE_ACPI_ERST */ ); @@ -XXX,XX +XXX,XX @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "virtio-sound-pci", QEMU_CAPS_DEVICE_VIRTIO_SOUND }, { "virtio-sound-device", QEMU_CAPS_DEVICE_VIRTIO_SOUND }, { "sev-snp-guest", QEMU_CAPS_SEV_SNP_GUEST }, + { "acpi-erst", QEMU_CAPS_DEVICE_ACPI_ERST }, }; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -XXX,XX +XXX,XX @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 460 */ QEMU_CAPS_SEV_SNP_GUEST, /* -object sev-snp-guest */ QEMU_CAPS_NETDEV_USER, /* -netdev user */ + QEMU_CAPS_DEVICE_ACPI_ERST, /* -device acpi-erst */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml b/tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='machine.virt.ras'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>6002092</version> <microcodeVersion>61700243</microcodeVersion> <package>v7.0.0-rc2</package> diff --git a/tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml b/tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='machine.virt.ras'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>6002092</version> <microcodeVersion>61700243</microcodeVersion> <package>v7.0.0-rc2</package> diff --git a/tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml b/tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7000000</version> <microcodeVersion>42900243</microcodeVersion> <package>v7.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7000000</version> <microcodeVersion>43100243</microcodeVersion> <package>v7.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml b/tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7001000</version> <microcodeVersion>42900244</microcodeVersion> <package>v7.1.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7001000</version> <microcodeVersion>43100244</microcodeVersion> <package>v7.1.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml b/tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml +++ b/tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7002000</version> <microcodeVersion>0</microcodeVersion> <package>qemu-7.2.0-6.fc37</package> diff --git a/tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml b/tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml +++ b/tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7002000</version> <microcodeVersion>43100245</microcodeVersion> <package>v7.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7002000</version> <microcodeVersion>43100245</microcodeVersion> <package>v7.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8000000</version> <microcodeVersion>43100244</microcodeVersion> <package>v8.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8001000</version> <microcodeVersion>43100245</microcodeVersion> <package>v8.1.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml b/tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml @@ -XXX,XX +XXX,XX @@ <flag name='machine.virt.ras'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8002000</version> <microcodeVersion>61700246</microcodeVersion> <package>v8.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml b/tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml @@ -XXX,XX +XXX,XX @@ <flag name='machine.virt.ras'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8002000</version> <microcodeVersion>0</microcodeVersion> <package>qemu-8.2.0-7.fc39</package> diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml b/tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8002000</version> <microcodeVersion>106300246</microcodeVersion> <package>v8.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8002000</version> <microcodeVersion>43100246</microcodeVersion> <package>v8.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>9000000</version> <microcodeVersion>43100245</microcodeVersion> <package>v9.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>9000050</version> <microcodeVersion>43100246</microcodeVersion> <package>v9.0.0-1388-g80e8f06021-dirty</package> -- 2.44.2
The aim of pstore device is to provide a bit of NVRAM storage for guest kernel to record oops/panic logs just before the it crashes. Typical usage includes usage in combination with a watchdog so that the logs can be inspected after the watchdog rebooted the machine. While Linux kernel (and possibly Windows too) support many backends, in QEMU there's just 'acpi-erst' device so stick with that for now. The device must be attached to a PCI bus and needs two additional values (well, corresponding memory-backend-file needs them): size and path. Despite using memory-backeng-file this does NOT add any additional RAM to the guest and thus I've decided to expose it as another device type instead of memory model. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.rst | 32 ++++ src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 153 ++++++++++++++++++ src/conf/domain_conf.h | 19 +++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 30 ++++ src/conf/schemas/domaincommon.rng | 25 +++ src/conf/virconftypes.h | 2 + src/hyperv/hyperv_driver.c | 1 + src/libvirt_private.syms | 2 + src/libxl/libxl_driver.c | 6 + src/lxc/lxc_driver.c | 6 + src/qemu/qemu_command.c | 1 + src/qemu/qemu_domain.c | 3 + src/qemu/qemu_domain_address.c | 11 ++ src/qemu/qemu_driver.c | 3 + src/qemu/qemu_hotplug.c | 5 + src/qemu/qemu_validate.c | 26 +++ .../pstore-acpi-erst.x86_64-latest.args | 36 +++++ .../pstore-acpi-erst.x86_64-latest.xml | 1 + tests/qemuxmlconfdata/pstore-acpi-erst.xml | 53 ++++++ tests/qemuxmlconftest.c | 1 + 22 files changed, 418 insertions(+) create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args create mode 120000 tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.xml diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -XXX,XX +XXX,XX @@ The optional attribute ``backend`` is required if the ``type`` is ``qemu``, the ... +Pstore +~~~~~~~~~ + +Pstore is an oops/panic logger that writes its logs to a block device and +non-block device before the system crashes. Currently only ACPI Error Record +Serialization Table, ERST, is supported. This feature is designed for storing +error records in persistent storage for future reference and/or debugging. +:since:`Since v10.5.0` + +:: + + ... + <pstore backend='acpi-erst'> + <path>/tmp/guest_acpi_esrt</path> + <size unit='KiB'>8</size> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </pstore> + ... + +The ``pstore`` element has one mandatory attribute ``backend`` which selects +desired backend (only ``acpi-erst`` is accepted for now). Then it has the +following child elements: + +``path`` + Represents a path in the host that backs the pstore device in the guest. It + is mandatory. + +``size`` + Configures the size of the persistent storage available to the guest. It is + mandatory. + + Security label -------------- diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index XXXXXXX..XXXXXXX 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -XXX,XX +XXX,XX @@ chValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Cloud-Hypervisor doesn't support '%1$s' device"), virDomainDeviceTypeToString(dev->type)); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virDomainDevice, "vsock", "audio", "crypto", + "pstore", ); VIR_ENUM_IMPL(virDomainDiskDevice, @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virDomainLaunchSecurity, "s390-pv", ); +VIR_ENUM_IMPL(virDomainPstoreBackend, + VIR_DOMAIN_PSTORE_BACKEND_LAST, + "acpi-erst", +); + typedef enum { VIR_DOMAIN_NET_VHOSTUSER_MODE_NONE, VIR_DOMAIN_NET_VHOSTUSER_MODE_CLIENT, @@ -XXX,XX +XXX,XX @@ void virDomainMemoryDefFree(virDomainMemoryDef *def) g_free(def); } +void virDomainPstoreDefFree(virDomainPstoreDef *def) +{ + if (!def) + return; + + g_free(def->path); + virDomainDeviceInfoClear(&def->info); + g_free(def); +} + void virDomainDeviceDefFree(virDomainDeviceDef *def) { if (!def) @@ -XXX,XX +XXX,XX @@ void virDomainDeviceDefFree(virDomainDeviceDef *def) case VIR_DOMAIN_DEVICE_CRYPTO: virDomainCryptoDefFree(def->data.crypto); break; + case VIR_DOMAIN_DEVICE_PSTORE: + virDomainPstoreDefFree(def->data.pstore); + break; case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: break; @@ -XXX,XX +XXX,XX @@ void virDomainDefFree(virDomainDef *def) virDomainIOMMUDefFree(def->iommu); + virDomainPstoreDefFree(def->pstore); + g_free(def->idmap.uidmap); g_free(def->idmap.gidmap); @@ -XXX,XX +XXX,XX @@ virDomainDeviceGetInfo(const virDomainDeviceDef *device) return &device->data.vsock->info; case VIR_DOMAIN_DEVICE_CRYPTO: return &device->data.crypto->info; + case VIR_DOMAIN_DEVICE_PSTORE: + return &device->data.pstore->info; /* The following devices do not contain virDomainDeviceInfo */ case VIR_DOMAIN_DEVICE_LEASE: @@ -XXX,XX +XXX,XX @@ virDomainDeviceSetData(virDomainDeviceDef *device, case VIR_DOMAIN_DEVICE_CRYPTO: device->data.crypto = devicedata; break; + case VIR_DOMAIN_DEVICE_PSTORE: + device->data.pstore = devicedata; + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; @@ -XXX,XX +XXX,XX @@ virDomainDeviceInfoIterateFlags(virDomainDef *def, return rc; } + device.type = VIR_DOMAIN_DEVICE_PSTORE; + if (def->pstore) { + device.data.pstore = def->pstore; + if ((rc = cb(def, &device, &def->pstore->info, opaque)) != 0) + return rc; + } + /* If the flag below is set, make sure @cb can handle @info being NULL */ if (iteratorFlags & DOMAIN_DEVICE_ITERATE_MISSING_INFO) { device.type = VIR_DOMAIN_DEVICE_GRAPHICS; @@ -XXX,XX +XXX,XX @@ virDomainDeviceInfoIterateFlags(virDomainDef *def, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; } #endif @@ -XXX,XX +XXX,XX @@ virDomainCryptoDefParseXML(virDomainXMLOption *xmlopt, } +static virDomainPstoreDef * +virDomainPstoreDefParseXML(virDomainXMLOption *xmlopt, + xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + g_autoptr(virDomainPstoreDef) def = NULL; + VIR_XPATH_NODE_AUTORESTORE(ctxt) + + def = g_new0(virDomainPstoreDef, 1); + + ctxt->node = node; + + if (virXMLPropEnum(node, "backend", + virDomainPstoreBackendTypeFromString, + VIR_XML_PROP_REQUIRED, + &def->backend) < 0) { + return NULL; + } + + def->path = virXPathString("string(./path)", ctxt); + + if (virDomainParseMemory("./size", "./size/@unit", ctxt, + &def->size, true, false) < 0) { + return NULL; + } + + if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0) + return NULL; + + return g_steal_pointer(&def); +} + + static int virDomainDeviceDefParseType(const char *typestr, virDomainDeviceType *type) @@ -XXX,XX +XXX,XX @@ virDomainDeviceDefParse(const char *xmlStr, flags))) return NULL; break; + case VIR_DOMAIN_DEVICE_PSTORE: + if (!(dev->data.pstore = virDomainPstoreDefParseXML(xmlopt, node, + ctxt, flags))) { + return NULL; + } + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; @@ -XXX,XX +XXX,XX @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, } VIR_FREE(nodes); + if ((n = virXPathNodeSet("./devices/pstore", ctxt, &nodes)) < 0) + return NULL; + + if (n > 1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("only a single pstore device is supported")); + return NULL; + } + + if (n > 0) { + if (!(def->pstore = virDomainPstoreDefParseXML(xmlopt, nodes[0], + ctxt, flags))) + return NULL; + } + VIR_FREE(nodes); + /* analysis of the user namespace mapping */ if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0) return NULL; @@ -XXX,XX +XXX,XX @@ virDomainVsockDefCheckABIStability(virDomainVsockDef *src, } +static bool +virDomainPstoreDefCheckABIStability(virDomainPstoreDef *src, + virDomainPstoreDef *dst) +{ + if (src->backend != dst->backend) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target pstore device backend '%1$s' does not match source '%2$s'"), + virDomainPstoreBackendTypeToString(dst->backend), + virDomainPstoreBackendTypeToString(src->backend)); + return false; + } + + if (src->size != dst->size) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target pstore size '%1$llu' does not match source '%2$llu'"), + dst->size, + src->size); + return false; + } + + if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info)) + return false; + + return true; +} + + static bool virDomainDefVcpuCheckAbiStability(virDomainDef *src, virDomainDef *dst) @@ -XXX,XX +XXX,XX @@ virDomainDefCheckABIStabilityFlags(virDomainDef *src, !virDomainVsockDefCheckABIStability(src->vsock, dst->vsock)) goto error; + if (!!src->pstore != !!dst->pstore) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Target domain pstore device count does not match source")); + goto error; + } + + if (src->pstore && + !virDomainPstoreDefCheckABIStability(src->pstore, dst->pstore)) { + goto error; + } + if (xmlopt && xmlopt->abi.domain && !xmlopt->abi.domain(src, dst)) goto error; @@ -XXX,XX +XXX,XX @@ virDomainDefCheckABIStabilityFlags(virDomainDef *src, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; } #endif @@ -XXX,XX +XXX,XX @@ virDomainDefFormatFeatures(virBuffer *buf, return 0; } +static int +virDomainPstoreDefFormat(virBuffer *buf, + virDomainPstoreDef *pstore, + unsigned int flags) +{ + g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + + virBufferAsprintf(&attrBuf, " backend='%s'", + virDomainPstoreBackendTypeToString(pstore->backend)); + + virBufferAsprintf(&childBuf, "<path>%s</path>\n", pstore->path); + virBufferAsprintf(&childBuf, "<size unit='KiB'>%llu</size>\n", pstore->size); + virDomainDeviceInfoFormat(&childBuf, &pstore->info, flags); + + virXMLFormatElement(buf, "pstore", &attrBuf, &childBuf); + return 0; +} + + int virDomainDefFormatInternal(virDomainDef *def, virDomainXMLOption *xmlopt, @@ -XXX,XX +XXX,XX @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, if (def->vsock) virDomainVsockDefFormat(buf, def->vsock); + if (def->pstore) + virDomainPstoreDefFormat(buf, def->pstore, flags); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</devices>\n"); @@ -XXX,XX +XXX,XX @@ virDomainDeviceIsUSB(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -XXX,XX +XXX,XX @@ typedef enum { VIR_DOMAIN_DEVICE_VSOCK, VIR_DOMAIN_DEVICE_AUDIO, VIR_DOMAIN_DEVICE_CRYPTO, + VIR_DOMAIN_DEVICE_PSTORE, VIR_DOMAIN_DEVICE_LAST } virDomainDeviceType; @@ -XXX,XX +XXX,XX @@ struct _virDomainDeviceDef { virDomainVsockDef *vsock; virDomainAudioDef *audio; virDomainCryptoDef *crypto; + virDomainPstoreDef *pstore; } data; }; @@ -XXX,XX +XXX,XX @@ struct _virDomainVirtioOptions { virTristateSwitch page_per_vq; }; +typedef enum { + VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST, + + VIR_DOMAIN_PSTORE_BACKEND_LAST +} virDomainPstoreBackend; + +struct _virDomainPstoreDef { + virDomainPstoreBackend backend; + unsigned long long size; + char *path; + virDomainDeviceInfo info; +}; + #define SCSI_SUPER_WIDE_BUS_MAX_CONT_UNIT 64 #define SCSI_WIDE_BUS_MAX_CONT_UNIT 16 @@ -XXX,XX +XXX,XX @@ struct _virDomainDef { virDomainRedirFilterDef *redirfilter; virDomainIOMMUDef *iommu; virDomainVsockDef *vsock; + virDomainPstoreDef *pstore; void *namespaceData; virXMLNamespace ns; @@ -XXX,XX +XXX,XX @@ void virDomainVsockDefFree(virDomainVsockDef *vsock); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainVsockDef, virDomainVsockDefFree); void virDomainCryptoDefFree(virDomainCryptoDef *def); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainCryptoDef, virDomainCryptoDefFree); +void virDomainPstoreDefFree(virDomainPstoreDef *def); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainPstoreDef, virDomainPstoreDefFree); void virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetTeamingInfo, virDomainNetTeamingInfoFree); void virDomainNetPortForwardFree(virDomainNetPortForward *pf); @@ -XXX,XX +XXX,XX @@ VIR_ENUM_DECL(virDomainCryptoBackend); VIR_ENUM_DECL(virDomainShmemModel); VIR_ENUM_DECL(virDomainShmemRole); VIR_ENUM_DECL(virDomainLaunchSecurity); +VIR_ENUM_DECL(virDomainPstoreBackend); /* from libvirt.h */ VIR_ENUM_DECL(virDomainState); VIR_ENUM_DECL(virDomainNostateReason); diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/domain_postparse.c +++ b/src/conf/domain_postparse.c @@ -XXX,XX +XXX,XX @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: ret = 0; break; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -XXX,XX +XXX,XX @@ virDomainTPMDevValidate(const virDomainTPMDef *tpm) } +static int +virDomainPstoreDefValidate(const virDomainPstoreDef *pstore) +{ + if (pstore->backend != VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unsupported backend for pstore device: %1$s"), + virDomainPstoreBackendTypeToString(pstore->backend)); + return -1; + } + + if (pstore->path == NULL || pstore->path[0] == '\0') { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing path for ACPI ERST pstore device")); + return -1; + } + + if (pstore->size < 4 || + !VIR_IS_POW2(pstore->size)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("invalid size of ACPI ERST pstore device")); + return -1; + } + + return 0; +} + + static int virDomainDeviceInfoValidate(const virDomainDeviceDef *dev) { @@ -XXX,XX +XXX,XX @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_TPM: return virDomainTPMDevValidate(dev->data.tpm); + case VIR_DOMAIN_DEVICE_PSTORE: + return virDomainPstoreDefValidate(dev->data.pstore); + case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_WATCHDOG: case VIR_DOMAIN_DEVICE_HUB: diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index XXXXXXX..XXXXXXX 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -XXX,XX +XXX,XX @@ </element> </define> + <define name="pstore"> + <element name="pstore"> + <attribute name="backend"> + <value>acpi-erst</value> + </attribute> + <interleave> + <element name="path"> + <ref name="absFilePath"/> + </element> + <element name="size"> + <ref name="scaledInteger"/> + </element> + <optional> + <ref name="address"/> + </optional> + <optional> + <ref name="alias"/> + </optional> + </interleave> + </element> + </define> + <define name="hostdev"> <element name="hostdev"> <interleave> @@ -XXX,XX +XXX,XX @@ <optional> <ref name="vsock"/> </optional> + <optional> + <ref name="pstore"/> + </optional> </interleave> </element> </define> diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -XXX,XX +XXX,XX @@ typedef struct _virDomainVsockDef virDomainVsockDef; typedef struct _virDomainCryptoDef virDomainCryptoDef; +typedef struct _virDomainPstoreDef virDomainPstoreDef; + typedef struct _virDomainWatchdogDef virDomainWatchdogDef; typedef struct _virDomainXMLOption virDomainXMLOption; diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -XXX,XX +XXX,XX @@ hypervDomainAttachDeviceFlags(virDomainPtr domain, const char *xml, unsigned int case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_INTERNAL_ERROR, _("Attaching devices of type %1$d is not implemented"), dev->type); return -1; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -XXX,XX +XXX,XX @@ virDomainPausedReasonTypeToString; virDomainPMSuspendedReasonTypeFromString; virDomainPMSuspendedReasonTypeToString; virDomainProcessCapsFeatureTypeToString; +virDomainPstoreBackendTypeFromString; +virDomainPstoreBackendTypeToString; virDomainRedirdevBusTypeFromString; virDomainRedirdevBusTypeToString; virDomainRedirdevDefFind; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -XXX,XX +XXX,XX @@ libxlDomainAttachDeviceLive(libxlDriverPrivate *driver, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be attached"), virDomainDeviceTypeToString(dev->type)); @@ -XXX,XX +XXX,XX @@ libxlDomainAttachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent attach of device is not supported")); return -1; @@ -XXX,XX +XXX,XX @@ libxlDomainDetachDeviceLive(libxlDriverPrivate *driver, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be detached"), virDomainDeviceTypeToString(dev->type)); @@ -XXX,XX +XXX,XX @@ libxlDomainDetachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent detach of device is not supported")); return -1; @@ -XXX,XX +XXX,XX @@ libxlDomainUpdateDeviceLive(virDomainObj *vm, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be updated"), virDomainDeviceTypeToString(dev->type)); @@ -XXX,XX +XXX,XX @@ libxlDomainUpdateDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent update of device is not supported")); return -1; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -XXX,XX +XXX,XX @@ lxcDomainAttachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent attach of device is not supported")); break; @@ -XXX,XX +XXX,XX @@ lxcDomainUpdateDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent update of device is not supported")); break; @@ -XXX,XX +XXX,XX @@ lxcDomainDetachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_AUDIO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent detach of device is not supported")); break; @@ -XXX,XX +XXX,XX @@ lxcDomainAttachDeviceMknodHelper(pid_t pid G_GNUC_UNUSED, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected device type %1$d"), data->def->type); @@ -XXX,XX +XXX,XX @@ lxcDomainAttachDeviceLive(virLXCDriver *driver, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be attached"), virDomainDeviceTypeToString(dev->type)); @@ -XXX,XX +XXX,XX @@ lxcDomainDetachDeviceLive(virLXCDriver *driver, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be detached"), virDomainDeviceTypeToString(dev->type)); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -XXX,XX +XXX,XX @@ qemuBuildVirtioDevGetConfigDev(const virDomainDeviceDef *device, case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: default: break; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -XXX,XX +XXX,XX @@ qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: ret = 0; break; @@ -XXX,XX +XXX,XX @@ qemuDomainPrepareChardevSourceOne(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; } @@ -XXX,XX +XXX,XX @@ qemuDomainDeviceBackendChardevForeachOne(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: /* no chardev backend */ break; } diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -XXX,XX +XXX,XX @@ qemuDomainDeviceSupportZPCI(virDomainDeviceDef *device) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; case VIR_DOMAIN_DEVICE_NONE: @@ -XXX,XX +XXX,XX @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev, } break; + case VIR_DOMAIN_DEVICE_PSTORE: + return pciFlags; + /* These devices don't ever connect with PCI */ case VIR_DOMAIN_DEVICE_NVRAM: case VIR_DOMAIN_DEVICE_TPM: @@ -XXX,XX +XXX,XX @@ qemuDomainAssignDevicePCISlots(virDomainDef *def, } } + if (def->pstore && + virDeviceInfoPCIAddressIsWanted(&def->pstore->info)) { + if (qemuDomainPCIAddressReserveNextAddr(addrs, + &def->pstore->info) < 0) + return -1; + } + return 0; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -XXX,XX +XXX,XX @@ qemuDomainAttachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent attach of device '%1$s' is not supported"), @@ -XXX,XX +XXX,XX @@ qemuDomainDetachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent detach of device '%1$s' is not supported"), @@ -XXX,XX +XXX,XX @@ qemuDomainUpdateDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent update of device '%1$s' is not supported"), diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -XXX,XX +XXX,XX @@ qemuDomainAttachDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live attach of device '%1$s' is not supported"), @@ -XXX,XX +XXX,XX @@ qemuDomainRemoveAuditDevice(virDomainObj *vm, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: /* libvirt doesn't yet support detaching these devices */ break; @@ -XXX,XX +XXX,XX @@ qemuDomainRemoveDevice(virQEMUDriver *driver, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("don't know how to remove a %1$s device"), @@ -XXX,XX +XXX,XX @@ qemuDomainDetachDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live detach of device '%1$s' is not supported"), @@ -XXX,XX +XXX,XX @@ qemuDomainUpdateDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("live update of device '%1$s' is not supported"), diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -XXX,XX +XXX,XX @@ qemuValidateDomainDeviceDefCrypto(virDomainCryptoDef *crypto, } +static int +qemuValidateDomainDeviceDefPstore(virDomainPstoreDef *pstore, + const virDomainDef *def G_GNUC_UNUSED, + virQEMUCaps *qemuCaps) +{ + if (pstore->backend == VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ACPI_ERST)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("acpi-erst backend of pstore device is not supported")); + return -1; + } + + if (pstore->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + pstore->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("ACPI ERST device must reside on a PCI bus")); + return -1; + } + + return 0; +} + + static int qemuSoundCodecTypeToCaps(int type) { @@ -XXX,XX +XXX,XX @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_CRYPTO: return qemuValidateDomainDeviceDefCrypto(dev->data.crypto, def, qemuCaps); + case VIR_DOMAIN_DEVICE_PSTORE: + return qemuValidateDomainDeviceDefPstore(dev->data.pstore, def, qemuCaps); + case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_NONE: diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args @@ -XXX,XX +XXX,XX @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-guest \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-guest/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-guest/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-guest/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=guest,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-guest/master-key.aes"}' \ +-machine pc-q35-9.0,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=on \ +-accel kvm \ +-cpu qemu64 \ +-m size=1048576k \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":1073741824}' \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 63840878-0deb-4095-97e6-fc444d9bc9fa \ +-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-pci-bridge","id":"pci.2","bus":"pci.1","addr":"0x0"}' \ +-device '{"driver":"pcie-root-port","port":9,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x1.0x1"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-global ICH9-LPC.noreboot=off \ +-watchdog-action reset \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml @@ -0,0 +1 @@ +pstore-acpi-erst.xml \ No newline at end of file diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.xml b/tests/qemuxmlconfdata/pstore-acpi-erst.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.xml @@ -XXX,XX +XXX,XX @@ +<domain type='kvm'> + <name>guest</name> + <uuid>63840878-0deb-4095-97e6-fc444d9bc9fa</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>1048576</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc-q35-9.0'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </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-x86_64</emulator> + <controller type='usb' index='0' model='none'/> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <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-to-pci-bridge'> + <model name='pcie-pci-bridge'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <watchdog model='itco' action='reset'/> + <memballoon model='none'/> + <pstore backend='acpi-erst'> + <path>/tmp/guest_acpi_esrt</path> + <size unit='KiB'>8</size> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </pstore> + </devices> +</domain> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST_CAPS_LATEST("mtp-usb-device") DO_TEST_CAPS_LATEST("net-usb") DO_TEST_CAPS_LATEST("sound-device-virtio") + DO_TEST_CAPS_LATEST("pstore-acpi-erst") DO_TEST_CAPS_LATEST_FAILURE("disk-network-iscsi-zero-hosts-invalid") -- 2.44.2
Nothing special going on here. Resolves: https://issues.redhat.com/browse/RHEL-24746 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_alias.c | 10 ++++ src/qemu/qemu_command.c | 51 +++++++++++++++++++ .../pstore-acpi-erst.x86_64-latest.args | 2 + 3 files changed, 63 insertions(+) diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -XXX,XX +XXX,XX @@ qemuAssignDeviceCryptoAlias(virDomainDef *def, } +static void +qemuAssignDevicePstoreAlias(virDomainPstoreDef *pstore) +{ + if (!pstore->info.alias) + pstore->info.alias = g_strdup("pstore0"); +} + + int qemuAssignDeviceAliases(virDomainDef *def) { @@ -XXX,XX +XXX,XX @@ qemuAssignDeviceAliases(virDomainDef *def) for (i = 0; i < def->ncryptos; i++) { qemuAssignDeviceCryptoAlias(def, def->cryptos[i]); } + if (def->pstore) + qemuAssignDevicePstoreAlias(def->pstore); return 0; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -XXX,XX +XXX,XX @@ qemuBuildCryptoCommandLine(virCommand *cmd, } +static int +qemuBuildPstoreCommandLine(virCommand *cmd, + const virDomainDef *def, + virDomainPstoreDef *pstore, + virQEMUCaps *qemuCaps) +{ + g_autoptr(virJSONValue) devProps = NULL; + g_autoptr(virJSONValue) memProps = NULL; + g_autofree char *memAlias = NULL; + + if (!pstore->info.alias) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("pstore device is missing alias")); + return -1; + } + + memAlias = g_strdup_printf("mem%s", pstore->info.alias); + + if (qemuMonitorCreateObjectProps(&memProps, + "memory-backend-file", + memAlias, + "s:mem-path", pstore->path, + "U:size", pstore->size * 1024, + "b:share", true, + NULL) < 0) { + return -1; + } + + if (virJSONValueObjectAdd(&devProps, + "s:driver", "acpi-erst", + "s:id", pstore->info.alias, + "s:memdev", memAlias, + NULL) < 0) { + return -1; + } + + if (qemuBuildDeviceAddressProps(devProps, def, &pstore->info) < 0) + return -1; + + if (qemuBuildObjectCommandlineFromJSON(cmd, memProps, qemuCaps) < 0 || + qemuBuildDeviceCommandlineFromJSON(cmd, devProps, def, qemuCaps) < 0) + return -1; + + return 0; +} + + static int qemuBuildAsyncTeardownCommandLine(virCommand *cmd, const virDomainDef *def, @@ -XXX,XX +XXX,XX @@ qemuBuildCommandLine(virDomainObj *vm, if (qemuBuildCryptoCommandLine(cmd, def, qemuCaps) < 0) return NULL; + if (def->pstore && + qemuBuildPstoreCommandLine(cmd, def, def->pstore, qemuCaps) < 0) + return NULL; + if (qemuBuildAsyncTeardownCommandLine(cmd, def, qemuCaps) < 0) return NULL; diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args index XXXXXXX..XXXXXXX 100644 --- a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args @@ -XXX,XX +XXX,XX @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-guest/.config \ -global ICH9-LPC.noreboot=off \ -watchdog-action reset \ -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-object '{"qom-type":"memory-backend-file","id":"mempstore0","mem-path":"/tmp/guest_acpi_esrt","size":8192,"share":true}' \ +-device '{"driver":"acpi-erst","id":"pstore0","memdev":"mempstore0","bus":"pci.2","addr":"0x1"}' \ -msg timestamp=on -- 2.44.2
The acpi-erst backend for pstore device exposes a path in the host accessible to the guest and as such we must set seclabels on it to grant QEMU RW access. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/security/security_dac.c | 10 ++++++++++ src/security/security_selinux.c | 9 +++++++++ src/security/virt-aa-helper.c | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/src/security/security_dac.c b/src/security/security_dac.c index XXXXXXX..XXXXXXX 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -XXX,XX +XXX,XX @@ virSecurityDACRestoreAllLabel(virSecurityManager *mgr, virSecurityDACRestoreFileLabel(mgr, def->os.slic_table) < 0) rc = -1; + if (def->pstore && + virSecurityDACRestoreFileLabel(mgr, def->pstore->path) < 0) + rc = -1; + return rc; } @@ -XXX,XX +XXX,XX @@ virSecurityDACSetAllLabel(virSecurityManager *mgr, user, group, true) < 0) return -1; + if (def->pstore && + virSecurityDACSetOwnership(mgr, NULL, + def->pstore->path, + user, group, true) < 0) + return -1; + return 0; } diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index XXXXXXX..XXXXXXX 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -XXX,XX +XXX,XX @@ virSecuritySELinuxRestoreAllLabel(virSecurityManager *mgr, virSecuritySELinuxRestoreFileLabel(mgr, def->os.slic_table, true) < 0) rc = -1; + if (def->pstore && + virSecuritySELinuxRestoreFileLabel(mgr, def->pstore->path, true) < 0) + rc = -1; + return rc; } @@ -XXX,XX +XXX,XX @@ virSecuritySELinuxSetAllLabel(virSecurityManager *mgr, data->content_context, true) < 0) return -1; + if (def->pstore && + virSecuritySELinuxSetFilecon(mgr, def->pstore->path, + data->content_context, true) < 0) + return -1; + return 0; } diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index XXXXXXX..XXXXXXX 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -XXX,XX +XXX,XX @@ get_files(vahControl * ctl) if (vah_add_file(&buf, ctl->def->os.slic_table, "r") != 0) goto cleanup; + if (ctl->def->pstore) + if (vah_add_file(&buf, ctl->def->pstore->path, "rw") != 0) + goto cleanup; + if (ctl->def->os.loader && ctl->def->os.loader->path) if (vah_add_file(&buf, ctl->def->os.loader->path, "rk") != 0) goto cleanup; -- 2.44.2
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- NEWS.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index XXXXXXX..XXXXXXX 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -XXX,XX +XXX,XX @@ v10.6.0 (unreleased) * **New features** + * Introduce pstore device + + The aim of pstore device is to provide a bit of NVRAM storage for guest + kernel to record oops/panic logs just before the it crashes. Typical usage + includes usage in combination with a watchdog so that the logs can be + inspected after the watchdog rebooted the machine. + * **Improvements** * **Bug fixes** -- 2.44.2
This is a rebased version of: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/UAUKLOCOYOYSUBF5DCCYCCDCLAZDEQHJ/ which was a rebased version of: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/VWR67LTU4Z5TQHDWVTPEVOGIS53FTJYK/ Let's hope no more resends will be needed. Michal Prívozník (5): qemu_capabilities: Introduce QEMU_CAPS_DEVICE_ACPI_ERST conf: Introduce pstore device qemu: Build cmd line for pstore device security: Set seclabels for pstore device NEWS: Document pstore device addition NEWS.rst | 7 + docs/formatdomain.rst | 32 ++++ src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 153 ++++++++++++++++++ src/conf/domain_conf.h | 19 +++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 30 ++++ src/conf/schemas/domaincommon.rng | 25 +++ src/conf/virconftypes.h | 2 + src/hyperv/hyperv_driver.c | 1 + src/libvirt_private.syms | 2 + src/libxl/libxl_driver.c | 6 + src/lxc/lxc_driver.c | 6 + src/qemu/qemu_alias.c | 10 ++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 52 ++++++ src/qemu/qemu_domain.c | 3 + src/qemu/qemu_domain_address.c | 11 ++ src/qemu/qemu_driver.c | 3 + src/qemu/qemu_hotplug.c | 5 + src/qemu/qemu_validate.c | 26 +++ src/security/security_dac.c | 10 ++ src/security/security_selinux.c | 9 ++ src/security/virt-aa-helper.c | 4 + src/test/test_driver.c | 1 + .../caps_7.0.0_aarch64+hvf.xml | 1 + .../caps_7.0.0_aarch64.xml | 1 + .../qemucapabilitiesdata/caps_7.0.0_ppc64.xml | 1 + .../caps_7.0.0_x86_64.xml | 1 + .../qemucapabilitiesdata/caps_7.1.0_ppc64.xml | 1 + .../caps_7.1.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml | 1 + .../caps_7.2.0_x86_64+hvf.xml | 1 + .../caps_7.2.0_x86_64.xml | 1 + .../caps_8.0.0_x86_64.xml | 1 + .../caps_8.1.0_x86_64.xml | 1 + .../caps_8.2.0_aarch64.xml | 1 + .../caps_8.2.0_armv7l.xml | 1 + .../caps_8.2.0_loongarch64.xml | 1 + .../caps_8.2.0_x86_64.xml | 1 + .../caps_9.0.0_x86_64.xml | 1 + .../caps_9.1.0_x86_64.xml | 1 + .../pstore-acpi-erst.x86_64-latest.args | 38 +++++ .../pstore-acpi-erst.x86_64-latest.xml | 1 + tests/qemuxmlconfdata/pstore-acpi-erst.xml | 53 ++++++ tests/qemuxmlconftest.c | 1 + 47 files changed, 532 insertions(+) create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args create mode 120000 tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.xml -- 2.44.2
This capability tracks whether QEMU has acpi-erst device. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml | 1 + tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml | 1 + tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml | 1 + tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml | 1 + tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml | 1 + tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml | 1 + 19 files changed, 20 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virQEMUCaps, /* 460 */ "sev-snp-guest", /* QEMU_CAPS_SEV_SNP_GUEST */ "netdev.user", /* QEMU_CAPS_NETDEV_USER */ + "acpi-erst", /* QEMU_CAPS_DEVICE_ACPI_ERST */ ); @@ -XXX,XX +XXX,XX @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "virtio-sound-pci", QEMU_CAPS_DEVICE_VIRTIO_SOUND }, { "virtio-sound-device", QEMU_CAPS_DEVICE_VIRTIO_SOUND }, { "sev-snp-guest", QEMU_CAPS_SEV_SNP_GUEST }, + { "acpi-erst", QEMU_CAPS_DEVICE_ACPI_ERST }, }; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -XXX,XX +XXX,XX @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 460 */ QEMU_CAPS_SEV_SNP_GUEST, /* -object sev-snp-guest */ QEMU_CAPS_NETDEV_USER, /* -netdev user */ + QEMU_CAPS_DEVICE_ACPI_ERST, /* -device acpi-erst */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml b/tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0_aarch64+hvf.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='machine.virt.ras'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>6002092</version> <microcodeVersion>61700243</microcodeVersion> <package>v7.0.0-rc2</package> diff --git a/tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml b/tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='machine.virt.ras'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>6002092</version> <microcodeVersion>61700243</microcodeVersion> <package>v7.0.0-rc2</package> diff --git a/tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml b/tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7000000</version> <microcodeVersion>42900243</microcodeVersion> <package>v7.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7000000</version> <microcodeVersion>43100243</microcodeVersion> <package>v7.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml b/tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7001000</version> <microcodeVersion>42900244</microcodeVersion> <package>v7.1.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7001000</version> <microcodeVersion>43100244</microcodeVersion> <package>v7.1.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml b/tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml +++ b/tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7002000</version> <microcodeVersion>0</microcodeVersion> <package>qemu-7.2.0-6.fc37</package> diff --git a/tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml b/tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml +++ b/tests/qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7002000</version> <microcodeVersion>43100245</microcodeVersion> <package>v7.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>7002000</version> <microcodeVersion>43100245</microcodeVersion> <package>v7.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8000000</version> <microcodeVersion>43100244</microcodeVersion> <package>v8.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='display-reload'/> <flag name='usb-mtp'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8001000</version> <microcodeVersion>43100245</microcodeVersion> <package>v8.1.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml b/tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml @@ -XXX,XX +XXX,XX @@ <flag name='machine.virt.ras'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8002000</version> <microcodeVersion>61700246</microcodeVersion> <package>v8.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml b/tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml @@ -XXX,XX +XXX,XX @@ <flag name='machine.virt.ras'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8002000</version> <microcodeVersion>0</microcodeVersion> <package>qemu-8.2.0-7.fc39</package> diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml b/tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_loongarch64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8002000</version> <microcodeVersion>106300246</microcodeVersion> <package>v8.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>8002000</version> <microcodeVersion>43100246</microcodeVersion> <package>v8.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>9000000</version> <microcodeVersion>43100245</microcodeVersion> <package>v9.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml index XXXXXXX..XXXXXXX 100644 --- a/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml @@ -XXX,XX +XXX,XX @@ <flag name='usb-mtp'/> <flag name='virtio-sound'/> <flag name='netdev.user'/> + <flag name='acpi-erst'/> <version>9000050</version> <microcodeVersion>43100246</microcodeVersion> <package>v9.0.0-1388-g80e8f06021-dirty</package> -- 2.44.2
The aim of pstore device is to provide a bit of NVRAM storage for guest kernel to record oops/panic logs just before the it crashes. Typical usage includes usage in combination with a watchdog so that the logs can be inspected after the watchdog rebooted the machine. While Linux kernel (and possibly Windows too) support many backends, in QEMU there's just 'acpi-erst' device so stick with that for now. The device must be attached to a PCI bus and needs two additional values (well, corresponding memory-backend-file needs them): size and path. Despite using memory-backeng-file this does NOT add any additional RAM to the guest and thus I've decided to expose it as another device type instead of memory model. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.rst | 32 ++++ src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 153 ++++++++++++++++++ src/conf/domain_conf.h | 19 +++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 30 ++++ src/conf/schemas/domaincommon.rng | 25 +++ src/conf/virconftypes.h | 2 + src/hyperv/hyperv_driver.c | 1 + src/libvirt_private.syms | 2 + src/libxl/libxl_driver.c | 6 + src/lxc/lxc_driver.c | 6 + src/qemu/qemu_command.c | 1 + src/qemu/qemu_domain.c | 3 + src/qemu/qemu_domain_address.c | 11 ++ src/qemu/qemu_driver.c | 3 + src/qemu/qemu_hotplug.c | 5 + src/qemu/qemu_validate.c | 26 +++ src/test/test_driver.c | 1 + .../pstore-acpi-erst.x86_64-latest.args | 36 +++++ .../pstore-acpi-erst.x86_64-latest.xml | 1 + tests/qemuxmlconfdata/pstore-acpi-erst.xml | 53 ++++++ tests/qemuxmlconftest.c | 1 + 23 files changed, 419 insertions(+) create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args create mode 120000 tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.xml diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -XXX,XX +XXX,XX @@ The optional attribute ``backend`` is required if the ``type`` is ``qemu``, the ... +Pstore +~~~~~~~~~ + +Pstore is an oops/panic logger that writes its logs to a block device and +non-block device before the system crashes. Currently only ACPI Error Record +Serialization Table, ERST, is supported. This feature is designed for storing +error records in persistent storage for future reference and/or debugging. +:since:`Since v10.6.0` + +:: + + ... + <pstore backend='acpi-erst'> + <path>/tmp/guest_acpi_esrt</path> + <size unit='KiB'>8</size> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </pstore> + ... + +The ``pstore`` element has one mandatory attribute ``backend`` which selects +desired backend (only ``acpi-erst`` is accepted for now). Then it has the +following child elements: + +``path`` + Represents a path in the host that backs the pstore device in the guest. It + is mandatory. + +``size`` + Configures the size of the persistent storage available to the guest. It is + mandatory. + + Security label -------------- diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index XXXXXXX..XXXXXXX 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -XXX,XX +XXX,XX @@ chValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Cloud-Hypervisor doesn't support '%1$s' device"), virDomainDeviceTypeToString(dev->type)); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virDomainDevice, "vsock", "audio", "crypto", + "pstore", ); VIR_ENUM_IMPL(virDomainDiskDevice, @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virDomainLaunchSecurity, "s390-pv", ); +VIR_ENUM_IMPL(virDomainPstoreBackend, + VIR_DOMAIN_PSTORE_BACKEND_LAST, + "acpi-erst", +); + typedef enum { VIR_DOMAIN_NET_VHOSTUSER_MODE_NONE, VIR_DOMAIN_NET_VHOSTUSER_MODE_CLIENT, @@ -XXX,XX +XXX,XX @@ void virDomainMemoryDefFree(virDomainMemoryDef *def) g_free(def); } +void virDomainPstoreDefFree(virDomainPstoreDef *def) +{ + if (!def) + return; + + g_free(def->path); + virDomainDeviceInfoClear(&def->info); + g_free(def); +} + void virDomainDeviceDefFree(virDomainDeviceDef *def) { if (!def) @@ -XXX,XX +XXX,XX @@ void virDomainDeviceDefFree(virDomainDeviceDef *def) case VIR_DOMAIN_DEVICE_CRYPTO: virDomainCryptoDefFree(def->data.crypto); break; + case VIR_DOMAIN_DEVICE_PSTORE: + virDomainPstoreDefFree(def->data.pstore); + break; case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: break; @@ -XXX,XX +XXX,XX @@ void virDomainDefFree(virDomainDef *def) virDomainIOMMUDefFree(def->iommu); + virDomainPstoreDefFree(def->pstore); + g_free(def->idmap.uidmap); g_free(def->idmap.gidmap); @@ -XXX,XX +XXX,XX @@ virDomainDeviceGetInfo(const virDomainDeviceDef *device) return &device->data.vsock->info; case VIR_DOMAIN_DEVICE_CRYPTO: return &device->data.crypto->info; + case VIR_DOMAIN_DEVICE_PSTORE: + return &device->data.pstore->info; /* The following devices do not contain virDomainDeviceInfo */ case VIR_DOMAIN_DEVICE_LEASE: @@ -XXX,XX +XXX,XX @@ virDomainDeviceSetData(virDomainDeviceDef *device, case VIR_DOMAIN_DEVICE_CRYPTO: device->data.crypto = devicedata; break; + case VIR_DOMAIN_DEVICE_PSTORE: + device->data.pstore = devicedata; + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; @@ -XXX,XX +XXX,XX @@ virDomainDeviceInfoIterateFlags(virDomainDef *def, return rc; } + device.type = VIR_DOMAIN_DEVICE_PSTORE; + if (def->pstore) { + device.data.pstore = def->pstore; + if ((rc = cb(def, &device, &def->pstore->info, opaque)) != 0) + return rc; + } + /* If the flag below is set, make sure @cb can handle @info being NULL */ if (iteratorFlags & DOMAIN_DEVICE_ITERATE_MISSING_INFO) { device.type = VIR_DOMAIN_DEVICE_GRAPHICS; @@ -XXX,XX +XXX,XX @@ virDomainDeviceInfoIterateFlags(virDomainDef *def, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; } #endif @@ -XXX,XX +XXX,XX @@ virDomainCryptoDefParseXML(virDomainXMLOption *xmlopt, } +static virDomainPstoreDef * +virDomainPstoreDefParseXML(virDomainXMLOption *xmlopt, + xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + g_autoptr(virDomainPstoreDef) def = NULL; + VIR_XPATH_NODE_AUTORESTORE(ctxt) + + def = g_new0(virDomainPstoreDef, 1); + + ctxt->node = node; + + if (virXMLPropEnum(node, "backend", + virDomainPstoreBackendTypeFromString, + VIR_XML_PROP_REQUIRED, + &def->backend) < 0) { + return NULL; + } + + def->path = virXPathString("string(./path)", ctxt); + + if (virDomainParseMemory("./size", "./size/@unit", ctxt, + &def->size, true, false) < 0) { + return NULL; + } + + if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0) + return NULL; + + return g_steal_pointer(&def); +} + + static int virDomainDeviceDefParseType(const char *typestr, virDomainDeviceType *type) @@ -XXX,XX +XXX,XX @@ virDomainDeviceDefParse(const char *xmlStr, flags))) return NULL; break; + case VIR_DOMAIN_DEVICE_PSTORE: + if (!(dev->data.pstore = virDomainPstoreDefParseXML(xmlopt, node, + ctxt, flags))) { + return NULL; + } + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; @@ -XXX,XX +XXX,XX @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, } VIR_FREE(nodes); + if ((n = virXPathNodeSet("./devices/pstore", ctxt, &nodes)) < 0) + return NULL; + + if (n > 1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("only a single pstore device is supported")); + return NULL; + } + + if (n > 0) { + if (!(def->pstore = virDomainPstoreDefParseXML(xmlopt, nodes[0], + ctxt, flags))) + return NULL; + } + VIR_FREE(nodes); + /* analysis of the user namespace mapping */ if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0) return NULL; @@ -XXX,XX +XXX,XX @@ virDomainVsockDefCheckABIStability(virDomainVsockDef *src, } +static bool +virDomainPstoreDefCheckABIStability(virDomainPstoreDef *src, + virDomainPstoreDef *dst) +{ + if (src->backend != dst->backend) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target pstore device backend '%1$s' does not match source '%2$s'"), + virDomainPstoreBackendTypeToString(dst->backend), + virDomainPstoreBackendTypeToString(src->backend)); + return false; + } + + if (src->size != dst->size) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target pstore size '%1$llu' does not match source '%2$llu'"), + dst->size, + src->size); + return false; + } + + if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info)) + return false; + + return true; +} + + static bool virDomainDefVcpuCheckAbiStability(virDomainDef *src, virDomainDef *dst) @@ -XXX,XX +XXX,XX @@ virDomainDefCheckABIStabilityFlags(virDomainDef *src, !virDomainVsockDefCheckABIStability(src->vsock, dst->vsock)) goto error; + if (!!src->pstore != !!dst->pstore) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Target domain pstore device count does not match source")); + goto error; + } + + if (src->pstore && + !virDomainPstoreDefCheckABIStability(src->pstore, dst->pstore)) { + goto error; + } + if (xmlopt && xmlopt->abi.domain && !xmlopt->abi.domain(src, dst)) goto error; @@ -XXX,XX +XXX,XX @@ virDomainDefCheckABIStabilityFlags(virDomainDef *src, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; } #endif @@ -XXX,XX +XXX,XX @@ virDomainDefFormatFeatures(virBuffer *buf, return 0; } +static int +virDomainPstoreDefFormat(virBuffer *buf, + virDomainPstoreDef *pstore, + unsigned int flags) +{ + g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + + virBufferAsprintf(&attrBuf, " backend='%s'", + virDomainPstoreBackendTypeToString(pstore->backend)); + + virBufferAsprintf(&childBuf, "<path>%s</path>\n", pstore->path); + virBufferAsprintf(&childBuf, "<size unit='KiB'>%llu</size>\n", pstore->size); + virDomainDeviceInfoFormat(&childBuf, &pstore->info, flags); + + virXMLFormatElement(buf, "pstore", &attrBuf, &childBuf); + return 0; +} + + int virDomainDefFormatInternal(virDomainDef *def, virDomainXMLOption *xmlopt, @@ -XXX,XX +XXX,XX @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, if (def->vsock) virDomainVsockDefFormat(buf, def->vsock); + if (def->pstore) + virDomainPstoreDefFormat(buf, def->pstore, flags); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</devices>\n"); @@ -XXX,XX +XXX,XX @@ virDomainDeviceIsUSB(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -XXX,XX +XXX,XX @@ typedef enum { VIR_DOMAIN_DEVICE_VSOCK, VIR_DOMAIN_DEVICE_AUDIO, VIR_DOMAIN_DEVICE_CRYPTO, + VIR_DOMAIN_DEVICE_PSTORE, VIR_DOMAIN_DEVICE_LAST } virDomainDeviceType; @@ -XXX,XX +XXX,XX @@ struct _virDomainDeviceDef { virDomainVsockDef *vsock; virDomainAudioDef *audio; virDomainCryptoDef *crypto; + virDomainPstoreDef *pstore; } data; }; @@ -XXX,XX +XXX,XX @@ struct _virDomainVirtioOptions { virTristateSwitch page_per_vq; }; +typedef enum { + VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST, + + VIR_DOMAIN_PSTORE_BACKEND_LAST +} virDomainPstoreBackend; + +struct _virDomainPstoreDef { + virDomainPstoreBackend backend; + unsigned long long size; + char *path; + virDomainDeviceInfo info; +}; + #define SCSI_SUPER_WIDE_BUS_MAX_CONT_UNIT 64 #define SCSI_WIDE_BUS_MAX_CONT_UNIT 16 @@ -XXX,XX +XXX,XX @@ struct _virDomainDef { virDomainRedirFilterDef *redirfilter; virDomainIOMMUDef *iommu; virDomainVsockDef *vsock; + virDomainPstoreDef *pstore; void *namespaceData; virXMLNamespace ns; @@ -XXX,XX +XXX,XX @@ void virDomainVsockDefFree(virDomainVsockDef *vsock); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainVsockDef, virDomainVsockDefFree); void virDomainCryptoDefFree(virDomainCryptoDef *def); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainCryptoDef, virDomainCryptoDefFree); +void virDomainPstoreDefFree(virDomainPstoreDef *def); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainPstoreDef, virDomainPstoreDefFree); void virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetTeamingInfo, virDomainNetTeamingInfoFree); void virDomainNetPortForwardFree(virDomainNetPortForward *pf); @@ -XXX,XX +XXX,XX @@ VIR_ENUM_DECL(virDomainCryptoBackend); VIR_ENUM_DECL(virDomainShmemModel); VIR_ENUM_DECL(virDomainShmemRole); VIR_ENUM_DECL(virDomainLaunchSecurity); +VIR_ENUM_DECL(virDomainPstoreBackend); /* from libvirt.h */ VIR_ENUM_DECL(virDomainState); VIR_ENUM_DECL(virDomainNostateReason); diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/domain_postparse.c +++ b/src/conf/domain_postparse.c @@ -XXX,XX +XXX,XX @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: ret = 0; break; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -XXX,XX +XXX,XX @@ virDomainTPMDevValidate(const virDomainTPMDef *tpm) } +static int +virDomainPstoreDefValidate(const virDomainPstoreDef *pstore) +{ + if (pstore->backend != VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unsupported backend for pstore device: %1$s"), + virDomainPstoreBackendTypeToString(pstore->backend)); + return -1; + } + + if (pstore->path == NULL || pstore->path[0] == '\0') { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing path for ACPI ERST pstore device")); + return -1; + } + + if (pstore->size < 4 || + !VIR_IS_POW2(pstore->size)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("invalid size of ACPI ERST pstore device")); + return -1; + } + + return 0; +} + + static int virDomainDeviceInfoValidate(const virDomainDeviceDef *dev) { @@ -XXX,XX +XXX,XX @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_TPM: return virDomainTPMDevValidate(dev->data.tpm); + case VIR_DOMAIN_DEVICE_PSTORE: + return virDomainPstoreDefValidate(dev->data.pstore); + case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_WATCHDOG: case VIR_DOMAIN_DEVICE_HUB: diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index XXXXXXX..XXXXXXX 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -XXX,XX +XXX,XX @@ </element> </define> + <define name="pstore"> + <element name="pstore"> + <attribute name="backend"> + <value>acpi-erst</value> + </attribute> + <interleave> + <element name="path"> + <ref name="absFilePath"/> + </element> + <element name="size"> + <ref name="scaledInteger"/> + </element> + <optional> + <ref name="address"/> + </optional> + <optional> + <ref name="alias"/> + </optional> + </interleave> + </element> + </define> + <define name="hostdev"> <element name="hostdev"> <interleave> @@ -XXX,XX +XXX,XX @@ <optional> <ref name="vsock"/> </optional> + <optional> + <ref name="pstore"/> + </optional> </interleave> </element> </define> diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -XXX,XX +XXX,XX @@ typedef struct _virDomainVsockDef virDomainVsockDef; typedef struct _virDomainCryptoDef virDomainCryptoDef; +typedef struct _virDomainPstoreDef virDomainPstoreDef; + typedef struct _virDomainWatchdogDef virDomainWatchdogDef; typedef struct _virDomainXMLOption virDomainXMLOption; diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -XXX,XX +XXX,XX @@ hypervDomainAttachDeviceFlags(virDomainPtr domain, const char *xml, unsigned int case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_INTERNAL_ERROR, _("Attaching devices of type %1$d is not implemented"), dev->type); return -1; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -XXX,XX +XXX,XX @@ virDomainPausedReasonTypeToString; virDomainPMSuspendedReasonTypeFromString; virDomainPMSuspendedReasonTypeToString; virDomainProcessCapsFeatureTypeToString; +virDomainPstoreBackendTypeFromString; +virDomainPstoreBackendTypeToString; virDomainRedirdevBusTypeFromString; virDomainRedirdevBusTypeToString; virDomainRedirdevDefFind; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -XXX,XX +XXX,XX @@ libxlDomainAttachDeviceLive(libxlDriverPrivate *driver, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be attached"), virDomainDeviceTypeToString(dev->type)); @@ -XXX,XX +XXX,XX @@ libxlDomainAttachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent attach of device is not supported")); return -1; @@ -XXX,XX +XXX,XX @@ libxlDomainDetachDeviceLive(libxlDriverPrivate *driver, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be detached"), virDomainDeviceTypeToString(dev->type)); @@ -XXX,XX +XXX,XX @@ libxlDomainDetachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent detach of device is not supported")); return -1; @@ -XXX,XX +XXX,XX @@ libxlDomainUpdateDeviceLive(virDomainObj *vm, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be updated"), virDomainDeviceTypeToString(dev->type)); @@ -XXX,XX +XXX,XX @@ libxlDomainUpdateDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent update of device is not supported")); return -1; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -XXX,XX +XXX,XX @@ lxcDomainAttachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent attach of device is not supported")); break; @@ -XXX,XX +XXX,XX @@ lxcDomainUpdateDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent update of device is not supported")); break; @@ -XXX,XX +XXX,XX @@ lxcDomainDetachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_AUDIO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent detach of device is not supported")); break; @@ -XXX,XX +XXX,XX @@ lxcDomainAttachDeviceMknodHelper(pid_t pid G_GNUC_UNUSED, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected device type %1$d"), data->def->type); @@ -XXX,XX +XXX,XX @@ lxcDomainAttachDeviceLive(virLXCDriver *driver, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be attached"), virDomainDeviceTypeToString(dev->type)); @@ -XXX,XX +XXX,XX @@ lxcDomainDetachDeviceLive(virLXCDriver *driver, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be detached"), virDomainDeviceTypeToString(dev->type)); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -XXX,XX +XXX,XX @@ qemuBuildVirtioDevGetConfigDev(const virDomainDeviceDef *device, case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: default: break; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -XXX,XX +XXX,XX @@ qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: ret = 0; break; @@ -XXX,XX +XXX,XX @@ qemuDomainPrepareChardevSourceOne(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; } @@ -XXX,XX +XXX,XX @@ qemuDomainDeviceBackendChardevForeachOne(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: /* no chardev backend */ break; } diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -XXX,XX +XXX,XX @@ qemuDomainDeviceSupportZPCI(virDomainDeviceDef *device) case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: break; case VIR_DOMAIN_DEVICE_NONE: @@ -XXX,XX +XXX,XX @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev, } break; + case VIR_DOMAIN_DEVICE_PSTORE: + return pciFlags; + /* These devices don't ever connect with PCI */ case VIR_DOMAIN_DEVICE_NVRAM: case VIR_DOMAIN_DEVICE_TPM: @@ -XXX,XX +XXX,XX @@ qemuDomainAssignDevicePCISlots(virDomainDef *def, } } + if (def->pstore && + virDeviceInfoPCIAddressIsWanted(&def->pstore->info)) { + if (qemuDomainPCIAddressReserveNextAddr(addrs, + &def->pstore->info) < 0) + return -1; + } + return 0; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -XXX,XX +XXX,XX @@ qemuDomainAttachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent attach of device '%1$s' is not supported"), @@ -XXX,XX +XXX,XX @@ qemuDomainDetachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent detach of device '%1$s' is not supported"), @@ -XXX,XX +XXX,XX @@ qemuDomainUpdateDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent update of device '%1$s' is not supported"), diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -XXX,XX +XXX,XX @@ qemuDomainAttachDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live attach of device '%1$s' is not supported"), @@ -XXX,XX +XXX,XX @@ qemuDomainRemoveAuditDevice(virDomainObj *vm, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: /* libvirt doesn't yet support detaching these devices */ break; @@ -XXX,XX +XXX,XX @@ qemuDomainRemoveDevice(virQEMUDriver *driver, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("don't know how to remove a %1$s device"), @@ -XXX,XX +XXX,XX @@ qemuDomainDetachDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live detach of device '%1$s' is not supported"), @@ -XXX,XX +XXX,XX @@ qemuDomainUpdateDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("live update of device '%1$s' is not supported"), diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -XXX,XX +XXX,XX @@ qemuValidateDomainDeviceDefCrypto(virDomainCryptoDef *crypto, } +static int +qemuValidateDomainDeviceDefPstore(virDomainPstoreDef *pstore, + const virDomainDef *def G_GNUC_UNUSED, + virQEMUCaps *qemuCaps) +{ + if (pstore->backend == VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ACPI_ERST)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("acpi-erst backend of pstore device is not supported")); + return -1; + } + + if (pstore->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + pstore->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("ACPI ERST device must reside on a PCI bus")); + return -1; + } + + return 0; +} + + static int qemuSoundCodecTypeToCaps(int type) { @@ -XXX,XX +XXX,XX @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_CRYPTO: return qemuValidateDomainDeviceDefCrypto(dev->data.crypto, def, qemuCaps); + case VIR_DOMAIN_DEVICE_PSTORE: + return qemuValidateDomainDeviceDefPstore(dev->data.pstore, def, qemuCaps); + case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_NONE: diff --git a/src/test/test_driver.c b/src/test/test_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -XXX,XX +XXX,XX @@ testDomainUpdateDevice(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_VSOCK: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_PSTORE: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent update of device '%1$s' is not supported"), diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args @@ -XXX,XX +XXX,XX @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-guest \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-guest/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-guest/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-guest/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=guest,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-guest/master-key.aes"}' \ +-machine pc-q35-9.0,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=on \ +-accel kvm \ +-cpu qemu64 \ +-m size=1048576k \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":1073741824}' \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 63840878-0deb-4095-97e6-fc444d9bc9fa \ +-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-pci-bridge","id":"pci.2","bus":"pci.1","addr":"0x0"}' \ +-device '{"driver":"pcie-root-port","port":9,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x1.0x1"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-global ICH9-LPC.noreboot=off \ +-watchdog-action reset \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml @@ -0,0 +1 @@ +pstore-acpi-erst.xml \ No newline at end of file diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.xml b/tests/qemuxmlconfdata/pstore-acpi-erst.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.xml @@ -XXX,XX +XXX,XX @@ +<domain type='kvm'> + <name>guest</name> + <uuid>63840878-0deb-4095-97e6-fc444d9bc9fa</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>1048576</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc-q35-9.0'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </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-x86_64</emulator> + <controller type='usb' index='0' model='none'/> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <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-to-pci-bridge'> + <model name='pcie-pci-bridge'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <watchdog model='itco' action='reset'/> + <memballoon model='none'/> + <pstore backend='acpi-erst'> + <path>/tmp/guest_acpi_esrt</path> + <size unit='KiB'>8</size> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </pstore> + </devices> +</domain> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST_CAPS_LATEST("mtp-usb-device") DO_TEST_CAPS_LATEST("net-usb") DO_TEST_CAPS_LATEST("sound-device-virtio") + DO_TEST_CAPS_LATEST("pstore-acpi-erst") DO_TEST_CAPS_LATEST_FAILURE("disk-network-iscsi-zero-hosts-invalid") DO_TEST_CAPS_LATEST_PARSE_ERROR("hostdev-scsi-vhost-rawio-invalid") -- 2.44.2
Nothing special going on here. Resolves: https://issues.redhat.com/browse/RHEL-24746 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_alias.c | 10 ++++ src/qemu/qemu_command.c | 51 +++++++++++++++++++ .../pstore-acpi-erst.x86_64-latest.args | 2 + 3 files changed, 63 insertions(+) diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -XXX,XX +XXX,XX @@ qemuAssignDeviceCryptoAlias(virDomainDef *def, } +static void +qemuAssignDevicePstoreAlias(virDomainPstoreDef *pstore) +{ + if (!pstore->info.alias) + pstore->info.alias = g_strdup("pstore0"); +} + + int qemuAssignDeviceAliases(virDomainDef *def) { @@ -XXX,XX +XXX,XX @@ qemuAssignDeviceAliases(virDomainDef *def) for (i = 0; i < def->ncryptos; i++) { qemuAssignDeviceCryptoAlias(def, def->cryptos[i]); } + if (def->pstore) + qemuAssignDevicePstoreAlias(def->pstore); return 0; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index XXXXXXX..XXXXXXX 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -XXX,XX +XXX,XX @@ qemuBuildCryptoCommandLine(virCommand *cmd, } +static int +qemuBuildPstoreCommandLine(virCommand *cmd, + const virDomainDef *def, + virDomainPstoreDef *pstore, + virQEMUCaps *qemuCaps) +{ + g_autoptr(virJSONValue) devProps = NULL; + g_autoptr(virJSONValue) memProps = NULL; + g_autofree char *memAlias = NULL; + + if (!pstore->info.alias) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("pstore device is missing alias")); + return -1; + } + + memAlias = g_strdup_printf("mem%s", pstore->info.alias); + + if (qemuMonitorCreateObjectProps(&memProps, + "memory-backend-file", + memAlias, + "s:mem-path", pstore->path, + "U:size", pstore->size * 1024, + "b:share", true, + NULL) < 0) { + return -1; + } + + if (virJSONValueObjectAdd(&devProps, + "s:driver", "acpi-erst", + "s:id", pstore->info.alias, + "s:memdev", memAlias, + NULL) < 0) { + return -1; + } + + if (qemuBuildDeviceAddressProps(devProps, def, &pstore->info) < 0) + return -1; + + if (qemuBuildObjectCommandlineFromJSON(cmd, memProps, qemuCaps) < 0 || + qemuBuildDeviceCommandlineFromJSON(cmd, devProps, def, qemuCaps) < 0) + return -1; + + return 0; +} + + static int qemuBuildAsyncTeardownCommandLine(virCommand *cmd, const virDomainDef *def, @@ -XXX,XX +XXX,XX @@ qemuBuildCommandLine(virDomainObj *vm, if (qemuBuildCryptoCommandLine(cmd, def, qemuCaps) < 0) return NULL; + if (def->pstore && + qemuBuildPstoreCommandLine(cmd, def, def->pstore, qemuCaps) < 0) + return NULL; + if (qemuBuildAsyncTeardownCommandLine(cmd, def, qemuCaps) < 0) return NULL; diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args index XXXXXXX..XXXXXXX 100644 --- a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args @@ -XXX,XX +XXX,XX @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-guest/.config \ -global ICH9-LPC.noreboot=off \ -watchdog-action reset \ -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-object '{"qom-type":"memory-backend-file","id":"mempstore0","mem-path":"/tmp/guest_acpi_esrt","size":8192,"share":true}' \ +-device '{"driver":"acpi-erst","id":"pstore0","memdev":"mempstore0","bus":"pci.2","addr":"0x1"}' \ -msg timestamp=on -- 2.44.2
The acpi-erst backend for pstore device exposes a path in the host accessible to the guest and as such we must set seclabels on it to grant QEMU RW access. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/security/security_dac.c | 10 ++++++++++ src/security/security_selinux.c | 9 +++++++++ src/security/virt-aa-helper.c | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/src/security/security_dac.c b/src/security/security_dac.c index XXXXXXX..XXXXXXX 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -XXX,XX +XXX,XX @@ virSecurityDACRestoreAllLabel(virSecurityManager *mgr, virSecurityDACRestoreFileLabel(mgr, def->os.slic_table) < 0) rc = -1; + if (def->pstore && + virSecurityDACRestoreFileLabel(mgr, def->pstore->path) < 0) + rc = -1; + return rc; } @@ -XXX,XX +XXX,XX @@ virSecurityDACSetAllLabel(virSecurityManager *mgr, user, group, true) < 0) return -1; + if (def->pstore && + virSecurityDACSetOwnership(mgr, NULL, + def->pstore->path, + user, group, true) < 0) + return -1; + return 0; } diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index XXXXXXX..XXXXXXX 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -XXX,XX +XXX,XX @@ virSecuritySELinuxRestoreAllLabel(virSecurityManager *mgr, virSecuritySELinuxRestoreFileLabel(mgr, def->os.slic_table, true) < 0) rc = -1; + if (def->pstore && + virSecuritySELinuxRestoreFileLabel(mgr, def->pstore->path, true) < 0) + rc = -1; + return rc; } @@ -XXX,XX +XXX,XX @@ virSecuritySELinuxSetAllLabel(virSecurityManager *mgr, data->content_context, true) < 0) return -1; + if (def->pstore && + virSecuritySELinuxSetFilecon(mgr, def->pstore->path, + data->content_context, true) < 0) + return -1; + return 0; } diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index XXXXXXX..XXXXXXX 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -XXX,XX +XXX,XX @@ get_files(vahControl * ctl) if (vah_add_file(&buf, ctl->def->os.slic_table, "r") != 0) goto cleanup; + if (ctl->def->pstore) + if (vah_add_file(&buf, ctl->def->pstore->path, "rw") != 0) + goto cleanup; + if (ctl->def->os.loader && ctl->def->os.loader->path) { bool readonly = false; virTristateBoolToBool(ctl->def->os.loader->readonly, &readonly); -- 2.44.2
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- NEWS.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index XXXXXXX..XXXXXXX 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -XXX,XX +XXX,XX @@ v10.6.0 (unreleased) * qemu: Add support for the 'pauth' Arm CPU feature + * Introduce pstore device + + The aim of pstore device is to provide a bit of NVRAM storage for guest + kernel to record oops/panic logs just before the it crashes. Typical usage + includes usage in combination with a watchdog so that the logs can be + inspected after the watchdog rebooted the machine. + * **Improvements** * **Bug fixes** -- 2.44.2