Hi Nikolai

On Wed, Sep 24, 2025 at 12:30 PM Marc-André Lureau
<[email protected]> wrote:
>
> Hi
>
> On Thu, Sep 11, 2025 at 4:37 PM Nikolai Barybin 
> <[email protected]> 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/[email protected]/thread/HJ3JRLWLGN3IKIC22OQ3PMZ4J3EFG5XB/#HJ3JRLWLGN3IKIC22OQ3PMZ4J3EFG5XB
>> [PATCH 0/4] Allow xml-configured coredump format on VM crash
>>
>> Signed-off-by: Nikolai Barybin <[email protected]>
>> Reviewed-by: Daniel P. Berrangé <[email protected]>
>
>

Have you looked at my review & updated the patches? thanks

> 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



-- 
Marc-André Lureau

Reply via email to