conf: 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. 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-backend-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>
Reviewed-by: Kristina Hanicova <khanicov@redhat.com>
This commit is contained in:
Michal Privoznik 2024-06-04 17:45:48 +02:00
parent 4a9c2d9bbe
commit 90e50e67c6
23 changed files with 419 additions and 0 deletions

View File

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

View File

@ -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));

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

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

View File

@ -260,6 +260,8 @@ typedef struct _virDomainVsockDef virDomainVsockDef;
typedef struct _virDomainCryptoDef virDomainCryptoDef;
typedef struct _virDomainPstoreDef virDomainPstoreDef;
typedef struct _virDomainWatchdogDef virDomainWatchdogDef;
typedef struct _virDomainXMLOption virDomainXMLOption;

View File

@ -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;

View File

@ -616,6 +616,8 @@ virDomainPausedReasonTypeToString;
virDomainPMSuspendedReasonTypeFromString;
virDomainPMSuspendedReasonTypeToString;
virDomainProcessCapsFeatureTypeToString;
virDomainPstoreBackendTypeFromString;
virDomainPstoreBackendTypeToString;
virDomainRedirdevBusTypeFromString;
virDomainRedirdevBusTypeToString;
virDomainRedirdevDefFind;

View File

@ -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;

View File

@ -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));

View File

@ -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;

View File

@ -6365,6 +6365,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;
@ -10367,6 +10368,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;
}
@ -12298,6 +12300,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;
}

View File

@ -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;
}

View File

@ -6882,6 +6882,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"),
@ -7100,6 +7101,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"),
@ -7225,6 +7227,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"),

View File

@ -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"),
@ -5276,6 +5277,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;
@ -5380,6 +5382,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"),
@ -6264,6 +6267,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"),
@ -7253,6 +7257,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"),

View File

@ -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:

View File

@ -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"),

View File

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

View File

@ -0,0 +1 @@
pstore-acpi-erst.xml

View File

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

View File

@ -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")