Commit b53ccc30 authored by qiaonuohan's avatar qiaonuohan Committed by Luiz Capitulino
Browse files

dump: make kdump-compressed format available for 'dump-guest-memory'



Make monitor command 'dump-guest-memory' be able to dump in kdump-compressed
format. The command's usage:

  dump [-p] protocol [begin] [length] [format]

'format' is used to specified the format of vmcore and can be:
1. 'elf': ELF format, without compression
2. 'kdump-zlib': kdump-compressed format, with zlib-compressed
3. 'kdump-lzo': kdump-compressed format, with lzo-compressed
4. 'kdump-snappy': kdump-compressed format, with snappy-compressed
Without 'format' being set, it is same as 'elf'. And if non-elf format is
specified, paging and filter is not allowed.

Note:
  1. The kdump-compressed format is readable only with the crash utility and
     makedumpfile, and it can be smaller than the ELF format because of the
     compression support.
  2. The kdump-compressed format is the 6th edition.

Signed-off-by: default avatarQiao Nuohan <qiaonuohan@cn.fujitsu.com>
Reviewed-by: default avatarLaszlo Ersek <lersek@redhat.com>
Signed-off-by: default avatarLuiz Capitulino <lcapitulino@redhat.com>
parent d12f57ec
Loading
Loading
Loading
Loading
+125 −6
Original line number Diff line number Diff line
@@ -1443,6 +1443,64 @@ out:
    return ret;
}

static int create_kdump_vmcore(DumpState *s)
{
    int ret;

    /*
     * the kdump-compressed format is:
     *                                               File offset
     *  +------------------------------------------+ 0x0
     *  |    main header (struct disk_dump_header) |
     *  |------------------------------------------+ block 1
     *  |    sub header (struct kdump_sub_header)  |
     *  |------------------------------------------+ block 2
     *  |            1st-dump_bitmap               |
     *  |------------------------------------------+ block 2 + X blocks
     *  |            2nd-dump_bitmap               | (aligned by block)
     *  |------------------------------------------+ block 2 + 2 * X blocks
     *  |  page desc for pfn 0 (struct page_desc)  | (aligned by block)
     *  |  page desc for pfn 1 (struct page_desc)  |
     *  |                    :                     |
     *  |------------------------------------------| (not aligned by block)
     *  |         page data (pfn 0)                |
     *  |         page data (pfn 1)                |
     *  |                    :                     |
     *  +------------------------------------------+
     */

    ret = write_start_flat_header(s->fd);
    if (ret < 0) {
        dump_error(s, "dump: failed to write start flat header.\n");
        return -1;
    }

    ret = write_dump_header(s);
    if (ret < 0) {
        return -1;
    }

    ret = write_dump_bitmap(s);
    if (ret < 0) {
        return -1;
    }

    ret = write_dump_pages(s);
    if (ret < 0) {
        return -1;
    }

    ret = write_end_flat_header(s->fd);
    if (ret < 0) {
        dump_error(s, "dump: failed to write end flat header.\n");
        return -1;
    }

    dump_completed(s);

    return 0;
}

static ram_addr_t get_start_block(DumpState *s)
{
    GuestPhysBlock *block;
@@ -1479,7 +1537,8 @@ static void get_max_mapnr(DumpState *s)
    s->max_mapnr = paddr_to_pfn(last_block->target_end, s->page_shift);
}

static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
static int dump_init(DumpState *s, int fd, bool has_format,
                     DumpGuestMemoryFormat format, bool paging, bool has_filter,
                     int64_t begin, int64_t length, Error **errp)
{
    CPUState *cpu;
@@ -1487,6 +1546,11 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
    Error *err = NULL;
    int ret;

    /* 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;
@@ -1557,6 +1621,28 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
    tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), s->page_size);
    s->len_dump_bitmap = tmp * s->page_size;

    /* init for kdump-compressed format */
    if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
        switch (format) {
        case DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB:
            s->flag_compress = DUMP_DH_COMPRESSED_ZLIB;
            break;

        case DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO:
            s->flag_compress = DUMP_DH_COMPRESSED_LZO;
            break;

        case DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY:
            s->flag_compress = DUMP_DH_COMPRESSED_SNAPPY;
            break;

        default:
            s->flag_compress = 0;
        }

        return 0;
    }

    if (s->has_filter) {
        memory_mapping_filter(&s->list, s->begin, s->length);
    }
@@ -1616,14 +1702,25 @@ cleanup:
}

void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
                           int64_t begin, bool has_length, int64_t length,
                           Error **errp)
                           int64_t begin, bool has_length,
                           int64_t length, bool has_format,
                           DumpGuestMemoryFormat format, Error **errp)
{
    const char *p;
    int fd = -1;
    DumpState *s;
    int ret;

    /*
     * kdump-compressed format need the whole memory dumped, so paging or
     * filter is not supported here.
     */
    if ((has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) &&
        (paging || has_begin || has_length)) {
        error_setg(errp, "kdump-compressed format doesn't support paging or "
                         "filter");
        return;
    }
    if (has_begin && !has_length) {
        error_set(errp, QERR_MISSING_PARAMETER, "length");
        return;
@@ -1633,6 +1730,21 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
        return;
    }

    /* check whether lzo/snappy is supported */
#ifndef CONFIG_LZO
    if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO) {
        error_setg(errp, "kdump-lzo is not available now");
        return;
    }
#endif

#ifndef CONFIG_SNAPPY
    if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY) {
        error_setg(errp, "kdump-snappy is not available now");
        return;
    }
#endif

#if !defined(WIN32)
    if (strstart(file, "fd:", &p)) {
        fd = monitor_get_fd(cur_mon, p, errp);
@@ -1657,15 +1769,22 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,

    s = g_malloc0(sizeof(DumpState));

    ret = dump_init(s, fd, paging, has_begin, begin, length, errp);
    ret = dump_init(s, fd, has_format, format, paging, has_begin,
                    begin, length, errp);
    if (ret < 0) {
        g_free(s);
        return;
    }

    if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
        if (create_kdump_vmcore(s) < 0 && !error_is_set(s->errp)) {
            error_set(errp, QERR_IO_ERROR);
        }
    } else {
        if (create_vmcore(s) < 0 && !error_is_set(s->errp)) {
            error_set(errp, QERR_IO_ERROR);
        }
    }

    g_free(s);
}
+4 −1
Original line number Diff line number Diff line
@@ -1311,8 +1311,11 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
    const char *file = qdict_get_str(qdict, "filename");
    bool has_begin = qdict_haskey(qdict, "begin");
    bool has_length = qdict_haskey(qdict, "length");
    /* kdump-compressed format is not supported for HMP */
    bool has_format = false;
    int64_t begin = 0;
    int64_t length = 0;
    enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
    char *prot;

    if (has_begin) {
@@ -1325,7 +1328,7 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
    prot = g_strconcat("file:", file, NULL);

    qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
                          &errp);
                          has_format, dump_format, &errp);
    hmp_handle_error(mon, &errp);
    g_free(prot);
}
+24 −1
Original line number Diff line number Diff line
@@ -2794,6 +2794,24 @@
##
{ 'command': 'device_del', 'data': {'id': 'str'} }

##
# @DumpGuestMemoryFormat:
#
# An enumeration of guest-memory-dump's format.
#
# @elf: elf format
#
# @kdump-zlib: kdump-compressed format with zlib-compressed
#
# @kdump-lzo: kdump-compressed format with lzo-compressed
#
# @kdump-snappy: kdump-compressed format with snappy-compressed
#
# Since: 2.0
##
{ 'enum': 'DumpGuestMemoryFormat',
  'data': [ 'elf', 'kdump-zlib', 'kdump-lzo', 'kdump-snappy' ] }

##
# @dump-guest-memory
#
@@ -2830,13 +2848,18 @@
#          want to dump all guest's memory, please specify the start @begin
#          and @length
#
# @format: #optional if specified, the format of guest memory dump. But non-elf
#          format is conflict with paging and filter, ie. @paging, @begin and
#          @length is not allowed to be specified with non-elf @format at the
#          same time (since 2.0)
#
# Returns: nothing on success
#
# Since: 1.2
##
{ 'command': 'dump-guest-memory',
  'data': { 'paging': 'bool', 'protocol': 'str', '*begin': 'int',
            '*length': 'int' } }
            '*length': 'int', '*format': 'DumpGuestMemoryFormat' } }

##
# @netdev_add:
+5 −2
Original line number Diff line number Diff line
@@ -791,8 +791,8 @@ EQMP

    {
        .name       = "dump-guest-memory",
        .args_type  = "paging:b,protocol:s,begin:i?,end:i?",
        .params     = "-p protocol [begin] [length]",
        .args_type  = "paging:b,protocol:s,begin:i?,end:i?,format:s?",
        .params     = "-p protocol [begin] [length] [format]",
        .help       = "dump guest memory to file",
        .user_print = monitor_user_noop,
        .mhandler.cmd_new = qmp_marshal_input_dump_guest_memory,
@@ -813,6 +813,9 @@ Arguments:
           with length together (json-int)
- "length": the memory size, in bytes. It's optional, and should be specified
            with begin together (json-int)
- "format": the format of guest memory dump. It's optional, and can be
            elf|kdump-zlib|kdump-lzo|kdump-snappy, but non-elf formats will
            conflict with paging and filter, ie. begin and length (json-string)

Example: