From patchwork Thu Feb 9 03:34:54 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wen Congyang X-Patchwork-Id: 140308 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 52C8BB71A7 for ; Thu, 9 Feb 2012 14:31:52 +1100 (EST) Received: from localhost ([::1]:52191 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RvKja-0006Sj-MU for incoming@patchwork.ozlabs.org; Wed, 08 Feb 2012 22:31:46 -0500 Received: from eggs.gnu.org ([140.186.70.92]:42322) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RvKjU-0006SW-88 for qemu-devel@nongnu.org; Wed, 08 Feb 2012 22:31:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RvKjS-0003CI-Hf for qemu-devel@nongnu.org; Wed, 08 Feb 2012 22:31:40 -0500 Received: from [222.73.24.84] (port=49451 helo=song.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RvKjQ-0003BJ-6v for qemu-devel@nongnu.org; Wed, 08 Feb 2012 22:31:38 -0500 Received: from tang.cn.fujitsu.com (tang.cn.fujitsu.com [10.167.250.3]) by song.cn.fujitsu.com (Postfix) with ESMTP id 15C26170123; Thu, 9 Feb 2012 11:31:34 +0800 (CST) Received: from mailserver.fnst.cn.fujitsu.com (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id q193VVT7000911; Thu, 9 Feb 2012 11:31:32 +0800 Received: from [10.167.225.226] ([10.167.225.226]) by mailserver.fnst.cn.fujitsu.com (Lotus Domino Release 8.5.1FP4) with ESMTP id 2012020911300409-577079 ; Thu, 9 Feb 2012 11:30:04 +0800 Message-ID: <4F333EDE.600@cn.fujitsu.com> Date: Thu, 09 Feb 2012 11:34:54 +0800 From: Wen Congyang User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100413 Fedora/3.0.4-2.fc13 Thunderbird/3.0.4 MIME-Version: 1.0 To: qemu-devel , Jan Kiszka , Dave Anderson , HATAYAMA Daisuke , Luiz Capitulino , Eric Blake References: <4F333AAA.1070601@cn.fujitsu.com> In-Reply-To: <4F333AAA.1070601@cn.fujitsu.com> X-MIMETrack: Itemize by SMTP Server on mailserver/fnst(Release 8.5.1FP4|July 25, 2010) at 2012-02-09 11:30:04, Serialize by Router on mailserver/fnst(Release 8.5.1FP4|July 25, 2010) at 2012-02-09 11:30:05, Serialize complete at 2012-02-09 11:30:05 X-detected-operating-system: by eggs.gnu.org: FreeBSD 6.x (1) X-Received-From: 222.73.24.84 Subject: [Qemu-devel] [RFC][PATCH 16/16 v6] allow user to dump a fraction of the 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 Signed-off-by: Wen Congyang --- dump.c | 206 ++++++++++++++++++++++++++++++++++++++++-------------- hmp-commands.hx | 6 +- hmp.c | 13 +++- memory_mapping.c | 27 +++++++ memory_mapping.h | 2 + qapi-schema.json | 6 ++- qmp-commands.hx | 4 +- 7 files changed, 205 insertions(+), 59 deletions(-) diff --git a/dump.c b/dump.c index 6322d1a..60a5180 100644 --- a/dump.c +++ b/dump.c @@ -77,6 +77,9 @@ typedef struct DumpState { char *error; int fd; bool detach; + bool has_filter; + int64_t begin; + int64_t length; target_phys_addr_t memory_offset; int64_t bandwidth; RAMBlock *block; @@ -397,23 +400,82 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, /* get the memory's offset in the vmcore */ static target_phys_addr_t get_offset(target_phys_addr_t phys_addr, - target_phys_addr_t memory_offset) + DumpState *s) { RAMBlock *block; - target_phys_addr_t offset = memory_offset; + target_phys_addr_t offset = s->memory_offset; + int64_t size_in_block, start; + + if (s->has_filter) { + if (phys_addr < s->begin || phys_addr >= s->begin + s->length) { + return -1; + } + } QLIST_FOREACH(block, &ram_list.blocks, next) { - if (phys_addr >= block->offset && - phys_addr < block->offset + block->length) { - return phys_addr - block->offset + offset; + if (s->has_filter) { + if (block->offset >= s->begin + s->length || + block->offset + block->length <= s->begin) { + /* This block is out of the range */ + continue; + } + + if (s->begin <= block->offset) { + start = block->offset; + } else { + start = s->begin; + } + + size_in_block = block->length - (start - block->offset); + if (s->begin + s->length < block->offset + block->length) { + size_in_block -= block->offset + block->length - + (s->begin + s->length); + } + } else { + start = block->offset; + size_in_block = block->length; } - offset += block->length; + + if (phys_addr >= start && phys_addr < start + size_in_block) { + return phys_addr - start + offset; + } + + offset += size_in_block; } return -1; } -static DumpState *dump_init(int fd, bool detach, Error **errp) +static ram_addr_t get_start_block(DumpState *s) +{ + RAMBlock *block; + + if (!s->has_filter) { + s->block = QLIST_FIRST(&ram_list.blocks); + return 0; + } + + QLIST_FOREACH(block, &ram_list.blocks, next) { + if (block->offset >= s->begin + s->length || + block->offset + block->length <= s->begin) { + /* This block is out of the range */ + continue; + } + + s->block = block; + if (s->begin > block->offset ) { + s->start = s->begin - block->offset; + } else { + s->start = 0; + } + return s->start; + } + + return -1; +} + +static DumpState *dump_init(int fd, bool detach, bool has_filter, int64_t begin, + int64_t length, Error **errp) { CPUState *env; DumpState *s = dump_get_current(); @@ -427,10 +489,17 @@ static DumpState *dump_init(int fd, bool detach, Error **errp) s->error = NULL; } s->fd = fd; - s->block = QLIST_FIRST(&ram_list.blocks); - s->start = 0; s->timer = NULL; s->detach = detach; + s->has_filter = has_filter; + s->begin = begin; + s->length = length; + + s->start = get_start_block(s); + if (s->start == -1) { + error_set(errp, QERR_INVALID_PARAMETER, "begin"); + return NULL; + } /* * get dump info: endian, class and architecture. @@ -454,6 +523,10 @@ static DumpState *dump_init(int fd, bool detach, Error **errp) QTAILQ_INIT(&s->list.head); get_memory_mapping(&s->list); + if (s->has_filter) { + filter_memory_mapping(&s->list, s->begin, s->length); + } + /* crash needs extra memory mapping to determine phys_base. */ ret = cpu_add_extra_memory_mapping(&s->list); if (ret < 0) { @@ -547,7 +620,7 @@ static int dump_completed(DumpState *s) int phdr_index = 1, ret; QTAILQ_FOREACH(memory_mapping, &s->list.head, next) { - offset = get_offset(memory_mapping->phys_addr, s->memory_offset); + offset = get_offset(memory_mapping->phys_addr, s); if (s->dump_info.d_class == ELFCLASS64) { ret = write_elf64_load(s, memory_mapping, phdr_index++, offset); } else { @@ -563,6 +636,33 @@ static int dump_completed(DumpState *s) return 0; } +static int get_next_block(DumpState *s, RAMBlock *block) +{ + while (1) { + block = QLIST_NEXT(block, next); + if (!block) { + /* no more block */ + return 1; + } + + s->start = 0; + s->block = block; + if (s->has_filter) { + if (block->offset >= s->begin + s->length || + block->offset + block->length <= s->begin) { + /* This block is out of the range */ + continue; + } + + if (s->begin > block->offset) { + s->start = s->begin - block->offset; + } + } + + return 0; + } +} + /* * write memory to vmcore. * @@ -573,47 +673,39 @@ static int dump_completed(DumpState *s) */ static int dump_iterate(DumpState *s, int64_t deadline) { - RAMBlock *block = s->block; + RAMBlock *block; target_phys_addr_t offset = s->offset; - int64_t size, remain, writen_size; + int64_t size, writen_size, size_in_block; int64_t total = s->bandwidth / 10; int ret; + bool first = true; - if ((block->length - s->start) >= total) { - size = total; - } else { - size = block->length - s->start; - } - - ret = write_memory(s, block, s->start, &offset, &size, deadline); - if (ret < 0) { - return -1; - } - - if (size == total || ret == 1) { - if ((size + s->start) == block->length) { - s->block = QLIST_NEXT(block, next); - s->start = 0; + size = 0; + while (size < total) { + if (first) { + first = false; } else { - s->start += size; + ret = get_next_block(s, block); + if (ret == 1) { + /* we have finished */ + return 1; + } } - goto end; - } - while (size < total) { - block = QLIST_NEXT(block, next); - if (!block) { - /* we have finished */ - return 1; + block = s->block; + writen_size = total - size; + size_in_block = block->length - s->start; + if (s->has_filter && + s->begin + s->length < block->offset + block->length) { + size_in_block -= block->offset + block->length - + (s->begin + s->length); } - remain = total - size; - if (remain >= block->length) { - writen_size = block->length; - } else { - writen_size = remain; + if (writen_size >= size_in_block) { + writen_size = size_in_block; } - ret = write_memory(s, block, 0, &offset, &writen_size, deadline); + + ret = write_memory(s, block, s->start, &offset, &writen_size, deadline); if (ret < 0) { return -1; } else if (ret == 1) { @@ -621,21 +713,17 @@ static int dump_iterate(DumpState *s, int64_t deadline) } size += writen_size; } - if (writen_size == block->length) { - s->block = QLIST_NEXT(block, next); - s->start = 0; + if (writen_size == size_in_block) { + ret = get_next_block(s, block); + if (ret == 1) { + /* we have finished */ + return 1; + } } else { - s->block = block; - s->start = writen_size; + s->start += writen_size; } -end: s->offset = offset; - if (!s->block) { - /* we have finished */ - return 1; - } - return 0; } @@ -687,12 +775,22 @@ static void dump_vm_state_change(void *opaque, int running, RunState state) } } -void qmp_dump(bool detach, const char *file, Error **errp) +void qmp_dump(bool detach, const char *file, bool has_begin, int64_t begin, + bool has_length, int64_t length, Error **errp) { const char *p; int fd = -1; DumpState *s; + if (has_begin && !has_length) { + error_set(errp, QERR_MISSING_PARAMETER, "length"); + return; + } + if (!has_begin && has_length) { + error_set(errp, QERR_MISSING_PARAMETER, "begin"); + return; + } + #if !defined(WIN32) if (strstart(file, "fd:", &p)) { fd = qemu_get_fd(p); @@ -716,7 +814,7 @@ void qmp_dump(bool detach, const char *file, Error **errp) return; } - s = dump_init(fd, detach, errp); + s = dump_init(fd, detach, has_begin, begin, length, errp); if (!s) { return; } diff --git a/hmp-commands.hx b/hmp-commands.hx index a026905..388b9ac 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -868,9 +868,11 @@ ETEXI { .name = "dump", - .args_type = "detach:-d,file:s", + .args_type = "detach:-d,file:s,begin:i?,length:i?", .params = "file", - .help = "dump to file (using -d to not wait for completion)", + .help = "dump to file (using -d to not wait for completion)" + "\n\t\t\t begin(optional): the starting physical address" + "\n\t\t\t length(optional): the memory size, in bytes", .user_print = monitor_user_noop, .mhandler.cmd = hmp_dump, }, diff --git a/hmp.c b/hmp.c index b36921c..e0c5c62 100644 --- a/hmp.c +++ b/hmp.c @@ -857,8 +857,19 @@ void hmp_dump(Monitor *mon, const QDict *qdict) Error *errp = NULL; bool detach = qdict_get_try_bool(qdict, "detach", 0); const char *file = qdict_get_str(qdict, "file"); + bool has_begin = qdict_haskey(qdict, "begin"); + bool has_length = qdict_haskey(qdict, "length"); + int64_t begin = 0; + int64_t length = 0; - qmp_dump(detach, file, &errp); + if (has_begin) { + begin = qdict_get_int(qdict, "begin"); + } + if (has_length) { + length = qdict_get_int(qdict, "length"); + } + + qmp_dump(detach, file, has_begin, begin, has_length, length, &errp); hmp_handle_error(mon, &errp); } diff --git a/memory_mapping.c b/memory_mapping.c index fc0ddee..e2fcf2e 100644 --- a/memory_mapping.c +++ b/memory_mapping.c @@ -193,3 +193,30 @@ void get_memory_mapping(MemoryMappingList *list) return; } + +void filter_memory_mapping(MemoryMappingList *list, int64_t begin, + int64_t length) +{ + MemoryMapping *cur, *next; + + QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) { + if (cur->phys_addr >= begin + length || + cur->phys_addr + cur->length <= begin) { + QTAILQ_REMOVE(&list->head, cur, next); + list->num--; + continue; + } + + if (cur->phys_addr < begin) { + cur->length -= begin - cur->phys_addr; + if (cur->virt_addr) { + cur->virt_addr += begin - cur->phys_addr; + } + cur->phys_addr = begin; + } + + if (cur->phys_addr + cur->length > begin + length) { + cur->length -= cur->phys_addr + cur->length - begin - length; + } + } +} diff --git a/memory_mapping.h b/memory_mapping.h index 679f9ef..c7bb4fa 100644 --- a/memory_mapping.h +++ b/memory_mapping.h @@ -35,5 +35,7 @@ void add_to_memory_mapping(MemoryMappingList *list, void free_memory_mapping_list(MemoryMappingList *list); void get_memory_mapping(MemoryMappingList *list); +void filter_memory_mapping(MemoryMappingList *list, int64_t begin, + int64_t length); #endif diff --git a/qapi-schema.json b/qapi-schema.json index 27d5199..aee9efa 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1590,12 +1590,16 @@ # # @detach: detached dumping. # @file: the filename or file descriptor of the vmcore. +# @begin: if specified, the starting physical address. +# @length: if specified, the memory size, in bytes. # # Returns: nothing on success # # Since: 1.1 ## -{ 'command': 'dump', 'data': { 'detach': 'bool', 'file': 'str' } } +{ 'command': 'dump', + 'data': { 'detach': 'bool', 'file': 'str', '*begin': 'int', + '*length': 'int' } } ## # @dump_cancel diff --git a/qmp-commands.hx b/qmp-commands.hx index 1656eea..0c72536 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -567,7 +567,7 @@ EQMP { .name = "dump", - .args_type = "detach:-d,file:s", + .args_type = "detach:-d,file:s,begin:i?,end:i?", .params = "file", .help = "dump to file (using -d to not wait for completion)", .user_print = monitor_user_noop, @@ -584,6 +584,8 @@ Arguments: - "detach": detached dumping (json-bool, optional) - "file": Destination file (json-string) +- "begin": the starting physical address (json-int) +- "length": the memory size, in bytes (json-int) Example: