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(a)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 00f861e385..8cebdb1ec7 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -8653,6 +8653,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.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 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 fde594f811..fd95f9d17e 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,
@@ -1512,6 +1513,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,
@@ -3546,6 +3552,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)
@@ -3630,6 +3646,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;
@@ -3989,6 +4008,8 @@ void virDomainDefFree(virDomainDef *def)
virDomainIOMMUDefFree(def->iommu);
+ virDomainPstoreDefFree(def->pstore);
+
g_free(def->idmap.uidmap);
g_free(def->idmap.gidmap);
@@ -4546,6 +4567,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:
@@ -4651,6 +4674,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;
@@ -4869,6 +4895,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;
@@ -4928,6 +4961,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
@@ -13925,6 +13959,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)
@@ -14104,6 +14172,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;
@@ -19451,6 +19525,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;
@@ -21323,6 +21413,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)
@@ -21782,6 +21899,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;
@@ -21822,6 +21950,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
@@ -27729,6 +27858,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,
@@ -28201,6 +28350,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");
@@ -28360,6 +28512,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 a06f015444..321e75a728 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;
};
@@ -2960,6 +2962,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
@@ -3136,6 +3151,7 @@ struct _virDomainDef {
virDomainRedirFilterDef *redirfilter;
virDomainIOMMUDef *iommu;
virDomainVsockDef *vsock;
+ virDomainPstoreDef *pstore;
void *namespaceData;
virXMLNamespace ns;
@@ -3579,6 +3595,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);
@@ -4249,6 +4267,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 395e036e8f..af999589dc 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -2977,6 +2977,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)
{
@@ -3087,6 +3114,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 a46a824f88..13f6be2c79 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -6181,6 +6181,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>
@@ -6650,6 +6672,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 0779bc224b..2aaa3092a8 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -256,6 +256,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 653c84a520..81449d5bae 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -611,6 +611,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 2d0eddc79e..5176b10db9 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 7ba2ea4a5e..b174878dbb 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -6339,6 +6339,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;
@@ -10340,6 +10341,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;
}
@@ -12270,6 +12272,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 e2698c7924..a631b8b4d8 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6859,6 +6859,7 @@ qemuDomainAttachDeviceConfig(virDomainDef *vmdef,
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,
_("persistent attach of device '%1$s' is not
supported"),
@@ -7066,6 +7067,7 @@ qemuDomainDetachDeviceConfig(virDomainDef *vmdef,
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,
_("persistent detach of device '%1$s' is not
supported"),
@@ -7191,6 +7193,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 4a3f4f657e..a079ddf71b 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"),
@@ -5265,6 +5266,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;
@@ -5369,6 +5371,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"),
@@ -6253,6 +6256,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"),
@@ -7242,6 +7246,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 95af93d606..60fd9b6d78 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -4640,6 +4640,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)
{
@@ -5343,6 +5366,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/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 d2f62081b7..4bf436fb58 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -2984,6 +2984,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")
/* check that all input files were actually used here */
if (testConfXMLCheck(existingTestCases) < 0)
--
2.44.2