All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wen Congyang <wency@cn.fujitsu.com>
To: qemu-devel <qemu-devel@nongnu.org>,
	Jan Kiszka <jan.kiszka@siemens.com>,
	Dave Anderson <anderson@redhat.com>,
	HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>,
	Luiz Capitulino <lcapitulino@redhat.com>,
	Eric Blake <eblake@redhat.com>
Subject: [Qemu-devel] [RFC][PATCH 14/14 v9] allow user to dump a fraction of the memory
Date: Wed, 14 Mar 2012 10:13:50 +0800	[thread overview]
Message-ID: <4F5FFEDE.8060606@cn.fujitsu.com> (raw)
In-Reply-To: <4F5FFC63.3060300@cn.fujitsu.com>

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");
+        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:
 
-- 
1.7.1

  parent reply	other threads:[~2012-03-14  2:12 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-14  2:03 [Qemu-devel] [RFC][PATCH 00/14 v9] introducing a new, dedicated memory dump mechanism Wen Congyang
2012-03-14  2:05 ` [Qemu-devel] [RFC][PATCH 01/14 v9] Add API to create memory mapping list Wen Congyang
2012-03-14  2:06 ` [Qemu-devel] [RFC][PATCH 02/14 v9] Add API to check whether a physical address is I/O address Wen Congyang
2012-03-14  9:18   ` [Qemu-devel] [RESEND][PATCH " Wen Congyang
2012-03-14  2:06 ` [Qemu-devel] [RFC][PATCH 03/14 v9] implement cpu_get_memory_mapping() Wen Congyang
2012-03-14  2:07 ` [Qemu-devel] [RFC][PATCH 04/14 v9] Add API to check whether paging mode is enabled Wen Congyang
2012-03-14  2:07 ` [Qemu-devel] [RFC][PATCH 05/14 v9] Add API to get memory mapping Wen Congyang
2012-03-16  3:52   ` HATAYAMA Daisuke
2012-03-16  6:50     ` Wen Congyang
2012-03-16  6:38   ` HATAYAMA Daisuke
2012-03-16  6:59     ` Wen Congyang
2012-03-14  2:08 ` [Qemu-devel] [RFC][PATCH 06/14 v9] Add API to get memory mapping without do paging Wen Congyang
2012-03-14  2:08 ` [Qemu-devel] [RFC][PATCH 07/14 v9] target-i386: Add API to write elf notes to core file Wen Congyang
2012-03-16  1:17   ` HATAYAMA Daisuke
2012-03-14  2:09 ` [Qemu-devel] [RFC][PATCH 08/14 v9] target-i386: Add API to write cpu status " Wen Congyang
2012-03-16  1:48   ` HATAYAMA Daisuke
2012-03-16  6:50     ` Wen Congyang
2012-03-19  1:09       ` HATAYAMA Daisuke
2012-03-14  2:09 ` [Qemu-devel] [RFC][PATCH 09/14 v9] target-i386: add API to get dump info Wen Congyang
2012-03-14  2:10 ` [Qemu-devel] [RFC][PATCH 10/14 v9] make gdb_id() generally avialable Wen Congyang
2012-03-14  2:11 ` [Qemu-devel] [RFC][PATCH 11/14 v9] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
2012-03-14 17:18   ` Luiz Capitulino
2012-03-15  2:29     ` Wen Congyang
2012-03-15 14:25     ` Luiz Capitulino
2012-03-16 10:13     ` Wen Congyang
2012-03-19  2:28     ` Wen Congyang
2012-03-19  8:31       ` Wen Congyang
2012-03-19 13:16       ` Luiz Capitulino
2012-03-16  3:23   ` HATAYAMA Daisuke
2012-03-16  6:41     ` Wen Congyang
2012-03-14  2:12 ` [Qemu-devel] [RFC][PATCH 12/14 v9] support to cancel the current dumping Wen Congyang
2012-03-14 17:19   ` Luiz Capitulino
2012-03-14  2:13 ` [Qemu-devel] [RFC][PATCH 13/14 v9] support to query dumping status Wen Congyang
2012-03-14 17:19   ` Luiz Capitulino
2012-03-14  2:13 ` Wen Congyang [this message]
2012-03-14 17:20   ` [Qemu-devel] [RFC][PATCH 14/14 v9] allow user to dump a fraction of the memory Luiz Capitulino
2012-03-14 17:26 ` [Qemu-devel] [RFC][PATCH 00/14 v9] introducing a new, dedicated memory dump mechanism Luiz Capitulino
2012-03-14 17:37   ` Eric Blake
2012-03-14 17:49   ` Anthony Liguori
2012-03-14 18:03     ` Luiz Capitulino

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F5FFEDE.8060606@cn.fujitsu.com \
    --to=wency@cn.fujitsu.com \
    --cc=anderson@redhat.com \
    --cc=d.hatayama@jp.fujitsu.com \
    --cc=eblake@redhat.com \
    --cc=jan.kiszka@siemens.com \
    --cc=lcapitulino@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.