From patchwork Sun Jan 5 07:27:43 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qiao Nuohan X-Patchwork-Id: 306927 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 7091F2C00BD for ; Sun, 5 Jan 2014 19:25:03 +1100 (EST) Received: from localhost ([::1]:57028 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vzj11-0007Ht-VR for incoming@patchwork.ozlabs.org; Sun, 05 Jan 2014 03:24:59 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40493) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vzj0f-0007Gs-R0 for qemu-devel@nongnu.org; Sun, 05 Jan 2014 03:24:44 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Vzj0Z-0001P2-F1 for qemu-devel@nongnu.org; Sun, 05 Jan 2014 03:24:37 -0500 Received: from fgwmail7.fujitsu.co.jp ([192.51.44.37]:43443) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vzj0Y-0001Oh-Er for qemu-devel@nongnu.org; Sun, 05 Jan 2014 03:24:31 -0500 Received: from fgwmail6.fujitsu.co.jp (fgwmail6.fujitsu.co.jp [192.51.44.36]) by fgwmail7.fujitsu.co.jp (Postfix) with ESMTP id 933681794845 for ; Sun, 5 Jan 2014 16:28:43 +0900 (JST) Received: from m2.gw.fujitsu.co.jp (unknown [10.0.50.72]) by fgwmail6.fujitsu.co.jp (Postfix) with ESMTP id 90C9C3EE0CB for ; Sun, 5 Jan 2014 16:28:42 +0900 (JST) Received: from smail (m2 [127.0.0.1]) by outgoing.m2.gw.fujitsu.co.jp (Postfix) with ESMTP id 8427B45DE3E for ; Sun, 5 Jan 2014 16:28:42 +0900 (JST) Received: from s2.gw.fujitsu.co.jp (s2.gw.nic.fujitsu.com [10.0.50.92]) by m2.gw.fujitsu.co.jp (Postfix) with ESMTP id 6DF6A45DE4C for ; Sun, 5 Jan 2014 16:28:42 +0900 (JST) Received: from s2.gw.fujitsu.co.jp (localhost.localdomain [127.0.0.1]) by s2.gw.fujitsu.co.jp (Postfix) with ESMTP id 619621DB802C for ; Sun, 5 Jan 2014 16:28:42 +0900 (JST) Received: from s00.gw.fujitsu.co.jp (s00.gw.nic.fujitsu.com [133.161.11.15]) by s2.gw.fujitsu.co.jp (Postfix) with ESMTP id 0786BE08001 for ; Sun, 5 Jan 2014 16:28:42 +0900 (JST) Received: from s00.gw.fujitsu.co.jp (kw-mxio2.gw.nic.fujitsu.com [10.0.237.142]) by s00.gw.fujitsu.co.jp (Postfix) with ESMTP id DDDAC118109 for ; Sun, 5 Jan 2014 16:28:41 +0900 (JST) Received: from G08FNSTD100518.localdomain (unknown [10.167.226.68]) by s00.gw.fujitsu.co.jp (Postfix) with ESMTP id BBA018A004 for ; Sun, 5 Jan 2014 16:28:41 +0900 (JST) Received: by G08FNSTD100518.localdomain (Postfix, from userid 0) id 3D578141E1F; Sun, 5 Jan 2014 15:28:29 +0800 (CST) From: Qiao Nuohan To: stefanha@gmail.com, lcapitulino@redhat.com, afaerber@suse.de, eblake@redhat.com Date: Sun, 5 Jan 2014 15:27:43 +0800 Message-Id: <1388906864-1083-11-git-send-email-qiaonuohan@cn.fujitsu.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1388906864-1083-1-git-send-email-qiaonuohan@cn.fujitsu.com> References: <1388906864-1083-1-git-send-email-qiaonuohan@cn.fujitsu.com> X-TM-AS-MML: disable X-TM-AS-Product-Ver: IMSS-7.1.0.1403-6.8.0.1017-20408.005 X-TM-AS-Result: No--22.947-7.0-31-10 X-imss-scan-details: No--22.947-7.0-31-10 X-TM-AS-User-Approved-Sender: No X-TMASE-MatchedRID: ntfZ/LmhKSg7GQ7VM/DlUcu00lnG8+PWguwtqyXlE6G/7bplhbPCQhcl 2rD10FYOwyWDdhVBAynxHXxxAO/d2ZCoy9iDotiwpvwZ9GmdwDN/r8x3wtvaX3DwxJWw/hfybIK PuQYVLlv5jqk7nfEfKN6bmObKUOT9tt90M/7M5GbRfDQgu+j+5SlayzmQ9QV0QZdVStJ/2iBueM FwDJsv/BJ6sgFwTRYhri3X8T1vMpHz50g+jp9gns+a+cvZqLkghSl7KAXaa8K6pZ/o2Hu2YT3JR DKZ4H1ssNDSWQktjDnoALLPaeFAShF4l1oN/bmOvHKClHGjjr2SeMExjuIoElwpnAAvAwazHBsH 6IIpfoKcPcDHCp4L+jMuKhR9jjkznEnP9v4KwegksSBZTGCrwt0H8LFZNFG7JQhrLH5KSJ0= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 192.51.44.37 Cc: qemu-devel@nongnu.org, qiaonuohan@cn.fujitsu.com, kumagai-atsushi@mxc.nes.nec.co.jp, anderson@redhat.com, akong@redhat.com, lersek@redhat.com Subject: [Qemu-devel] [PATCH v6 10/11] dump: Make kdump-compressed format available for 'dump-guest-memory' X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 And without 'format' being set, it is same as 'elf'. 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: Qiao Nuohan --- dump.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- hmp-commands.hx | 12 +++- hmp.c | 23 +++++++- qapi-schema.json | 22 +++++++- qmp-commands.hx | 6 +- 5 files changed, 212 insertions(+), 14 deletions(-) diff --git a/dump.c b/dump.c index 848957c..b4e79ff 100644 --- a/dump.c +++ b/dump.c @@ -1398,6 +1398,70 @@ 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) | + * | : | + * | page desc for pfn Z (struct page_desc) | + * |------------------------------------------| (not aligned by block) + * | page data (pfn 0) | + * | page data (pfn 1) | + * | : | + * | page data (pfn Z) | + * +------------------------------------------+ offset_eraseinfo + * | : | + * +------------------------------------------+ + */ + + if (s->flag_flatten) { + ret = write_start_flat_header(s->fd); + if (ret < 0) { + 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; + } + + if (s->flag_flatten) { + ret = write_end_flat_header(s->fd); + if (ret < 0) { + return -1; + } + } + + dump_completed(s); + + return 0; +} + static ram_addr_t get_start_block(DumpState *s) { GuestPhysBlock *block; @@ -1426,7 +1490,27 @@ static ram_addr_t get_start_block(DumpState *s) return -1; } -static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, +static bool use_flatten_format(int fd) +{ + if (lseek(fd, 0, SEEK_SET) < 0) { + return true; + } + + return false; +} + +static void get_max_mapnr(DumpState *s) +{ + MemoryMapping *memory_mapping; + + QTAILQ_FOREACH(memory_mapping, &s->list.head, next) { + s->max_mapnr = paddr_to_pfn(memory_mapping->phys_addr + + memory_mapping->length, s->page_shift); + } +} + +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; @@ -1494,6 +1578,44 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, qemu_get_guest_simple_memory_mapping(&s->list, &s->guest_phys_blocks); } + /* 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; + } + + /* + * check to see if fd is available to seek. + * if not, flatten format is used to avoid seek + */ + s->flag_flatten = use_flatten_format(fd); + + s->nr_cpus = nr_cpus; + s->page_size = PAGE_SIZE; + s->page_shift = ffs(s->page_size) - 1; + + get_max_mapnr(s); + + size_t tmp; + tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), s->page_size); + s->len_dump_bitmap = tmp * s->page_size; + + return 0; + } + if (s->has_filter) { memory_mapping_filter(&s->list, s->begin, s->length); } @@ -1553,8 +1675,9 @@ 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; @@ -1569,6 +1692,27 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, error_set(errp, QERR_MISSING_PARAMETER, "begin"); return; } + /* kdump-compressed format doesn't support paging or filter */ + if ((has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) && + (paging || has_begin || has_length)) { + error_set(errp, QERR_INVALID_PARAMETER_COMBINATION); + return; + } + + /* check whether lzo/snappy is supported */ +#ifndef CONFIG_LZO + if (format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "format", + "supported format(kdump-lzo is not available now)"); + } +#endif + +#ifndef CONFIG_SNAPPY + if (format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "format", + "supported format(kdump-snappy is not available now)"); + } +#endif #if !defined(WIN32) if (strstart(file, "fd:", &p)) { @@ -1594,14 +1738,21 @@ 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 (create_vmcore(s) < 0 && !error_is_set(s->errp)) { - error_set(errp, QERR_IO_ERROR); + 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); diff --git a/hmp-commands.hx b/hmp-commands.hx index ebe8e78..3856bb4 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -993,17 +993,19 @@ ETEXI { .name = "dump-guest-memory", - .args_type = "paging:-p,filename:F,begin:i?,length:i?", - .params = "[-p] filename [begin] [length]", + .args_type = "paging:-p,filename:F,begin:i?,length:i?,format:s?", + .params = "[-p] filename [begin] [length] [format]", .help = "dump guest memory to file" "\n\t\t\t begin(optional): the starting physical address" - "\n\t\t\t length(optional): the memory size, in bytes", + "\n\t\t\t length(optional): the memory size, in bytes" + "\n\t\t\t format(optional): the format of guest memory dump," + "\n\t\t\t it can be elf|kdump-zlib|kdump-lzo|kdump-snappy", .mhandler.cmd = hmp_dump_guest_memory, }, STEXI -@item dump-guest-memory [-p] @var{protocol} @var{begin} @var{length} +@item dump-guest-memory [-p] @var{protocol} @var{begin} @var{length} @var{format} @findex dump-guest-memory Dump guest memory to @var{protocol}. The file can be processed with crash or gdb. @@ -1013,6 +1015,8 @@ gdb. specified with length together. length: the memory size, in bytes. It's optional, and should be specified with begin together. + format: the format of guest memory dump. It's optional, and can be + elf|kdump-zlib|kdump-lzo|kdump-snappy ETEXI { diff --git a/hmp.c b/hmp.c index 32ee285..9bd62b8 100644 --- a/hmp.c +++ b/hmp.c @@ -1307,9 +1307,12 @@ 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"); + bool has_format = qdict_haskey(qdict, "format"); int64_t begin = 0; int64_t length = 0; + const char *format = NULL; char *prot; + enum DumpGuestMemoryFormat dump_format; if (has_begin) { begin = qdict_get_int(qdict, "begin"); @@ -1317,11 +1320,29 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) if (has_length) { length = qdict_get_int(qdict, "length"); } + if (has_format) { + format = qdict_get_str(qdict, "format"); + } + + if (strcmp(format, "elf") == 0) { + dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF; + } else if (strcmp(format, "kdump-zlib") == 0) { + dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB; + } else if (strcmp(format, "kdump-lzo") == 0) { + dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO; + } else if (strcmp(format, "kdump-snappy") == 0) { + dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY; + } else { + error_set(&errp, QERR_INVALID_PARAMETER_VALUE, + "format", "elf|kdump-zlib|kdump-lzo|kdump-snappy"); + hmp_handle_error(mon, &errp); + return; + } 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); } diff --git a/qapi-schema.json b/qapi-schema.json index c3c939c..19b2b23 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2676,6 +2676,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 zlib-compressed +# +# @kdump-snappy: kdump-compressed format with zlib-compressed +# +# Since: 1.8 +## +{ 'enum': 'DumpGuestMemoryFormat', + 'data': [ 'elf', 'kdump-zlib', 'kdump-lzo', 'kdump-snappy' ] } + +## # @dump-guest-memory # # Dump guest's memory to vmcore. It is a synchronous operation that can take @@ -2711,13 +2729,15 @@ # want to dump all guest's memory, please specify the start @begin # and @length # +# @format: #optional if specified, the format of guest memory dump. (since 1.8) +# # 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: diff --git a/qmp-commands.hx b/qmp-commands.hx index fba15cd..3de9e7d 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -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?,length: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,8 @@ 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 (json-string) Example: