[PATCH 0/4] Allow xml-configured coredump format on VM crash

When libvirt processes VM crash event it always dumps core in raw format. This series makes it possible to configure dump format via domain xml. This would be especcialy helpful for Windows guests, because it requires a lot effort to convert raw dump into wingdb. Nikolai Barybin (4): conf: schemas: add coredump_format element to events section src: conf: add parsing/formatting for 'coredump_format' value qemu: use configurable dump format in doCoreDumpToAutoDumpPath() docs: formatdomain: document 'coredump_format' element docs/formatdomain.rst | 9 +++++ src/conf/domain_conf.c | 64 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 + src/conf/schemas/domaincommon.rng | 19 +++++++++ src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 2 +- 6 files changed, 97 insertions(+), 1 deletion(-) -- 2.43.5

Signed-off-by: Nikolai Barybin <nikolai.barybin@virtuozzo.com> --- src/conf/schemas/domaincommon.rng | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 5597d5a66b..dc8f708779 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -4816,6 +4816,11 @@ <ref name="crashOptions"/> </element> </optional> + <optional> + <element name="coredump_format"> + <ref name="coredumpFormat"/> + </element> + </optional> <optional> <element name="on_lockfailure"> <ref name="lockfailureOptions"/> @@ -4862,6 +4867,20 @@ <value>coredump-restart</value> </choice> </define> + <!-- + Spicifies domain's coredump format when 'coredump-destroy' or 'coredump-restart' + are chosen in crashOptions. + Default value is 'raw'. + --> + <define name="coredumpFormat"> + <choice> + <value>raw</value> + <value>kdump-zlib</value> + <value>kdump-lzo</value> + <value>kdump-snappy</value> + <value>win-dmp</value> + </choice> + </define> <!-- Options when resource locks are lost: poweroff: power off the domain -- 2.43.5

Signed-off-by: Nikolai Barybin <nikolai.barybin@virtuozzo.com> --- src/conf/domain_conf.c | 64 ++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 ++ src/libvirt_private.syms | 2 ++ 3 files changed, 68 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 99ecb03067..89dceacf79 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -303,6 +303,15 @@ VIR_ENUM_IMPL(virDomainLifecycleAction, "coredump-restart", ); +VIR_ENUM_IMPL(virDomainCoreDumpFormat, + VIR_DOMAIN_CORE_DUMP_FORMAT_LAST, + "raw", + "kdump-zlib", + "kdump-lzo", + "kdump-snappy", + "win-dmp", +); + VIR_ENUM_IMPL(virDomainLockFailure, VIR_DOMAIN_LOCK_FAILURE_LAST, "default", @@ -13820,6 +13829,29 @@ virDomainRedirFilterDefParseXML(xmlNodePtr node, return NULL; } +static int +virDomainCoredumpFormatParseXML(xmlXPathContextPtr ctxt, + const char *name, + const char *xpath, + int *val, + int defaultVal, + virEventActionFromStringFunc convFunc) +{ + g_autofree char *tmp = virXPathString(xpath, ctxt); + + if (tmp == NULL) { + *val = defaultVal; + } else { + *val = convFunc(tmp); + if (*val < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown %1$s format: %2$s"), name, tmp); + return -1; + } + } + return 0; +} + static int virDomainEventActionParseXML(xmlXPathContextPtr ctxt, const char *name, @@ -19163,6 +19195,13 @@ virDomainDefLifecycleParse(virDomainDef *def, virDomainLifecycleActionTypeFromString) < 0) return -1; + if (virDomainCoredumpFormatParseXML(ctxt, "coredump_format", + "string(./coredump_format[1])", + &def->coredumpFormat, + VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, + virDomainCoreDumpFormatTypeFromString) < 0) + return -1; + if (virDomainEventActionParseXML(ctxt, "on_lockfailure", "string(./on_lockfailure[1])", &def->onLockFailure, @@ -22857,6 +22896,25 @@ virDomainEventActionDefFormat(virBuffer *buf, } +static int +virDomainCoreDumpFormatDefFormat(virBuffer *buf, + int type, + const char *name, + virEventActionToStringFunc convFunc) +{ + const char *typeStr = convFunc(type); + if (!typeStr) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected %1$s coredump format: %2$d"), name, type); + return -1; + } + + virBufferAsprintf(buf, "<%s>%s</%s>\n", name, typeStr, name); + + return 0; +} + + static void virSecurityLabelDefFormat(virBuffer *buf, virSecurityLabelDef *def, @@ -29023,6 +29081,12 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, "on_crash", virDomainLifecycleActionTypeToString) < 0) return -1; + if ((def->onCrash == VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY || + def->onCrash == VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART) && + virDomainCoreDumpFormatDefFormat(buf, def->coredumpFormat, + "coredump_format", + virDomainCoreDumpFormatTypeToString) < 0) + return -1; if (def->onLockFailure != VIR_DOMAIN_LOCK_FAILURE_DEFAULT && virDomainEventActionDefFormat(buf, def->onLockFailure, "on_lockfailure", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 0d1dd954ae..6e43282160 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3144,6 +3144,7 @@ struct _virDomainDef { int onReboot; int onPoweroff; int onCrash; + int coredumpFormat; int onLockFailure; /* enum virDomainLockFailureAction */ @@ -4281,6 +4282,7 @@ VIR_ENUM_DECL(virDomainCapabilitiesPolicy); VIR_ENUM_DECL(virDomainProcessCapsFeature); VIR_ENUM_DECL(virDomainLifecycle); VIR_ENUM_DECL(virDomainLifecycleAction); +VIR_ENUM_DECL(virDomainCoreDumpFormat); VIR_ENUM_DECL(virDomainDevice); VIR_ENUM_DECL(virDomainDiskDevice); VIR_ENUM_DECL(virDomainDiskGeometryTrans); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 812fa4e435..72f9e3418f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -303,6 +303,8 @@ virDomainControllerPCIModelNameTypeFromString; virDomainControllerPCIModelNameTypeToString; virDomainControllerRemove; virDomainControllerTypeToString; +virDomainCoreDumpFormatTypeFromString; +virDomainCoreDumpFormatTypeToString; virDomainCpuPlacementModeTypeFromString; virDomainCpuPlacementModeTypeToString; virDomainCryptoBackendTypeFromString; -- 2.43.5

Instead of doing dump in raw format, let's use configurable vm->def->coredumpFormat, which is either way will be raw by default. Signed-off-by: Nikolai Barybin <nikolai.barybin@virtuozzo.com> --- src/qemu/qemu_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6ce949dd07..961e1eb2e8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3470,7 +3470,7 @@ doCoreDumpToAutoDumpPath(virQEMUDriver *driver, flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0; if ((ret = doCoreDump(driver, vm, dumpfile, flags, - VIR_DOMAIN_CORE_DUMP_FORMAT_RAW)) < 0) + vm->def->coredumpFormat)) < 0) virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Dump failed")); return ret; -- 2.43.5

Signed-off-by: Nikolai Barybin <nikolai.barybin@virtuozzo.com> --- docs/formatdomain.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 3be7ee0ff4..edd9762fd4 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -1957,6 +1957,15 @@ The ``on_crash`` event supports these additional actions :since:`since 0.8.4`. The crashed domain's core will be dumped, and then the domain will be restarted with the same configuration +The crashed domain's core format may be specified by ``coredump_format`` element: + ... + <on_crash>coredump-destroy</on_crash> + <coredum_format>raw</coredump_format> + ... + +The possible values are ``raw`` (default), ``kdump-zlib``, ``kdump-lzo``, ``kdump-snappy``, +``win-dmp``. + :since:`Since 3.9.0`, the lifecycle events can be configured via the `virDomainSetLifecycleAction <html/libvirt-libvirt-domain.html#virDomainSetLifecycleAction>`__ API. -- 2.43.5

On 3/27/25 11:14, Nikolai Barybin wrote:
When libvirt processes VM crash event it always dumps core in raw format.
This series makes it possible to configure dump format via domain xml. This would be especcialy helpful for Windows guests, because it requires a lot effort to convert raw dump into wingdb.
Nikolai Barybin (4): conf: schemas: add coredump_format element to events section src: conf: add parsing/formatting for 'coredump_format' value qemu: use configurable dump format in doCoreDumpToAutoDumpPath() docs: formatdomain: document 'coredump_format' element
docs/formatdomain.rst | 9 +++++ src/conf/domain_conf.c | 64 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 + src/conf/schemas/domaincommon.rng | 19 +++++++++ src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 2 +- 6 files changed, 97 insertions(+), 1 deletion(-)
The idea is that correct Windows dump could be collected only at the moment of the dump collection as dump collector code in QEMU uses some information from Windows drivers. Later conversion using external tools proven to be complex. That is why we either should specify the type of the dump inside the configuration file or autoguess the format. I though that latter could be implemented as the next step using f.e. presence of HyperV feature or checking OS type in metadata. I think that this thing would be useful. Den

On Fri, Mar 28, 2025 at 05:45:12PM +0100, Denis V. Lunev via Devel wrote:
On 3/27/25 11:14, Nikolai Barybin wrote:
When libvirt processes VM crash event it always dumps core in raw format.
This series makes it possible to configure dump format via domain xml. This would be especcialy helpful for Windows guests, because it requires a lot effort to convert raw dump into wingdb.
Nikolai Barybin (4): conf: schemas: add coredump_format element to events section src: conf: add parsing/formatting for 'coredump_format' value qemu: use configurable dump format in doCoreDumpToAutoDumpPath() docs: formatdomain: document 'coredump_format' element
docs/formatdomain.rst | 9 +++++ src/conf/domain_conf.c | 64 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 + src/conf/schemas/domaincommon.rng | 19 +++++++++ src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 2 +- 6 files changed, 97 insertions(+), 1 deletion(-)
The idea is that correct Windows dump could be collected only at the moment of the dump collection as dump collector code in QEMU uses some information from Windows drivers. Later conversion using external tools proven to be complex.
That is why we either should specify the type of the dump inside the configuration file or autoguess the format. I though that latter could be implemented as the next step using f.e. presence of HyperV feature or checking OS type in metadata.
I think that this thing would be useful.
Effectively QEMU has three dump formats - WinDump, KDump and ELF, with the KDump format being overloaded to express 6 different sub-variants. The global qemu.conf setting is effectively useless as far as the 'win-dmp' format goes, because it is highly unlikely to have a single host running exclusively windows guests. Anyone know if the KDump format is only interesting for Linux guests, or can it be useful for dumping any guest OS types ? Looking at the QEMU impl, IIUC the WinDump format can only be requested if the guest OS has exposed the Win Dump note in fw_cfg via the vmcoreinfo device, otherwise we'll hit a hard error on the check if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 && s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) { error_setg(errp, "win-dump: invalid vmcoreinfo note size"); return; } This in turn depends on whether the KVM guest drivers are installed in the guest. IOW, we can't auto-choose WinDump merely based on presence of the HyperV fature, nor even libosinfo OS type in metadata. QEMU itself should always knows whether or not it can use WinDump format, as it can see the fw_cfg data, but I can't see any way this is exposed to the mgmt app, but potentially that could be expressed via a new qmp command if needed ? Essentially I'm wondering whether there's any pratical way we can "do the right thing" without manual configuration of each guest ? If it is just a choice between using win-dmp vs the qemu.conf setting it might be doable, assuming the various kdump,elf formats are viable for /all/ guest types. If we needed to auto-detct kdump vs elf it gets harder With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On 4/2/25 12:15, Daniel P. Berrangé wrote:
On Fri, Mar 28, 2025 at 05:45:12PM +0100, Denis V. Lunev via Devel wrote:
On 3/27/25 11:14, Nikolai Barybin wrote:
When libvirt processes VM crash event it always dumps core in raw format.
This series makes it possible to configure dump format via domain xml. This would be especcialy helpful for Windows guests, because it requires a lot effort to convert raw dump into wingdb.
Nikolai Barybin (4): conf: schemas: add coredump_format element to events section src: conf: add parsing/formatting for 'coredump_format' value qemu: use configurable dump format in doCoreDumpToAutoDumpPath() docs: formatdomain: document 'coredump_format' element
docs/formatdomain.rst | 9 +++++ src/conf/domain_conf.c | 64 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 + src/conf/schemas/domaincommon.rng | 19 +++++++++ src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 2 +- 6 files changed, 97 insertions(+), 1 deletion(-)
The idea is that correct Windows dump could be collected only at the moment of the dump collection as dump collector code in QEMU uses some information from Windows drivers. Later conversion using external tools proven to be complex.
That is why we either should specify the type of the dump inside the configuration file or autoguess the format. I though that latter could be implemented as the next step using f.e. presence of HyperV feature or checking OS type in metadata.
I think that this thing would be useful. Effectively QEMU has three dump formats - WinDump, KDump and ELF, with the KDump format being overloaded to express 6 different sub-variants.
The global qemu.conf setting is effectively useless as far as the 'win-dmp' format goes, because it is highly unlikely to have a single host running exclusively windows guests.
Anyone know if the KDump format is only interesting for Linux guests, or can it be useful for dumping any guest OS types ?
Looking at the QEMU impl, IIUC the WinDump format can only be requested if the guest OS has exposed the Win Dump note in fw_cfg via the vmcoreinfo device, otherwise we'll hit a hard error on the check
if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 && s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) { error_setg(errp, "win-dump: invalid vmcoreinfo note size"); return; }
This in turn depends on whether the KVM guest drivers are installed in the guest. IOW, we can't auto-choose WinDump merely based on presence of the HyperV fature, nor even libosinfo OS type in metadata.
QEMU itself should always knows whether or not it can use WinDump format, as it can see the fw_cfg data, but I can't see any way this is exposed to the mgmt app, but potentially that could be expressed via a new qmp command if needed ?
Essentially I'm wondering whether there's any pratical way we can "do the right thing" without manual configuration of each guest ?
If it is just a choice between using win-dmp vs the qemu.conf setting it might be doable, assuming the various kdump,elf formats are viable for /all/ guest types. If we needed to auto-detct kdump vs elf it gets harder
With regards, Daniel
Hello everyone! I didn't clearly get the outcome of previous discussion. Could you clarify whether we plan to review/merge these patches or drop them? Best regards, Nikolai Barybin

On Wed, Apr 02, 2025 at 11:15:41AM +0100, Daniel P. Berrangé via Devel wrote:
QEMU itself should always knows whether or not it can use WinDump format, as it can see the fw_cfg data, but I can't see any way this is exposed to the mgmt app, but potentially that could be expressed via a new qmp command if needed ?
Essentially I'm wondering whether there's any pratical way we can "do the right thing" without manual configuration of each guest ?
So QEMU exposes a QMP command (QEMU) query-dump-guest-memory-capability {"return": {"formats": ["elf", "kdump-zlib", "kdump-raw-zlib", "kdump-lzo", "kdump-raw-lzo", "kdump-snappy", "kdump-raw-snappy", "win-dmp"]}} but this is a lie (QEMU) dump-guest-memory format=win-dmp paging=false protocol=file:foo.dmp {"error": {"class": "GenericError", "desc": "win-dump: invalid vmcoreinfo note size"}} QEMU's impl of 'query-dump-guest-memory-capability' does if (win_dump_available(NULL)) { QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_WIN_DMP); } where win_dump_available is: #if defined(TARGET_X86_64) bool win_dump_available(Error **errp) { return true; } #else bool win_dump_available(Error **errp) { error_setg(errp, "Windows dump is only available for x86-64"); return false; } #endif This is a broken impl IMHO, as it should only report 'win-dump' if the running guest is actually capable of it.
If it is just a choice between using win-dmp vs the qemu.conf setting it might be doable, assuming the various kdump,elf formats are viable for /all/ guest types. If we needed to auto-detct kdump vs elf it gets harder
Assuming we can fix QEMU to accurately report 'win-dump', then we can make libvirt "do the right thing(tm)" out of the box, without needing a per-guest XML knob. ie, if 'win-dump' is reported as available, use that, otherwise use the format configured in qemu.conf. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
participants (3)
-
Daniel P. Berrangé
-
Denis V. Lunev
-
Nikolai Barybin