[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC][PATCH 14/14 v9] allow user to dump a fraction of
From: |
Luiz Capitulino |
Subject: |
Re: [Qemu-devel] [RFC][PATCH 14/14 v9] allow user to dump a fraction of the memory |
Date: |
Wed, 14 Mar 2012 14:20:06 -0300 |
On Wed, 14 Mar 2012 10:13:50 +0800
Wen Congyang <address@hidden> wrote:
> This API allows the user to limit how much memory to be dumped,
> rather than forcing the user to dump all memory at once.
>
> Signed-off-by: Wen Congyang <address@hidden>
> ---
> dump.c | 186
> +++++++++++++++++++++++++++++++++++++++++++++---------
> hmp-commands.hx | 14 +++-
> hmp.c | 13 ++++-
> memory_mapping.c | 27 ++++++++
> memory_mapping.h | 3 +
> qapi-schema.json | 6 ++-
> qmp-commands.hx | 8 ++-
> 7 files changed, 220 insertions(+), 37 deletions(-)
>
> diff --git a/dump.c b/dump.c
> index 7f9ea09..cd65488 100644
> --- a/dump.c
> +++ b/dump.c
> @@ -83,6 +83,12 @@ typedef struct DumpState {
> write_core_dump_function f;
> void (*cleanup)(void *opaque);
> void *opaque;
> +
> + RAMBlock *block;
> + ram_addr_t start;
> + bool has_filter;
> + int64_t begin;
> + int64_t length;
> } DumpState;
>
> static DumpState *dump_get_current(void)
> @@ -389,24 +395,30 @@ static int write_data(DumpState *s, void *buf, int
> length,
> }
>
> /* write the memroy to vmcore. 1 page per I/O. */
> -static int write_memory(DumpState *s, RAMBlock *block,
> - target_phys_addr_t *offset)
> +static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
> + target_phys_addr_t *offset, int64_t *size)
> {
> int i, ret;
> + int64_t writen_size = 0;
>
> - for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
> - ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
> + *size = block->length - start;
> + for (i = 0; i < *size / TARGET_PAGE_SIZE; i++) {
> + ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
> TARGET_PAGE_SIZE, offset);
> if (ret < 0) {
> - return -1;
> + *size = writen_size;
> + return ret;
> }
> +
> + writen_size += TARGET_PAGE_SIZE;
> }
>
> - if ((block->length % TARGET_PAGE_SIZE) != 0) {
> - ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
> - block->length % TARGET_PAGE_SIZE, offset);
> + if ((*size % TARGET_PAGE_SIZE) != 0) {
> + ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
> + *size % TARGET_PAGE_SIZE, offset);
> if (ret < 0) {
> - return -1;
> + *size = writen_size;
> + return ret;
> }
> }
>
> @@ -415,17 +427,47 @@ static int write_memory(DumpState *s, RAMBlock *block,
>
> /* 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;
> @@ -512,7 +554,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 {
> @@ -528,22 +570,55 @@ 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 all memory to vmcore */
> -static int dump_iterate(DumpState *s)
> +static int dump_iterate(void *opaque)
> {
> + DumpState *s = opaque;
> RAMBlock *block;
> target_phys_addr_t offset = s->memory_offset;
> + int64_t size;
> int ret;
>
> - /* write all memory to vmcore */
> - QLIST_FOREACH(block, &ram_list.blocks, next) {
> - ret = write_memory(s, block, &offset);
> - if (ret < 0) {
> - return -1;
> + while(1) {
> + block = s->block;
> + ret = write_memory(s, block, s->start, &offset, &size);
> + if (ret == -1) {
> + return ret;
> }
> - }
>
> - return dump_completed(s);
> + ret = get_next_block(s, block);
> + if (ret == 1) {
> + dump_completed(s);
> + return 0;
> + }
> + }
> }
>
> static int create_vmcore(DumpState *s)
> @@ -563,7 +638,36 @@ static int create_vmcore(DumpState *s)
> return 0;
> }
>
> -static DumpState *dump_init(bool paging, 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(bool paging, bool has_filter, int64_t begin,
> + int64_t length, Error **errp)
> {
> CPUState *env;
> DumpState *s = dump_get_current();
> @@ -581,6 +685,15 @@ static DumpState *dump_init(bool paging, Error **errp)
> s->error = NULL;
> }
>
> + 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");
This will let the VM stopped.
> + return NULL;
> + }
> +
> /*
> * get dump info: endian, class and architecture.
> * If the target architecture is not supported, cpu_get_dump_info() will
> @@ -607,6 +720,10 @@ static DumpState *dump_init(bool paging, Error **errp)
> qemu_get_guest_simple_memory_mapping(&s->list);
> }
>
> + if (s->has_filter) {
> + memory_mapping_filter(&s->list, s->begin, s->length);
> + }
> +
> /*
> * calculate phdr_num
> *
> @@ -659,9 +776,10 @@ static void fd_cleanup(void *opaque)
> }
> }
>
> -static DumpState *dump_init_fd(int fd, bool paging, Error **errp)
> +static DumpState *dump_init_fd(int fd, bool paging, bool has_filter,
> + int64_t begin, int64_t length, Error **errp)
> {
> - DumpState *s = dump_init(paging, errp);
> + DumpState *s = dump_init(paging, has_filter, begin, length, errp);
>
> if (s == NULL) {
> return NULL;
> @@ -674,12 +792,22 @@ static DumpState *dump_init_fd(int fd, bool paging,
> Error **errp)
> return s;
> }
>
> -void qmp_dump(bool paging, const char *file, Error **errp)
> +void qmp_dump(bool paging, 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);
> @@ -703,7 +831,7 @@ void qmp_dump(bool paging, const char *file, Error **errp)
> return;
> }
>
> - s = dump_init_fd(fd, paging, errp);
> + s = dump_init_fd(fd, paging, has_begin, begin, length, errp);
> if (!s) {
> return;
> }
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index abd412e..af0f112 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -883,21 +883,27 @@ ETEXI
> #if defined(CONFIG_HAVE_CORE_DUMP)
> {
> .name = "dump",
> - .args_type = "paging:-p,file:s",
> - .params = "[-p] file",
> - .help = "dump to file",
> + .args_type = "paging:-p,file:s,begin:i?,length:i?",
> + .params = "[-p] file [begin] [length]",
> + .help = "dump to file"
> + "\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,
> },
>
>
> STEXI
> address@hidden dump [-p] @var{file}
> address@hidden dump [-p] @var{file} @var{begin} @var{length}
> @findex dump
> Dump to @var{file}. The file can be processed with crash or gdb.
> file: destination file(started with "file:") or destination file
> descriptor
> (started with "fd:")
> paging: do paging to get guest's memory mapping
> + begin: the starting physical address. It's optional, and should be
> specified
> + with length together.
> + length: the memory size, in bytes. It's optional, and should be specified
> with
> + begin together.
> ETEXI
> #endif
>
> diff --git a/hmp.c b/hmp.c
> index d0aa94b..b399119 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -866,8 +866,19 @@ void hmp_dump(Monitor *mon, const QDict *qdict)
> Error *errp = NULL;
> int paging = qdict_get_try_bool(qdict, "paging", 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(!!paging, file, &errp);
> + if (has_begin) {
> + begin = qdict_get_int(qdict, "begin");
> + }
> + if (has_length) {
> + length = qdict_get_int(qdict, "length");
> + }
> +
> + qmp_dump(!!paging, file, has_begin, begin, has_length, length, &errp);
> hmp_handle_error(mon, &errp);
> }
>
> diff --git a/memory_mapping.c b/memory_mapping.c
> index 8dd0750..f2b8252 100644
> --- a/memory_mapping.c
> +++ b/memory_mapping.c
> @@ -209,3 +209,30 @@ void
> qemu_get_guest_simple_memory_mapping(MemoryMappingList *list)
> create_new_memory_mapping(list, block->offset, 0, block->length);
> }
> }
> +
> +void memory_mapping_filter(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 50b1f25..c5004ed 100644
> --- a/memory_mapping.h
> +++ b/memory_mapping.h
> @@ -55,4 +55,7 @@ int qemu_get_guest_memory_mapping(MemoryMappingList *list);
> /* get guest's memory mapping without do paging(virtual address is 0). */
> void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list);
>
> +void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
> + int64_t length);
> +
> #endif
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 9728f5f..cc42fa0 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -1671,12 +1671,16 @@
> #
> # @paging: if true, do paging to get guest's memory mapping
> # @file: the filename or file descriptor of the vmcore.
> +# @begin: if specified, the starting physical address.
> +# @length: if specified, the memory size, in bytes.
'begin' and 'length' are optionals and have to be marked as such (look
in qapi-schema.json for examples).
Also, I would squash this patch into 11/14.
> #
> # Returns: nothing on success
> #
> # Since: 1.1
> ##
> -{ 'command': 'dump', 'data': { 'paging': 'bool', 'file': 'str' } }
> +{ 'command': 'dump',
> + 'data': { 'paging': 'bool', 'file': 'str', '*begin': 'int',
> + '*length': 'int' } }
>
> ##
> # @dump_cancel
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 036e111..738fff8 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -589,8 +589,8 @@ EQMP
> #if defined(CONFIG_HAVE_CORE_DUMP)
> {
> .name = "dump",
> - .args_type = "paging:-p,file:s",
> - .params = "[-p] file",
> + .args_type = "paging:-p,file:s,begin:i?,end:i?",
> + .params = "[-p] file [begin] [length]",
> .help = "dump to file",
> .user_print = monitor_user_noop,
> .mhandler.cmd_new = qmp_marshal_input_dump,
> @@ -607,6 +607,10 @@ Arguments:
> - "paging": do paging to get guest's memory mapping (json-bool)
> - "file": destination file(started with "file:") or destination file
> descriptor
> (started with "fd:") (json-string)
> +- "begin": the starting physical address. It's optional, and should be
> specified
> + with length together (json-int)
> +- "length": the memory size, in bytes. It's optional, and should be specified
> + with begin together (json-int)
>
> Example:
>
- [Qemu-devel] [RFC][PATCH 08/14 v9] target-i386: Add API to write cpu status to core file, (continued)
- [Qemu-devel] [RFC][PATCH 08/14 v9] target-i386: Add API to write cpu status to core file, Wen Congyang, 2012/03/13
- [Qemu-devel] [RFC][PATCH 09/14 v9] target-i386: add API to get dump info, Wen Congyang, 2012/03/13
- [Qemu-devel] [RFC][PATCH 10/14 v9] make gdb_id() generally avialable, Wen Congyang, 2012/03/13
- [Qemu-devel] [RFC][PATCH 11/14 v9] introduce a new monitor command 'dump' to dump guest's memory, Wen Congyang, 2012/03/13
- [Qemu-devel] [RFC][PATCH 12/14 v9] support to cancel the current dumping, Wen Congyang, 2012/03/13
- [Qemu-devel] [RFC][PATCH 13/14 v9] support to query dumping status, Wen Congyang, 2012/03/13
- [Qemu-devel] [RFC][PATCH 14/14 v9] allow user to dump a fraction of the memory, Wen Congyang, 2012/03/13
- Re: [Qemu-devel] [RFC][PATCH 14/14 v9] allow user to dump a fraction of the memory,
Luiz Capitulino <=
- Re: [Qemu-devel] [RFC][PATCH 00/14 v9] introducing a new, dedicated memory dump mechanism, Luiz Capitulino, 2012/03/14