Message ID | 4F5FFEDE.8060606@cn.fujitsu.com |
---|---|
State | New |
Headers | show |
On Wed, 14 Mar 2012 10:13:50 +0800 Wen Congyang <wency@cn.fujitsu.com> 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 <wency@cn.fujitsu.com> > --- > 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 > -@item dump [-p] @var{file} > +@item 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: >
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"); + 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 -@item dump [-p] @var{file} +@item 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. # # 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:
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 <wency@cn.fujitsu.com> --- 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(-)