On Mon, Jul 22, 2024 at 2:32 PM Michal Privoznik <[email protected]> wrote:
> 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 > *memory-backend-file this does.... guest and thus I've decided to expose it as another device type > instead of memory model. > > Signed-off-by: Michal Privoznik <[email protected]> > --- > 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 10584dfe83..8b35005c9e 100644 > --- a/docs/formatdomain.rst > +++ b/docs/formatdomain.rst > @@ -8659,6 +8659,38 @@ 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 8e3e205c8c..e1e14554a8 100644 > --- a/src/ch/ch_domain.c > +++ b/src/ch/ch_domain.c > @@ -180,6 +180,7 @@ 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 6733857a3a..12ae8a9526 100644 > --- a/src/conf/domain_conf.c > +++ b/src/conf/domain_conf.c > @@ -337,6 +337,7 @@ VIR_ENUM_IMPL(virDomainDevice, > "vsock", > "audio", > "crypto", > + "pstore", > ); > > VIR_ENUM_IMPL(virDomainDiskDevice, > @@ -1513,6 +1514,11 @@ 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, > @@ -3548,6 +3554,16 @@ 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) > @@ -3632,6 +3648,9 @@ 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; > @@ -3997,6 +4016,8 @@ void virDomainDefFree(virDomainDef *def) > > virDomainIOMMUDefFree(def->iommu); > > + virDomainPstoreDefFree(def->pstore); > + > g_free(def->idmap.uidmap); > g_free(def->idmap.gidmap); > > @@ -4554,6 +4575,8 @@ 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: > @@ -4659,6 +4682,9 @@ 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; > @@ -4877,6 +4903,13 @@ 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; > @@ -4936,6 +4969,7 @@ 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 > @@ -14006,6 +14040,40 @@ 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) > @@ -14185,6 +14253,12 @@ 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; > @@ -19532,6 +19606,22 @@ 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; > @@ -21404,6 +21494,33 @@ > 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) > @@ -21863,6 +21980,17 @@ 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; > @@ -21903,6 +22031,7 @@ 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 > @@ -27849,6 +27978,26 @@ 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, > @@ -28320,6 +28469,9 @@ 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"); > > @@ -28479,6 +28631,7 @@ 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 8283493dfc..546c14e7b0 100644 > --- a/src/conf/domain_conf.h > +++ b/src/conf/domain_conf.h > @@ -87,6 +87,7 @@ typedef enum { > VIR_DOMAIN_DEVICE_VSOCK, > VIR_DOMAIN_DEVICE_AUDIO, > VIR_DOMAIN_DEVICE_CRYPTO, > + VIR_DOMAIN_DEVICE_PSTORE, > > VIR_DOMAIN_DEVICE_LAST > } virDomainDeviceType; > @@ -120,6 +121,7 @@ struct _virDomainDeviceDef { > virDomainVsockDef *vsock; > virDomainAudioDef *audio; > virDomainCryptoDef *crypto; > + virDomainPstoreDef *pstore; > } data; > }; > > @@ -2983,6 +2985,19 @@ 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 > @@ -3159,6 +3174,7 @@ struct _virDomainDef { > virDomainRedirFilterDef *redirfilter; > virDomainIOMMUDef *iommu; > virDomainVsockDef *vsock; > + virDomainPstoreDef *pstore; > > void *namespaceData; > virXMLNamespace ns; > @@ -3598,6 +3614,8 @@ 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); > @@ -4268,6 +4286,7 @@ 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 112795ea65..bf33f29638 100644 > --- a/src/conf/domain_postparse.c > +++ b/src/conf/domain_postparse.c > @@ -757,6 +757,7 @@ 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 8209e8fdae..39b8d67928 100644 > --- a/src/conf/domain_validate.c > +++ b/src/conf/domain_validate.c > @@ -3022,6 +3022,33 @@ 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) > { > @@ -3132,6 +3159,9 @@ 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 ab5374d5f0..200009efa5 100644 > --- a/src/conf/schemas/domaincommon.rng > +++ b/src/conf/schemas/domaincommon.rng > @@ -6255,6 +6255,28 @@ > </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> > @@ -6724,6 +6746,9 @@ > <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 d8e7c5278c..f18ebcca10 100644 > --- a/src/conf/virconftypes.h > +++ b/src/conf/virconftypes.h > @@ -260,6 +260,8 @@ 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 7580c6a06c..43ccb9cbd7 100644 > --- a/src/hyperv/hyperv_driver.c > +++ b/src/hyperv/hyperv_driver.c > @@ -3133,6 +3133,7 @@ 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 c35366c9e1..d15d6a6a9d 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -616,6 +616,8 @@ virDomainPausedReasonTypeToString; > virDomainPMSuspendedReasonTypeFromString; > virDomainPMSuspendedReasonTypeToString; > virDomainProcessCapsFeatureTypeToString; > +virDomainPstoreBackendTypeFromString; > +virDomainPstoreBackendTypeToString; > virDomainRedirdevBusTypeFromString; > virDomainRedirdevBusTypeToString; > virDomainRedirdevDefFind; > diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c > index 7dcae58413..e72553603d 100644 > --- a/src/libxl/libxl_driver.c > +++ b/src/libxl/libxl_driver.c > @@ -3505,6 +3505,7 @@ 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)); > @@ -3613,6 +3614,7 @@ 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; > @@ -3981,6 +3983,7 @@ 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)); > @@ -4071,6 +4074,7 @@ 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; > @@ -4133,6 +4137,7 @@ 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)); > @@ -4195,6 +4200,7 @@ 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 f76d09e8a9..534e257f30 100644 > --- a/src/lxc/lxc_driver.c > +++ b/src/lxc/lxc_driver.c > @@ -3056,6 +3056,7 @@ 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; > @@ -3121,6 +3122,7 @@ 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; > @@ -3202,6 +3204,7 @@ 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; > @@ -3303,6 +3306,7 @@ 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); > @@ -3974,6 +3978,7 @@ 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)); > @@ -4391,6 +4396,7 @@ 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 684de3f701..def124cc27 100644 > --- a/src/qemu/qemu_command.c > +++ b/src/qemu/qemu_command.c > @@ -973,6 +973,7 @@ 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 2134b11038..a8d7a1e525 100644 > --- a/src/qemu/qemu_domain.c > +++ b/src/qemu/qemu_domain.c > @@ -6358,6 +6358,7 @@ 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; > > @@ -10360,6 +10361,7 @@ > qemuDomainPrepareChardevSourceOne(virDomainDeviceDef *dev, > case VIR_DOMAIN_DEVICE_VSOCK: > case VIR_DOMAIN_DEVICE_AUDIO: > case VIR_DOMAIN_DEVICE_CRYPTO: > + case VIR_DOMAIN_DEVICE_PSTORE: > break; > } > > @@ -12290,6 +12292,7 @@ > 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 251f5b7e1a..970ae3949d 100644 > --- a/src/qemu/qemu_domain_address.c > +++ b/src/qemu/qemu_domain_address.c > @@ -470,6 +470,7 @@ 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: > @@ -1002,6 +1003,9 @@ > 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: > @@ -2424,6 +2428,13 @@ 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 9f3013e231..e473018ef2 100644 > --- a/src/qemu/qemu_driver.c > +++ b/src/qemu/qemu_driver.c > @@ -6863,6 +6863,7 @@ 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"), > @@ -7081,6 +7082,7 @@ 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"), > @@ -7206,6 +7208,7 @@ 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 1f4620d833..af4229d507 100644 > --- a/src/qemu/qemu_hotplug.c > +++ b/src/qemu/qemu_hotplug.c > @@ -3452,6 +3452,7 @@ 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"), > @@ -5282,6 +5283,7 @@ 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; > @@ -5386,6 +5388,7 @@ 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"), > @@ -6270,6 +6273,7 @@ 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"), > @@ -7259,6 +7263,7 @@ 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 8840306bfd..0e8f0f977f 100644 > --- a/src/qemu/qemu_validate.c > +++ b/src/qemu/qemu_validate.c > @@ -4669,6 +4669,29 @@ > 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) > { > @@ -5372,6 +5395,9 @@ 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 df6a86ea44..7cb77f044d 100644 > --- a/src/test/test_driver.c > +++ b/src/test/test_driver.c > @@ -10294,6 +10294,7 @@ 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 0000000000..d7c4708acb > --- /dev/null > +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args > @@ -0,0 +1,36 @@ > +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 0000000000..11ade68605 > --- /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 0000000000..9b9ba266b2 > --- /dev/null > +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.xml > @@ -0,0 +1,53 @@ > +<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 cc984440ea..68d1127cf4 100644 > --- a/tests/qemuxmlconftest.c > +++ b/tests/qemuxmlconftest.c > @@ -2949,6 +2949,7 @@ 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 > Reviewed-by: Kristina Hanicova <[email protected]> Kristina
