Hi

On Thu, Sep 11, 2025 at 4:37 PM Nikolai Barybin <
nikolai.bary...@virtuozzo.com> wrote:

> QMP query-dump-guest-memory-capability reports win dump as available for
> any x86 VM, which is false.
>
> This patch implements proper query of vmcoreinfo and calculation of
> guest note size. Based on that we can surely report whether win dump
> available or not.
>
> To perform this I suggest to split dump_init() into dump_preinit() and
> dump_init_complete() to avoid exausting copypaste in
> win_dump_available().
>
> For further reference one may review this libvirt discussion:
>
> https://lists.libvirt.org/archives/list/de...@lists.libvirt.org/thread/HJ3JRLWLGN3IKIC22OQ3PMZ4J3EFG5XB/#HJ3JRLWLGN3IKIC22OQ3PMZ4J3EFG5XB
> [PATCH 0/4] Allow xml-configured coredump format on VM crash
>
> Signed-off-by: Nikolai Barybin <nikolai.bary...@virtuozzo.com>
> Reviewed-by: Daniel P. Berrangé <berra...@redhat.com>
>

Could we split the patch for the generic dump refactoring and then the
windows specifics?


> ---
>  dump/dump.c     | 129 +++++++++++++++++++++++++++---------------------
>  dump/win_dump.c |  23 +++++++--
>  dump/win_dump.h |   2 +-
>  3 files changed, 95 insertions(+), 59 deletions(-)
>
> diff --git a/dump/dump.c b/dump/dump.c
> index b2f7ea7abd..ce8b43f819 100644
> --- a/dump/dump.c
> +++ b/dump/dump.c
> @@ -1780,10 +1780,7 @@ static void vmcoreinfo_update_phys_base(DumpState
> *s)
>      g_strfreev(lines);
>  }
>
> -static void dump_init(DumpState *s, int fd, bool has_format,
> -                      DumpGuestMemoryFormat format, bool paging, bool
> has_filter,
> -                      int64_t begin, int64_t length, bool kdump_raw,
> -                      Error **errp)
> +static void dump_preinit(DumpState *s, Error **errp)
>  {
>      ERRP_GUARD();
>      VMCoreInfoState *vmci = vmcoreinfo_find();
> @@ -1791,16 +1788,6 @@ static void dump_init(DumpState *s, int fd, bool
> has_format,
>      int nr_cpus;
>      int ret;
>
> -    s->has_format = has_format;
> -    s->format = format;
> -    s->written_size = 0;
> -    s->kdump_raw = kdump_raw;
> -
> -    /* kdump-compressed is conflict with paging and filter */
> -    if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
> -        assert(!paging && !has_filter);
> -    }
> -
>      if (runstate_is_running()) {
>          vm_stop(RUN_STATE_SAVE_VM);
>          s->resume = true;
> @@ -1817,41 +1804,10 @@ static void dump_init(DumpState *s, int fd, bool
> has_format,
>          nr_cpus++;
>      }
>
> -    s->fd = fd;
> -    if (has_filter && !length) {
> -        error_setg(errp, "parameter 'length' expects a non-zero size");
> -        goto cleanup;
> -    }
> -    s->filter_area_begin = begin;
> -    s->filter_area_length = length;
> -
> -    /* First index is 0, it's the special null name */
> -    s->string_table_buf = g_array_new(FALSE, TRUE, 1);
> -    /*
> -     * Allocate the null name, due to the clearing option set to true
> -     * it will be 0.
> -     */
> -    g_array_set_size(s->string_table_buf, 1);
> -
>      memory_mapping_list_init(&s->list);
> -
>      guest_phys_blocks_init(&s->guest_phys_blocks);
>      guest_phys_blocks_append(&s->guest_phys_blocks);
> -    s->total_size = dump_calculate_size(s);
> -#ifdef DEBUG_DUMP_GUEST_MEMORY
> -    fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size);
> -#endif
>
> -    /* it does not make sense to dump non-existent memory */
> -    if (!s->total_size) {
> -        error_setg(errp, "dump: no guest memory to dump");
> -        goto cleanup;
> -    }
> -
> -    /* get dump info: endian, class and architecture.
> -     * If the target architecture is not supported, cpu_get_dump_info()
> will
> -     * return -1.
> -     */
>

Why drop that comment?


>      ret = cpu_get_dump_info(&s->dump_info, &s->guest_phys_blocks);
>      if (ret < 0) {
>          error_setg(errp,
> @@ -1909,6 +1865,56 @@ static void dump_init(DumpState *s, int fd, bool
> has_format,
>          }
>      }
>
> +    s->nr_cpus = nr_cpus;
> +    return;
> +cleanup:
> +    dump_cleanup(s);
>

Is it intentional and safe to call dump_cleanup() two times from
qmp_query_dump_guest_memory_capability()? Maybe it should only be called by
the one who allocated/init it, and thus dropped from this function.


> +}
> +
> +static void dump_init_complete(DumpState *s, int fd, bool has_format,
> +                               DumpGuestMemoryFormat format, bool paging,
> +                               bool has_filter, int64_t begin, int64_t
> length,
> +                               bool kdump_raw, Error **errp)
> +{
> +    ERRP_GUARD();
> +
> +    s->has_format = has_format;
> +    s->format = format;
> +    s->written_size = 0;
> +    s->kdump_raw = kdump_raw;
> +
> +    /* kdump-compressed is conflict with paging and filter */
> +    if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
> +        assert(!paging && !has_filter);
> +    }
> +
> +    s->fd = fd;
> +    if (has_filter && !length) {
> +        error_setg(errp, "parameter 'length' expects a non-zero size");
> +        goto cleanup;
> +    }
> +    s->filter_area_begin = begin;
> +    s->filter_area_length = length;
> +
> +    /* First index is 0, it's the special null name */
> +    s->string_table_buf = g_array_new(FALSE, TRUE, 1);
> +    /*
> +     * Allocate the null name, due to the clearing option set to true
> +     * it will be 0.
> +     */
> +    g_array_set_size(s->string_table_buf, 1);
> +
> +    s->total_size = dump_calculate_size(s);
> +#ifdef DEBUG_DUMP_GUEST_MEMORY
> +    fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size);
> +#endif
> +
> +    /* it does not make sense to dump non-existent memory */
> +    if (!s->total_size) {
> +        error_setg(errp, "dump: no guest memory to dump");
> +        goto cleanup;
> +    }
> +
>      /* get memory mapping */
>      if (paging) {
>          qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks,
> errp);
> @@ -1919,8 +1925,6 @@ static void dump_init(DumpState *s, int fd, bool
> has_format,
>          qemu_get_guest_simple_memory_mapping(&s->list,
> &s->guest_phys_blocks);
>      }
>
> -    s->nr_cpus = nr_cpus;
> -
>      get_max_mapnr(s);
>
>      uint64_t tmp;
> @@ -2150,11 +2154,6 @@ void qmp_dump_guest_memory(bool paging, const char
> *protocol,
>      }
>  #endif
>
> -    if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_WIN_DMP
> -        && !win_dump_available(errp)) {
> -        return;
> -    }
> -
>      if (strstart(protocol, "fd:", &p)) {
>          fd = monitor_get_fd(monitor_cur(), p, errp);
>          if (fd == -1) {
> @@ -2193,9 +2192,19 @@ void qmp_dump_guest_memory(bool paging, const char
> *protocol,
>
>
It may be worth adding an ERRP_GUARD since you check *errp.

Why not make dump_preinit() return a bool, true on success, like
recommended by error API docs?



>      s = &dump_state_global;
>      dump_state_prepare(s);
> +    dump_preinit(s, errp);
> +    if (*errp) {
> +        qatomic_set(&s->status, DUMP_STATUS_FAILED);
> +        return;
> +    }
> +
> +    if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_WIN_DMP
> +        && !win_dump_available(s, errp)) {
> +        return;
> +    }
>
> -    dump_init(s, fd, has_format, format, paging, has_begin,
> -              begin, length, kdump_raw, errp);
> +    dump_init_complete(s, fd, has_format, format, paging, has_begin,
> +                       begin, length, kdump_raw, errp);
>      if (*errp) {
>          qatomic_set(&s->status, DUMP_STATUS_FAILED);
>          return;
> @@ -2218,6 +2227,13 @@ DumpGuestMemoryCapability
> *qmp_query_dump_guest_memory_capability(Error **errp)
>                                    g_new0(DumpGuestMemoryCapability, 1);
>      DumpGuestMemoryFormatList **tail = &cap->formats;
>

Same for ERRP_GUARD


>
> +    DumpState *s = g_new0(DumpState, 1);
> +    dump_state_prepare(s);
> +    dump_preinit(s, errp);
> +    if (*errp) {
> +        goto cleanup;
> +    }
> +
>      /* elf is always available */
>      QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_ELF);
>
> @@ -2237,9 +2253,12 @@ DumpGuestMemoryCapability
> *qmp_query_dump_guest_memory_capability(Error **errp)
>      QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_KDUMP_RAW_SNAPPY);
>  #endif
>
> -    if (win_dump_available(NULL)) {
> +    if (win_dump_available(s, NULL)) {
>          QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_WIN_DMP);
>      }
>
> + cleanup:
> +    dump_cleanup(s);
> +    g_free(s);
>      return cap;
>  }
> diff --git a/dump/win_dump.c b/dump/win_dump.c
> index 3162e8bd48..d42427feb2 100644
> --- a/dump/win_dump.c
> +++ b/dump/win_dump.c
> @@ -20,8 +20,25 @@
>
>  #if defined(TARGET_X86_64)
>
> -bool win_dump_available(Error **errp)
> +static bool check_header(WinDumpHeader *h, bool *x64, Error **errp);
> +
> +bool win_dump_available(DumpState *s, Error **errp)
>  {
> +    WinDumpHeader *h = (void *)(s->guest_note +
> VMCOREINFO_ELF_NOTE_HDR_SIZE);
> +    Error *local_err = NULL;
> +    bool x64 = true;
> +
> +    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 false;
> +    }
> +
> +    if (!check_header(h, &x64, &local_err)) {
> +        error_propagate(errp, local_err);
> +        return false;
> +    }

+
>      return true;
>  }
>
> @@ -480,7 +497,7 @@ out_cr3:
>
>  #else /* !TARGET_X86_64 */
>
> -bool win_dump_available(Error **errp)
> +bool win_dump_available(DumpState *s, Error **errp)
>  {
>      error_setg(errp, "Windows dump is only available for x86-64");
>
> @@ -489,7 +506,7 @@ bool win_dump_available(Error **errp)
>
>  void create_win_dump(DumpState *s, Error **errp)
>  {
> -    win_dump_available(errp);
> +    win_dump_available(s, errp);
>  }
>
>  #endif
> diff --git a/dump/win_dump.h b/dump/win_dump.h
> index 9d6cfa47c5..62e19c2527 100644
> --- a/dump/win_dump.h
> +++ b/dump/win_dump.h
> @@ -14,7 +14,7 @@
>  #include "system/dump.h"
>
>  /* Check Windows dump availability for the current target */
> -bool win_dump_available(Error **errp);
> +bool win_dump_available(DumpState *s, Error **errp);
>
>  void create_win_dump(DumpState *s, Error **errp);
>
> --
> 2.43.5
>


Sadly we still don't have much testing for dump..

thanks

Reply via email to