Blame SOURCES/kvm-dump-make-kdump-compressed-format-available-for-dump.patch

958e1b
From 7cc714c354fc4dbfaeca66156ca331f57bf9653e Mon Sep 17 00:00:00 2001
958e1b
From: Laszlo Ersek <lersek@redhat.com>
958e1b
Date: Fri, 7 Nov 2014 17:18:03 +0100
958e1b
Subject: [PATCH 16/41] dump: make kdump-compressed format available for
958e1b
 'dump-guest-memory'
958e1b
958e1b
Message-id: <1415380693-16593-17-git-send-email-lersek@redhat.com>
958e1b
Patchwork-id: 62202
958e1b
O-Subject: [RHEL-7.1 qemu-kvm PATCH 16/26] dump: make kdump-compressed format available for 'dump-guest-memory'
958e1b
Bugzilla: 1157798
958e1b
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
958e1b
RH-Acked-by: Luiz Capitulino <lcapitulino@redhat.com>
958e1b
RH-Acked-by: dgibson <dgibson@redhat.com>
958e1b
958e1b
From: qiaonuohan <qiaonuohan@cn.fujitsu.com>
958e1b
958e1b
Make monitor command 'dump-guest-memory' be able to dump in kdump-compressed
958e1b
format. The command's usage:
958e1b
958e1b
  dump [-p] protocol [begin] [length] [format]
958e1b
958e1b
'format' is used to specified the format of vmcore and can be:
958e1b
1. 'elf': ELF format, without compression
958e1b
2. 'kdump-zlib': kdump-compressed format, with zlib-compressed
958e1b
3. 'kdump-lzo': kdump-compressed format, with lzo-compressed
958e1b
4. 'kdump-snappy': kdump-compressed format, with snappy-compressed
958e1b
Without 'format' being set, it is same as 'elf'. And if non-elf format is
958e1b
specified, paging and filter is not allowed.
958e1b
958e1b
Note:
958e1b
  1. The kdump-compressed format is readable only with the crash utility and
958e1b
     makedumpfile, and it can be smaller than the ELF format because of the
958e1b
     compression support.
958e1b
  2. The kdump-compressed format is the 6th edition.
958e1b
958e1b
Signed-off-by: Qiao Nuohan <qiaonuohan@cn.fujitsu.com>
958e1b
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
958e1b
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
958e1b
(cherry picked from commit b53ccc30c40df52d192e469a86c188a8649c6df3)
958e1b
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
958e1b
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
958e1b
---
958e1b
 dump.c           | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
958e1b
 hmp.c            |   5 ++-
958e1b
 qapi-schema.json |  25 ++++++++++-
958e1b
 qmp-commands.hx  |   7 ++-
958e1b
 4 files changed, 158 insertions(+), 10 deletions(-)
958e1b
958e1b
diff --git a/dump.c b/dump.c
958e1b
index fc5530f..c0d5877 100644
958e1b
--- a/dump.c
958e1b
+++ b/dump.c
958e1b
@@ -1449,6 +1449,64 @@ out:
958e1b
     return ret;
958e1b
 }
958e1b
 
958e1b
+static int create_kdump_vmcore(DumpState *s)
958e1b
+{
958e1b
+    int ret;
958e1b
+
958e1b
+    /*
958e1b
+     * the kdump-compressed format is:
958e1b
+     *                                               File offset
958e1b
+     *  +------------------------------------------+ 0x0
958e1b
+     *  |    main header (struct disk_dump_header) |
958e1b
+     *  |------------------------------------------+ block 1
958e1b
+     *  |    sub header (struct kdump_sub_header)  |
958e1b
+     *  |------------------------------------------+ block 2
958e1b
+     *  |            1st-dump_bitmap               |
958e1b
+     *  |------------------------------------------+ block 2 + X blocks
958e1b
+     *  |            2nd-dump_bitmap               | (aligned by block)
958e1b
+     *  |------------------------------------------+ block 2 + 2 * X blocks
958e1b
+     *  |  page desc for pfn 0 (struct page_desc)  | (aligned by block)
958e1b
+     *  |  page desc for pfn 1 (struct page_desc)  |
958e1b
+     *  |                    :                     |
958e1b
+     *  |------------------------------------------| (not aligned by block)
958e1b
+     *  |         page data (pfn 0)                |
958e1b
+     *  |         page data (pfn 1)                |
958e1b
+     *  |                    :                     |
958e1b
+     *  +------------------------------------------+
958e1b
+     */
958e1b
+
958e1b
+    ret = write_start_flat_header(s->fd);
958e1b
+    if (ret < 0) {
958e1b
+        dump_error(s, "dump: failed to write start flat header.\n");
958e1b
+        return -1;
958e1b
+    }
958e1b
+
958e1b
+    ret = write_dump_header(s);
958e1b
+    if (ret < 0) {
958e1b
+        return -1;
958e1b
+    }
958e1b
+
958e1b
+    ret = write_dump_bitmap(s);
958e1b
+    if (ret < 0) {
958e1b
+        return -1;
958e1b
+    }
958e1b
+
958e1b
+    ret = write_dump_pages(s);
958e1b
+    if (ret < 0) {
958e1b
+        return -1;
958e1b
+    }
958e1b
+
958e1b
+    ret = write_end_flat_header(s->fd);
958e1b
+    if (ret < 0) {
958e1b
+        dump_error(s, "dump: failed to write end flat header.\n");
958e1b
+        return -1;
958e1b
+    }
958e1b
+
958e1b
+    dump_completed(s);
958e1b
+
958e1b
+    return 0;
958e1b
+}
958e1b
+
958e1b
 static ram_addr_t get_start_block(DumpState *s)
958e1b
 {
958e1b
     GuestPhysBlock *block;
958e1b
@@ -1485,7 +1543,8 @@ static void get_max_mapnr(DumpState *s)
958e1b
     s->max_mapnr = paddr_to_pfn(last_block->target_end, s->page_shift);
958e1b
 }
958e1b
 
958e1b
-static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
958e1b
+static int dump_init(DumpState *s, int fd, bool has_format,
958e1b
+                     DumpGuestMemoryFormat format, bool paging, bool has_filter,
958e1b
                      int64_t begin, int64_t length, Error **errp)
958e1b
 {
958e1b
     CPUArchState *env;
958e1b
@@ -1493,6 +1552,11 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
958e1b
     Error *err = NULL;
958e1b
     int ret;
958e1b
 
958e1b
+    /* kdump-compressed is conflict with paging and filter */
958e1b
+    if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
958e1b
+        assert(!paging && !has_filter);
958e1b
+    }
958e1b
+
958e1b
     if (runstate_is_running()) {
958e1b
         vm_stop(RUN_STATE_SAVE_VM);
958e1b
         s->resume = true;
958e1b
@@ -1563,6 +1627,28 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
958e1b
     tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), s->page_size);
958e1b
     s->len_dump_bitmap = tmp * s->page_size;
958e1b
 
958e1b
+    /* init for kdump-compressed format */
958e1b
+    if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
958e1b
+        switch (format) {
958e1b
+        case DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB:
958e1b
+            s->flag_compress = DUMP_DH_COMPRESSED_ZLIB;
958e1b
+            break;
958e1b
+
958e1b
+        case DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO:
958e1b
+            s->flag_compress = DUMP_DH_COMPRESSED_LZO;
958e1b
+            break;
958e1b
+
958e1b
+        case DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY:
958e1b
+            s->flag_compress = DUMP_DH_COMPRESSED_SNAPPY;
958e1b
+            break;
958e1b
+
958e1b
+        default:
958e1b
+            s->flag_compress = 0;
958e1b
+        }
958e1b
+
958e1b
+        return 0;
958e1b
+    }
958e1b
+
958e1b
     if (s->has_filter) {
958e1b
         memory_mapping_filter(&s->list, s->begin, s->length);
958e1b
     }
958e1b
@@ -1622,14 +1708,25 @@ cleanup:
958e1b
 }
958e1b
 
958e1b
 void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
958e1b
-                           int64_t begin, bool has_length, int64_t length,
958e1b
-                           Error **errp)
958e1b
+                           int64_t begin, bool has_length,
958e1b
+                           int64_t length, bool has_format,
958e1b
+                           DumpGuestMemoryFormat format, Error **errp)
958e1b
 {
958e1b
     const char *p;
958e1b
     int fd = -1;
958e1b
     DumpState *s;
958e1b
     int ret;
958e1b
 
958e1b
+    /*
958e1b
+     * kdump-compressed format need the whole memory dumped, so paging or
958e1b
+     * filter is not supported here.
958e1b
+     */
958e1b
+    if ((has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) &&
958e1b
+        (paging || has_begin || has_length)) {
958e1b
+        error_setg(errp, "kdump-compressed format doesn't support paging or "
958e1b
+                         "filter");
958e1b
+        return;
958e1b
+    }
958e1b
     if (has_begin && !has_length) {
958e1b
         error_set(errp, QERR_MISSING_PARAMETER, "length");
958e1b
         return;
958e1b
@@ -1639,6 +1736,21 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
958e1b
         return;
958e1b
     }
958e1b
 
958e1b
+    /* check whether lzo/snappy is supported */
958e1b
+#ifndef CONFIG_LZO
958e1b
+    if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO) {
958e1b
+        error_setg(errp, "kdump-lzo is not available now");
958e1b
+        return;
958e1b
+    }
958e1b
+#endif
958e1b
+
958e1b
+#ifndef CONFIG_SNAPPY
958e1b
+    if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY) {
958e1b
+        error_setg(errp, "kdump-snappy is not available now");
958e1b
+        return;
958e1b
+    }
958e1b
+#endif
958e1b
+
958e1b
 #if !defined(WIN32)
958e1b
     if (strstart(file, "fd:", &p)) {
958e1b
         fd = monitor_get_fd(cur_mon, p, errp);
958e1b
@@ -1663,14 +1775,21 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
958e1b
 
958e1b
     s = g_malloc0(sizeof(DumpState));
958e1b
 
958e1b
-    ret = dump_init(s, fd, paging, has_begin, begin, length, errp);
958e1b
+    ret = dump_init(s, fd, has_format, format, paging, has_begin,
958e1b
+                    begin, length, errp);
958e1b
     if (ret < 0) {
958e1b
         g_free(s);
958e1b
         return;
958e1b
     }
958e1b
 
958e1b
-    if (create_vmcore(s) < 0 && !error_is_set(s->errp)) {
958e1b
-        error_set(errp, QERR_IO_ERROR);
958e1b
+    if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
958e1b
+        if (create_kdump_vmcore(s) < 0 && !error_is_set(s->errp)) {
958e1b
+            error_set(errp, QERR_IO_ERROR);
958e1b
+        }
958e1b
+    } else {
958e1b
+        if (create_vmcore(s) < 0 && !error_is_set(s->errp)) {
958e1b
+            error_set(errp, QERR_IO_ERROR);
958e1b
+        }
958e1b
     }
958e1b
 
958e1b
     g_free(s);
958e1b
diff --git a/hmp.c b/hmp.c
958e1b
index b723b26..1805926 100644
958e1b
--- a/hmp.c
958e1b
+++ b/hmp.c
958e1b
@@ -1195,8 +1195,11 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
958e1b
     const char *file = qdict_get_str(qdict, "filename");
958e1b
     bool has_begin = qdict_haskey(qdict, "begin");
958e1b
     bool has_length = qdict_haskey(qdict, "length");
958e1b
+    /* kdump-compressed format is not supported for HMP */
958e1b
+    bool has_format = false;
958e1b
     int64_t begin = 0;
958e1b
     int64_t length = 0;
958e1b
+    enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
958e1b
     char *prot;
958e1b
 
958e1b
     if (has_begin) {
958e1b
@@ -1209,7 +1212,7 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
958e1b
     prot = g_strconcat("file:", file, NULL);
958e1b
 
958e1b
     qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
958e1b
-                          &errp);
958e1b
+                          has_format, dump_format, &errp);
958e1b
     hmp_handle_error(mon, &errp);
958e1b
     g_free(prot);
958e1b
 }
958e1b
diff --git a/qapi-schema.json b/qapi-schema.json
958e1b
index d3d4e57..8f81c76 100644
958e1b
--- a/qapi-schema.json
958e1b
+++ b/qapi-schema.json
958e1b
@@ -2578,6 +2578,24 @@
958e1b
 { 'command': 'device_del', 'data': {'id': 'str'} }
958e1b
 
958e1b
 ##
958e1b
+# @DumpGuestMemoryFormat:
958e1b
+#
958e1b
+# An enumeration of guest-memory-dump's format.
958e1b
+#
958e1b
+# @elf: elf format
958e1b
+#
958e1b
+# @kdump-zlib: kdump-compressed format with zlib-compressed
958e1b
+#
958e1b
+# @kdump-lzo: kdump-compressed format with lzo-compressed
958e1b
+#
958e1b
+# @kdump-snappy: kdump-compressed format with snappy-compressed
958e1b
+#
958e1b
+# Since: 2.0
958e1b
+##
958e1b
+{ 'enum': 'DumpGuestMemoryFormat',
958e1b
+  'data': [ 'elf', 'kdump-zlib', 'kdump-lzo', 'kdump-snappy' ] }
958e1b
+
958e1b
+##
958e1b
 # @dump-guest-memory
958e1b
 #
958e1b
 # Dump guest's memory to vmcore. It is a synchronous operation that can take
958e1b
@@ -2613,13 +2631,18 @@
958e1b
 #          want to dump all guest's memory, please specify the start @begin
958e1b
 #          and @length
958e1b
 #
958e1b
+# @format: #optional if specified, the format of guest memory dump. But non-elf
958e1b
+#          format is conflict with paging and filter, ie. @paging, @begin and
958e1b
+#          @length is not allowed to be specified with non-elf @format at the
958e1b
+#          same time (since 2.0)
958e1b
+#
958e1b
 # Returns: nothing on success
958e1b
 #
958e1b
 # Since: 1.2
958e1b
 ##
958e1b
 { 'command': 'dump-guest-memory',
958e1b
   'data': { 'paging': 'bool', 'protocol': 'str', '*begin': 'int',
958e1b
-            '*length': 'int' } }
958e1b
+            '*length': 'int', '*format': 'DumpGuestMemoryFormat' } }
958e1b
 
958e1b
 ##
958e1b
 # @netdev_add:
958e1b
diff --git a/qmp-commands.hx b/qmp-commands.hx
958e1b
index e164ff8..61aa3bf 100644
958e1b
--- a/qmp-commands.hx
958e1b
+++ b/qmp-commands.hx
958e1b
@@ -885,8 +885,8 @@ EQMP
958e1b
 
958e1b
     {
958e1b
         .name       = "dump-guest-memory",
958e1b
-        .args_type  = "paging:b,protocol:s,begin:i?,end:i?",
958e1b
-        .params     = "-p protocol [begin] [length]",
958e1b
+        .args_type  = "paging:b,protocol:s,begin:i?,end:i?,format:s?",
958e1b
+        .params     = "-p protocol [begin] [length] [format]",
958e1b
         .help       = "dump guest memory to file",
958e1b
         .user_print = monitor_user_noop,
958e1b
         .mhandler.cmd_new = qmp_marshal_input_dump_guest_memory,
958e1b
@@ -907,6 +907,9 @@ Arguments:
958e1b
            with length together (json-int)
958e1b
 - "length": the memory size, in bytes. It's optional, and should be specified
958e1b
             with begin together (json-int)
958e1b
+- "format": the format of guest memory dump. It's optional, and can be
958e1b
+            elf|kdump-zlib|kdump-lzo|kdump-snappy, but non-elf formats will
958e1b
+            conflict with paging and filter, ie. begin and length (json-string)
958e1b
 
958e1b
 Example:
958e1b
 
958e1b
-- 
958e1b
1.8.3.1
958e1b