* [GIT PULL 0/8] Dump patches for 2026-06-30
@ 2026-06-30 15:13 Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 1/8] migration: add migration_guest_ram_loading() helper Marc-André Lureau
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
The following changes since commit 30e8a06b64aa58a3990ba39cb5d09531e7d265e0:
Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging (2026-06-29 17:41:42 +0200)
are available in the Git repository at:
https://gitlab.com/marcandre.lureau/qemu.git tags/dump-pr-v1
for you to fetch changes up to 89f7c15e628147edd1cae5214827c8175e8fabd1:
dump: fix misleading VMCOREINFO phys_base parse error (2026-06-30 19:12:59 +0400)
----------------------------------------------------------------
Dump patches for 2026-06-30
To: qemu-devel@nongnu.org
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
----------------------------------------------------------------
Denis V. Lunev (7):
migration: add migration_guest_ram_loading() helper
dump: refuse dump-guest-memory while guest RAM is being migrated
system/cpus: refuse memsave/pmemsave while guest RAM is being migrated
dump: make win_dump_available() check vmcoreinfo for a Windows dump header
tests/qtest: add dump-guest-memory test
tests/qtest/dump: reject win-dmp without vmcoreinfo
tests/qtest/dump: cover win-dmp availability via vmcoreinfo
yujun (1):
dump: fix misleading VMCOREINFO phys_base parse error
MAINTAINERS | 1 +
include/migration/misc.h | 3 +
dump/dump.c | 8 +-
dump/win_dump-x86.c | 49 ++++++-
migration/migration.c | 6 +
system/cpus.c | 11 ++
tests/qtest/dump-test.c | 331 +++++++++++++++++++++++++++++++++++++++++++++++
tests/qtest/meson.build | 1 +
8 files changed, 402 insertions(+), 8 deletions(-)
create mode 100644 tests/qtest/dump-test.c
^ permalink raw reply [flat|nested] 10+ messages in thread
* [GIT PULL 1/8] migration: add migration_guest_ram_loading() helper
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
@ 2026-06-30 15:13 ` Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 2/8] dump: refuse dump-guest-memory while guest RAM is being migrated Marc-André Lureau
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
From: "Denis V. Lunev" <den@openvz.org>
Operations that read guest RAM (dump-guest-memory, memsave, pmemsave)
must refuse to run while the destination of a migration is still
receiving that RAM: during precopy it is incomplete, and during postcopy
a read faults the page in from the source. Provide a single predicate
they can share instead of open-coding the runstate and postcopy checks.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260619101834.228432-2-den@openvz.org>
---
include/migration/misc.h | 3 +++
migration/migration.c | 6 ++++++
2 files changed, 9 insertions(+)
diff --git a/include/migration/misc.h b/include/migration/misc.h
index 3159a5e53c3..d3d6e1f50d1 100644
--- a/include/migration/misc.h
+++ b/include/migration/misc.h
@@ -117,6 +117,9 @@ void migration_file_set_error(int ret, Error *err);
/* True if incoming migration entered POSTCOPY_INCOMING_DISCARD */
bool migration_in_incoming_postcopy(void);
+/* True while the destination still receives guest RAM (precopy or postcopy) */
+bool migration_guest_ram_loading(void);
+
/* True if incoming migration entered POSTCOPY_INCOMING_ADVISE */
bool migration_incoming_postcopy_advised(void);
diff --git a/migration/migration.c b/migration/migration.c
index 278cad502ae..0f56432d903 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1643,6 +1643,12 @@ bool migration_in_incoming_postcopy(void)
return ps >= POSTCOPY_INCOMING_DISCARD && ps < POSTCOPY_INCOMING_END;
}
+bool migration_guest_ram_loading(void)
+{
+ return runstate_check(RUN_STATE_INMIGRATE) ||
+ migration_in_incoming_postcopy();
+}
+
bool migration_incoming_postcopy_advised(void)
{
PostcopyState ps = postcopy_state_get();
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [GIT PULL 2/8] dump: refuse dump-guest-memory while guest RAM is being migrated
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 1/8] migration: add migration_guest_ram_loading() helper Marc-André Lureau
@ 2026-06-30 15:13 ` Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 3/8] system/cpus: refuse memsave/pmemsave " Marc-André Lureau
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
From: "Denis V. Lunev" <den@openvz.org>
dump-guest-memory reads all of guest RAM. The existing guard only rejects
the dump in RUN_STATE_INMIGRATE, i.e. the precopy load phase. On a
postcopy destination the guest already runs (RUN_STATE_RUNNING) while its
pages are pulled from the source on demand.
A non-detached dump reads that RAM on the main thread with the BQL held.
Touching a not-yet-received page blocks on the userfault, and because the
postcopy incoming path itself takes the BQL to install pages, the
transfer that would satisfy the fault cannot progress: the VM deadlocks.
Use migration_guest_ram_loading(), which also covers postcopy, so the
dump is refused for the whole time the destination is still receiving
guest RAM.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260619101834.228432-3-den@openvz.org>
---
dump/dump.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dump/dump.c b/dump/dump.c
index eb2ee1c10df..7fa2d6f788c 100644
--- a/dump/dump.c
+++ b/dump/dump.c
@@ -30,6 +30,7 @@
#include "qemu/main-loop.h"
#include "hw/misc/vmcoreinfo.h"
#include "migration/blocker.h"
+#include "migration/misc.h"
#include "hw/core/cpu.h"
#include "win_dump.h"
#include "qemu/range.h"
@@ -2080,8 +2081,8 @@ void qmp_dump_guest_memory(bool paging, const char *protocol,
bool detach_p = false;
bool kdump_raw = false;
- if (runstate_check(RUN_STATE_INMIGRATE)) {
- error_setg(errp, "Dump not allowed during incoming migration.");
+ if (migration_guest_ram_loading()) {
+ error_setg(errp, "Dump not allowed during migration.");
return;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [GIT PULL 3/8] system/cpus: refuse memsave/pmemsave while guest RAM is being migrated
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 1/8] migration: add migration_guest_ram_loading() helper Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 2/8] dump: refuse dump-guest-memory while guest RAM is being migrated Marc-André Lureau
@ 2026-06-30 15:13 ` Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 4/8] dump: make win_dump_available() check vmcoreinfo for a Windows dump header Marc-André Lureau
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
From: "Denis V. Lunev" <den@openvz.org>
memsave and pmemsave read guest memory and write it to a file, with no
guard at all. They run on the main thread with the BQL held, so on a
postcopy destination touching a not-yet-received page deadlocks: the
thread blocks on the userfault while the postcopy incoming path waits for
the BQL to install that page. During precopy the read returns incomplete
state instead.
Refuse both while guest RAM is still being received, using the same
migration_guest_ram_loading() check as dump-guest-memory.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260619101834.228432-4-den@openvz.org>
---
system/cpus.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/system/cpus.c b/system/cpus.c
index 49f6daec3cd..b31c825b464 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -43,6 +43,7 @@
#include "system/physmem.h"
#include "system/replay.h"
#include "system/runstate.h"
+#include "migration/misc.h"
#include "system/cpu-timers.h"
#include "system/whpx.h"
#include "hw/core/boards.h"
@@ -843,6 +844,11 @@ void qmp_memsave(uint64_t addr, uint64_t size, const char *filename,
uint8_t buf[1024];
uint64_t orig_addr = addr, orig_size = size;
+ if (migration_guest_ram_loading()) {
+ error_setg(errp, "Guest memory access not allowed during migration");
+ return;
+ }
+
if (!has_cpu) {
cpu_index = 0;
}
@@ -889,6 +895,11 @@ void qmp_pmemsave(uint64_t addr, uint64_t size, const char *filename,
uint64_t l;
uint8_t buf[1024];
+ if (migration_guest_ram_loading()) {
+ error_setg(errp, "Guest memory access not allowed during migration");
+ return;
+ }
+
f = fopen(filename, "wb");
if (!f) {
error_setg_file_open(errp, errno, filename);
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [GIT PULL 4/8] dump: make win_dump_available() check vmcoreinfo for a Windows dump header
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
` (2 preceding siblings ...)
2026-06-30 15:13 ` [GIT PULL 3/8] system/cpus: refuse memsave/pmemsave " Marc-André Lureau
@ 2026-06-30 15:13 ` Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 5/8] tests/qtest: add dump-guest-memory test Marc-André Lureau
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
From: "Denis V. Lunev" <den@openvz.org>
QMP query-dump-guest-memory-capability reports win-dmp as available for
any x86 VM, and dump-guest-memory accepts the win-dmp format
unconditionally. Both are wrong: win-dmp only works when the guest has
published a Windows dump header through vmcoreinfo.
The guest registers that note with the vmcoreinfo device (its physical
address and size), so win_dump_available() can read it back directly and
validate the note size and the Windows dump header signature. This needs
no other guest state, so it does not stop the vCPUs.
The capability query reads the note on the main thread with the BQL held
and has no migration guard of its own, so it is skipped while a migration
destination is still receiving guest RAM: there the read would deadlock
against the postcopy load (which needs the BQL) or, in precopy, see
incomplete pages.
Based on the original work of Nikolai Barybin.
Signed-off-by: Denis V. Lunev <den@openvz.org>
[ MA - changed physical_memory_read() call ]
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260619101834.228432-5-den@openvz.org>
---
dump/win_dump-x86.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 44 insertions(+), 5 deletions(-)
diff --git a/dump/win_dump-x86.c b/dump/win_dump-x86.c
index 8848c8bfca3..0dd0c503c56 100644
--- a/dump/win_dump-x86.c
+++ b/dump/win_dump-x86.c
@@ -18,11 +18,10 @@
#include "qemu/win_dump_defs.h"
#include "win_dump.h"
#include "cpu.h"
-
-bool win_dump_available(Error **errp)
-{
- return true;
-}
+#include "qemu/bswap.h"
+#include "hw/misc/vmcoreinfo.h"
+#include "migration/misc.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
static size_t win_dump_ptr_size(bool x64)
{
@@ -404,6 +403,46 @@ static void restore_context(WinDumpHeader *h, bool x64,
}
}
+bool win_dump_available(Error **errp)
+{
+ VMCoreInfoState *vmci = vmcoreinfo_find();
+ g_autofree uint8_t *note = NULL;
+ Error *local_err = NULL;
+ WinDumpHeader *h;
+ uint32_t size;
+ bool x64 = true;
+
+ if (migration_guest_ram_loading()) {
+ error_setg(errp, "win-dump: not available during migration");
+ return false;
+ }
+
+ if (!vmci || !vmci->has_vmcoreinfo ||
+ le16_to_cpu(vmci->vmcoreinfo.guest_format) !=
+ FW_CFG_VMCOREINFO_FORMAT_ELF) {
+ error_setg(errp, "win-dump: no vmcoreinfo note from the guest");
+ return false;
+ }
+
+ size = le32_to_cpu(vmci->vmcoreinfo.size);
+ if (size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 &&
+ size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) {
+ error_setg(errp, "win-dump: invalid vmcoreinfo note size");
+ return false;
+ }
+
+ note = g_malloc(size);
+ physical_memory_read(le64_to_cpu(vmci->vmcoreinfo.paddr), note, size);
+
+ h = (void *)(note + VMCOREINFO_ELF_NOTE_HDR_SIZE);
+ if (!check_header(h, &x64, &local_err)) {
+ error_propagate(errp, local_err);
+ return false;
+ }
+
+ return true;
+}
+
void create_win_dump(DumpState *s, Error **errp)
{
WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE);
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [GIT PULL 5/8] tests/qtest: add dump-guest-memory test
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
` (3 preceding siblings ...)
2026-06-30 15:13 ` [GIT PULL 4/8] dump: make win_dump_available() check vmcoreinfo for a Windows dump header Marc-André Lureau
@ 2026-06-30 15:13 ` Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 6/8] tests/qtest/dump: reject win-dmp without vmcoreinfo Marc-André Lureau
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
From: "Denis V. Lunev" <den@openvz.org>
There is currently almost no coverage for the dump-guest-memory QMP
command beyond the test-hmp smoke test. Add a qtest that runs on a bare
machine (no guest OS) and checks:
- query-dump-guest-memory-capability always advertises 'elf';
- an ELF dump is produced and starts with the ELF magic;
- a non-raw kdump dump is emitted in makedumpfile flattened format;
- a raw kdump dump starts with the on-disk KDUMP header;
- an unknown protocol is rejected without killing the VM, and dumping
still works afterwards.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260619101834.228432-6-den@openvz.org>
---
MAINTAINERS | 1 +
tests/qtest/dump-test.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/qtest/meson.build | 1 +
3 files changed, 190 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 2ecfd7159db..7ff0ae09cdc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3309,6 +3309,7 @@ F: scripts/dump-guest-memory.py
F: stubs/dump.c
F: docs/specs/vmcoreinfo.rst
F: tests/qtest/vmcoreinfo-test.c
+F: tests/qtest/dump-test.c
Error reporting
M: Markus Armbruster <armbru@redhat.com>
diff --git a/tests/qtest/dump-test.c b/tests/qtest/dump-test.c
new file mode 100644
index 00000000000..eb188c9ccb8
--- /dev/null
+++ b/tests/qtest/dump-test.c
@@ -0,0 +1,188 @@
+/*
+ * QTest testcase for dump-guest-memory
+ *
+ * Generic coverage for the dump-guest-memory QMP command and the
+ * query-dump-guest-memory-capability reporting, exercised on a bare
+ * machine (no guest OS required).
+ *
+ * Copyright (c) 2026 Virtuozzo International GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qobject/qdict.h"
+#include "qobject/qlist.h"
+#include "qobject/qstring.h"
+#include "qemu/bswap.h"
+#include "elf.h"
+
+#define KDUMP_RAW_MAGIC "KDUMP "
+#define KDUMP_FLAT_MAGIC "makedumpfile"
+
+static QTestState *dump_test_start(void)
+{
+ return qtest_initf("-machine q35 -accel qtest -m 16");
+}
+
+static void assert_file_magic(const char *path, const char *magic, size_t len)
+{
+ g_autofree char *buf = g_malloc0(len);
+ FILE *f = fopen(path, "rb");
+
+ g_assert_nonnull(f);
+ g_assert_cmpint(fread(buf, 1, len, f), ==, len);
+ fclose(f);
+ g_assert_cmpint(memcmp(buf, magic, len), ==, 0);
+}
+
+/* validate that the file is a sane x86 ELF core, not just the leading magic */
+static void assert_valid_elf_core(const char *path)
+{
+ unsigned char e[64];
+ FILE *f = fopen(path, "rb");
+ uint16_t e_type, e_machine, e_phnum;
+
+ g_assert_nonnull(f);
+ g_assert_cmpint(fread(e, 1, sizeof(e), f), ==, sizeof(e));
+ fclose(f);
+
+ g_assert_cmpint(memcmp(e, ELFMAG, SELFMAG), ==, 0);
+
+ /* e_type and e_machine sit at the same offset for ELF32 and ELF64 */
+ e_type = lduw_le_p(e + 16);
+ e_machine = lduw_le_p(e + 18);
+ g_assert_cmpint(e_type, ==, ET_CORE);
+ g_assert(e_machine == EM_386 || e_machine == EM_X86_64);
+
+ /* e_phnum lives at a class-dependent offset */
+ if (e[EI_CLASS] == ELFCLASS64) {
+ e_phnum = lduw_le_p(e + 56);
+ } else {
+ e_phnum = lduw_le_p(e + 44);
+ }
+ g_assert_cmpint(e_phnum, >, 0);
+}
+
+/* dump-guest-memory to a fresh temp file; returns the path (caller frees) */
+static char *do_dump(QTestState *qts, const char *format)
+{
+ g_autofree char *tmp = NULL;
+ g_autofree char *proto = NULL;
+ GError *err = NULL;
+ int fd;
+
+ fd = g_file_open_tmp("dump-test-XXXXXX", &tmp, &err);
+ g_assert_no_error(err);
+ close(fd);
+ proto = g_strdup_printf("file:%s", tmp);
+
+ if (format) {
+ qtest_qmp_assert_success(qts,
+ "{ 'execute': 'dump-guest-memory',"
+ " 'arguments': { 'paging': false, 'protocol': %s,"
+ " 'format': %s } }", proto, format);
+ } else {
+ qtest_qmp_assert_success(qts,
+ "{ 'execute': 'dump-guest-memory',"
+ " 'arguments': { 'paging': false, 'protocol': %s } }", proto);
+ }
+
+ return g_steal_pointer(&tmp);
+}
+
+/* query-dump-guest-memory-capability must always advertise at least 'elf' */
+static void test_query_capability(void)
+{
+ QTestState *qts = dump_test_start();
+ QDict *resp, *ret;
+ QList *formats;
+ QListEntry *e;
+ bool has_elf = false;
+
+ resp = qtest_qmp(qts,
+ "{ 'execute': 'query-dump-guest-memory-capability' }");
+ g_assert(qdict_haskey(resp, "return"));
+ ret = qdict_get_qdict(resp, "return");
+ formats = qdict_get_qlist(ret, "formats");
+ g_assert_nonnull(formats);
+
+ QLIST_FOREACH_ENTRY(formats, e) {
+ QString *qs = qobject_to(QString, qlist_entry_obj(e));
+
+ if (g_str_equal(qstring_get_str(qs), "elf")) {
+ has_elf = true;
+ }
+ }
+ g_assert_true(has_elf);
+
+ qobject_unref(resp);
+ qtest_quit(qts);
+}
+
+static void test_dump_elf(void)
+{
+ QTestState *qts = dump_test_start();
+ g_autofree char *path = do_dump(qts, NULL);
+
+ assert_valid_elf_core(path);
+ unlink(path);
+ qtest_quit(qts);
+}
+
+/* non-raw kdump is emitted in makedumpfile flattened format */
+static void test_dump_kdump_zlib(void)
+{
+ QTestState *qts = dump_test_start();
+ g_autofree char *path = do_dump(qts, "kdump-zlib");
+
+ assert_file_magic(path, KDUMP_FLAT_MAGIC, strlen(KDUMP_FLAT_MAGIC));
+ unlink(path);
+ qtest_quit(qts);
+}
+
+/* raw kdump starts with the on-disk KDUMP header */
+static void test_dump_kdump_raw_zlib(void)
+{
+ QTestState *qts = dump_test_start();
+ g_autofree char *path = do_dump(qts, "kdump-raw-zlib");
+
+ assert_file_magic(path, KDUMP_RAW_MAGIC, strlen(KDUMP_RAW_MAGIC));
+ unlink(path);
+ qtest_quit(qts);
+}
+
+/* an unknown protocol must be rejected, not crash the VM */
+static void test_dump_invalid_protocol(void)
+{
+ QTestState *qts = dump_test_start();
+ g_autofree char *path = NULL;
+ QDict *resp;
+
+ resp = qtest_qmp(qts,
+ "{ 'execute': 'dump-guest-memory',"
+ " 'arguments': { 'paging': false, 'protocol': 'bogus:/x' } }");
+ g_assert(qdict_haskey(resp, "error"));
+ qobject_unref(resp);
+
+ /* VM is still alive and dumping still works afterwards */
+ path = do_dump(qts, NULL);
+ assert_valid_elf_core(path);
+ unlink(path);
+
+ qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/dump/query-capability", test_query_capability);
+ qtest_add_func("/dump/elf", test_dump_elf);
+ qtest_add_func("/dump/kdump-zlib", test_dump_kdump_zlib);
+ qtest_add_func("/dump/kdump-raw-zlib", test_dump_kdump_raw_zlib);
+ qtest_add_func("/dump/invalid-protocol", test_dump_invalid_protocol);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 822e0bd2869..84062028f9c 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -59,6 +59,7 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_FDC_ISA') ? ['fdc-test'] : []) + \
(config_all_devices.has_key('CONFIG_I440FX') ? ['fw_cfg-test'] : []) + \
(config_all_devices.has_key('CONFIG_FW_CFG_DMA') ? ['vmcoreinfo-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_Q35') ? ['dump-test'] : []) + \
(config_all_devices.has_key('CONFIG_I440FX') ? ['i440fx-test'] : []) + \
(config_all_devices.has_key('CONFIG_I440FX') ? ['ide-test'] : []) + \
(config_all_devices.has_key('CONFIG_I440FX') ? ['numa-test'] : []) + \
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [GIT PULL 6/8] tests/qtest/dump: reject win-dmp without vmcoreinfo
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
` (4 preceding siblings ...)
2026-06-30 15:13 ` [GIT PULL 5/8] tests/qtest: add dump-guest-memory test Marc-André Lureau
@ 2026-06-30 15:13 ` Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 7/8] tests/qtest/dump: cover win-dmp availability via vmcoreinfo Marc-André Lureau
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
From: "Denis V. Lunev" <den@openvz.org>
Requesting the Windows crashdump format (win-dmp) on a guest that does not
expose a Windows dump header through vmcoreinfo must be rejected, not
silently turned into a bogus dump. Add a test that asks for win-dmp on a
plain VM and checks the request fails with "invalid vmcoreinfo note size"
and that the VM stays usable afterwards (a subsequent ELF dump succeeds).
The test is x86_64 only, where win_dump_available() performs this check.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260619101834.228432-7-den@openvz.org>
---
tests/qtest/dump-test.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/tests/qtest/dump-test.c b/tests/qtest/dump-test.c
index eb188c9ccb8..6afaa2c2ea4 100644
--- a/tests/qtest/dump-test.c
+++ b/tests/qtest/dump-test.c
@@ -174,8 +174,51 @@ static void test_dump_invalid_protocol(void)
qtest_quit(qts);
}
+/*
+ * Requesting win-dmp without a Windows dump header in vmcoreinfo must be
+ * rejected with a clear error -- and must leave the VM usable, rather than
+ * produce a bogus dump.
+ */
+static void test_dump_win_dmp_unavailable(void)
+{
+ QTestState *qts = dump_test_start();
+ g_autofree char *tmp = NULL;
+ g_autofree char *proto = NULL;
+ g_autofree char *path = NULL;
+ GError *err = NULL;
+ QDict *resp, *error;
+ const char *desc;
+ int fd;
+
+ fd = g_file_open_tmp("dump-test-XXXXXX", &tmp, &err);
+ g_assert_no_error(err);
+ close(fd);
+ proto = g_strdup_printf("file:%s", tmp);
+
+ resp = qtest_qmp(qts,
+ "{ 'execute': 'dump-guest-memory',"
+ " 'arguments': { 'paging': false, 'protocol': %s,"
+ " 'format': 'win-dmp' } }", proto);
+ error = qdict_get_qdict(resp, "error");
+ g_assert_nonnull(error);
+ desc = qdict_get_try_str(error, "desc");
+ g_assert_nonnull(desc);
+ g_assert_nonnull(strstr(desc, "vmcoreinfo"));
+ qobject_unref(resp);
+ unlink(tmp);
+
+ /* the failed request must not wedge the VM: a plain dump still works */
+ path = do_dump(qts, NULL);
+ assert_valid_elf_core(path);
+ unlink(path);
+
+ qtest_quit(qts);
+}
+
int main(int argc, char **argv)
{
+ const char *arch = qtest_get_arch();
+
g_test_init(&argc, &argv, NULL);
qtest_add_func("/dump/query-capability", test_query_capability);
@@ -184,5 +227,11 @@ int main(int argc, char **argv)
qtest_add_func("/dump/kdump-raw-zlib", test_dump_kdump_raw_zlib);
qtest_add_func("/dump/invalid-protocol", test_dump_invalid_protocol);
+ /* win-dmp is an x86_64-only format */
+ if (g_str_equal(arch, "x86_64")) {
+ qtest_add_func("/dump/win-dmp-unavailable",
+ test_dump_win_dmp_unavailable);
+ }
+
return g_test_run();
}
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [GIT PULL 7/8] tests/qtest/dump: cover win-dmp availability via vmcoreinfo
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
` (5 preceding siblings ...)
2026-06-30 15:13 ` [GIT PULL 6/8] tests/qtest/dump: reject win-dmp without vmcoreinfo Marc-André Lureau
@ 2026-06-30 15:13 ` Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 8/8] dump: fix misleading VMCOREINFO phys_base parse error Marc-André Lureau
2026-07-02 18:49 ` [GIT PULL 0/8] Dump patches for 2026-06-30 Stefan Hajnoczi
8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
From: "Denis V. Lunev" <den@openvz.org>
win-dmp becomes available only once the guest exposes a Windows dump
header through vmcoreinfo. Forge exactly such a note (an ELF note
header followed by a WinDumpHeader64 carrying the PAGE/DU64
signatures, the layout a Windows guest with the QEMU vmcoreinfo writer
produces), place it in guest RAM, point the vmcoreinfo device at it via
fw_cfg, and check that win-dmp flips from unavailable to available.
This exercises win_dump_available()'s positive path without a real
Windows guest. It only covers availability reporting; the actual
win-dmp generation (create_win_dump()) needs real Windows kernel
structures and is not exercised here.
The test is registered only on x86_64 with a vmcoreinfo device present.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260619101834.228432-8-den@openvz.org>
---
tests/qtest/dump-test.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)
diff --git a/tests/qtest/dump-test.c b/tests/qtest/dump-test.c
index 6afaa2c2ea4..30c95a35285 100644
--- a/tests/qtest/dump-test.c
+++ b/tests/qtest/dump-test.c
@@ -12,10 +12,15 @@
#include "qemu/osdep.h"
#include "libqtest.h"
+#include "libqos/libqos-pc.h"
+#include "libqos/fw_cfg.h"
#include "qobject/qdict.h"
#include "qobject/qlist.h"
#include "qobject/qstring.h"
#include "qemu/bswap.h"
+#include "qemu/win_dump_defs.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
+#include "hw/misc/vmcoreinfo.h"
#include "elf.h"
#define KDUMP_RAW_MAGIC "KDUMP "
@@ -215,6 +220,90 @@ static void test_dump_win_dmp_unavailable(void)
qtest_quit(qts);
}
+static bool capability_has_format(QTestState *qts, const char *want)
+{
+ QDict *resp, *ret;
+ QList *formats;
+ QListEntry *e;
+ bool found = false;
+
+ resp = qtest_qmp(qts,
+ "{ 'execute': 'query-dump-guest-memory-capability' }");
+ g_assert(qdict_haskey(resp, "return"));
+ ret = qdict_get_qdict(resp, "return");
+ formats = qdict_get_qlist(ret, "formats");
+ g_assert_nonnull(formats);
+
+ QLIST_FOREACH_ENTRY(formats, e) {
+ QString *qs = qobject_to(QString, qlist_entry_obj(e));
+
+ if (g_str_equal(qstring_get_str(qs), want)) {
+ found = true;
+ }
+ }
+ qobject_unref(resp);
+ return found;
+}
+
+/*
+ * win-dmp becomes available only once the guest exposes a Windows dump
+ * header through vmcoreinfo. Forge exactly such a note -- the layout a
+ * Windows guest with the QEMU vmcoreinfo writer produces: a fixed-size ELF
+ * note header followed by a WinDumpHeader64 carrying the PAGE/DU64
+ * signatures -- place it in guest RAM, point the vmcoreinfo device at it
+ * via fw_cfg, and check that win-dmp flips from unavailable to available.
+ *
+ * This only covers availability *reporting*; the actual win-dmp generation
+ * (create_win_dump()) needs real Windows kernel structures and is not
+ * exercised here.
+ */
+static void test_dump_win_dmp_available(void)
+{
+ const uint64_t paddr = 0x800000; /* 8 MiB, inside guest RAM */
+ size_t notesz = VMCOREINFO_WIN_DUMP_NOTE_SIZE64;
+ g_autofree uint8_t *note = g_malloc0(notesz);
+ Elf64_Nhdr *nhdr = (Elf64_Nhdr *)note;
+ WinDumpHeader64 *hdr;
+ FWCfgVMCoreInfo info;
+ QFWCFG *fw_cfg;
+ QOSState *qs;
+
+ /* the WinDumpHeader64 must sit right after the fixed ELF note header */
+ g_assert_cmpint(sizeof(WinDumpHeader64) % 4, ==, 0);
+
+ nhdr->n_namesz = cpu_to_le32(sizeof("VMCOREINFO")); /* 11 -> padded 12 */
+ nhdr->n_descsz = cpu_to_le32(sizeof(WinDumpHeader64));
+ nhdr->n_type = 0;
+ memcpy(note + sizeof(Elf64_Nhdr), "VMCOREINFO", sizeof("VMCOREINFO") - 1);
+
+ hdr = (WinDumpHeader64 *)(note + VMCOREINFO_ELF_NOTE_HDR_SIZE);
+ memcpy(hdr->Signature, "PAGE", sizeof(hdr->Signature));
+ memcpy(hdr->ValidDump, "DU64", sizeof(hdr->ValidDump));
+
+ qs = qtest_pc_boot("-device vmcoreinfo -m 16");
+ fw_cfg = pc_fw_cfg_init(qs->qts);
+
+ /* with no guest note yet, win-dmp must not be advertised */
+ g_assert_false(capability_has_format(qs->qts, "win-dmp"));
+
+ /* place the forged note in guest RAM and point vmcoreinfo at it */
+ qtest_memwrite(qs->qts, paddr, note, notesz);
+
+ memset(&info, 0, sizeof(info));
+ info.host_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF);
+ info.guest_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF);
+ info.size = cpu_to_le32(notesz);
+ info.paddr = cpu_to_le64(paddr);
+ qfw_cfg_write_file(fw_cfg, qs, FW_CFG_VMCOREINFO_FILENAME,
+ &info, sizeof(info));
+
+ /* now win-dmp must be reported as available */
+ g_assert_true(capability_has_format(qs->qts, "win-dmp"));
+
+ pc_fw_cfg_uninit(fw_cfg);
+ qtest_shutdown(qs);
+}
+
int main(int argc, char **argv)
{
const char *arch = qtest_get_arch();
@@ -231,6 +320,11 @@ int main(int argc, char **argv)
if (g_str_equal(arch, "x86_64")) {
qtest_add_func("/dump/win-dmp-unavailable",
test_dump_win_dmp_unavailable);
+
+ if (qtest_has_device("vmcoreinfo")) {
+ qtest_add_func("/dump/win-dmp-available",
+ test_dump_win_dmp_available);
+ }
}
return g_test_run();
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [GIT PULL 8/8] dump: fix misleading VMCOREINFO phys_base parse error
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
` (6 preceding siblings ...)
2026-06-30 15:13 ` [GIT PULL 7/8] tests/qtest/dump: cover win-dmp availability via vmcoreinfo Marc-André Lureau
@ 2026-06-30 15:13 ` Marc-André Lureau
2026-07-02 18:49 ` [GIT PULL 0/8] Dump patches for 2026-06-30 Stefan Hajnoczi
8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2026-06-30 15:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Stefan Hajnoczi
From: yujun <yujun@kylinos.cn>
When qemu_strtou64() fails on the value after NUMBER(phys_base)= or
NUMBER(PHYS_OFFSET)=, report a parse failure and include the malformed
value. The previous message suggested the field name itself could not
be read.
Fixes: d9feb51772 ("dump: update phys_base header field based on VMCOREINFO content")
Signed-off-by: yujun <yujun@kylinos.cn>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260629114646.288664-1-yujun@kylinos.cn>
---
dump/dump.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dump/dump.c b/dump/dump.c
index 7fa2d6f788c..52be7258a5d 100644
--- a/dump/dump.c
+++ b/dump/dump.c
@@ -1772,7 +1772,8 @@ static void vmcoreinfo_update_phys_base(DumpState *s)
if (prefix && g_str_has_prefix(lines[i], prefix)) {
if (qemu_strtou64(lines[i] + strlen(prefix), NULL, 16,
&phys_base) < 0) {
- warn_report("Failed to read %s", prefix);
+ warn_report("failed to parse %s in VMCOREINFO: '%s'",
+ prefix, lines[i] + strlen(prefix));
} else {
s->dump_info.phys_base = phys_base;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [GIT PULL 0/8] Dump patches for 2026-06-30
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
` (7 preceding siblings ...)
2026-06-30 15:13 ` [GIT PULL 8/8] dump: fix misleading VMCOREINFO phys_base parse error Marc-André Lureau
@ 2026-07-02 18:49 ` Stefan Hajnoczi
8 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2026-07-02 18:49 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, Stefan Hajnoczi
[-- Attachment #1: Type: text/plain, Size: 116 bytes --]
Applied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-03 5:01 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-30 15:13 [GIT PULL 0/8] Dump patches for 2026-06-30 Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 1/8] migration: add migration_guest_ram_loading() helper Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 2/8] dump: refuse dump-guest-memory while guest RAM is being migrated Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 3/8] system/cpus: refuse memsave/pmemsave " Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 4/8] dump: make win_dump_available() check vmcoreinfo for a Windows dump header Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 5/8] tests/qtest: add dump-guest-memory test Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 6/8] tests/qtest/dump: reject win-dmp without vmcoreinfo Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 7/8] tests/qtest/dump: cover win-dmp availability via vmcoreinfo Marc-André Lureau
2026-06-30 15:13 ` [GIT PULL 8/8] dump: fix misleading VMCOREINFO phys_base parse error Marc-André Lureau
2026-07-02 18:49 ` [GIT PULL 0/8] Dump patches for 2026-06-30 Stefan Hajnoczi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.