From: Paolo Bonzini <pbonzini@redhat.com>
To: Laszlo Ersek <lersek@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v2 for-qmp-1.6 3/4] dump: populate guest_phys_blocks
Date: Mon, 05 Aug 2013 16:23:30 +0200 [thread overview]
Message-ID: <51FFB562.3080007@redhat.com> (raw)
In-Reply-To: <1375690789-25212-4-git-send-email-lersek@redhat.com>
On 08/05/2013 10:19 AM, Laszlo Ersek wrote:
> While the machine is paused, in guest_phys_blocks_append() we register a
> one-shot MemoryListener, solely for the initial collection of the valid
> guest-physical memory ranges that happens at client registration time.
>
> For each range that is reported to guest_phys_blocks_set_memory(), we
> attempt to merge the range with adjacent (preceding, subsequent, or both)
> ranges. We use two hash tables for this purpose, both indexing the same
> ranges, just by different keys (guest-phys-start vs. guest-phys-end).
>
> Ranges can only be joined if they are contiguous in both guest-physical
> address space, and contiguous in host virtual address space.
>
> The "maximal" ranges that remain in the end constitute the guest-physical
> memory map that the dump will be based on.
>
> Related RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=981582
I would expect the ranges to be pretty large with MemoryListener, so
there should be no need for merging (on IRC in fact you mentioned only
10 calls to region_add).
So I would zap all the merging code. Apart from this detail, this is
great work!
Paolo
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
> include/sysemu/memory_mapping.h | 1 +
> dump.c | 2 +-
> memory_mapping.c | 135 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 137 insertions(+), 1 deletions(-)
>
> diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h
> index 53c2cd5..6723dc5 100644
> --- a/include/sysemu/memory_mapping.h
> +++ b/include/sysemu/memory_mapping.h
> @@ -66,6 +66,7 @@ void memory_mapping_list_init(MemoryMappingList *list);
>
> void guest_phys_blocks_free(GuestPhysBlockList *list);
> void guest_phys_blocks_init(GuestPhysBlockList *list);
> +void guest_phys_blocks_append(GuestPhysBlockList *list);
>
> void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp);
>
> diff --git a/dump.c b/dump.c
> index 716fb1d..3fa33fc 100644
> --- a/dump.c
> +++ b/dump.c
> @@ -746,7 +746,7 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
> s->length = length;
>
> guest_phys_blocks_init(&s->guest_phys_blocks);
> - /* FILL LIST */
> + guest_phys_blocks_append(&s->guest_phys_blocks);
>
> s->start = get_start_block(s);
> if (s->start == -1) {
> diff --git a/memory_mapping.c b/memory_mapping.c
> index c70505b..efaabf8 100644
> --- a/memory_mapping.c
> +++ b/memory_mapping.c
> @@ -11,9 +11,13 @@
> *
> */
>
> +#include <glib.h>
> +
> #include "cpu.h"
> #include "exec/cpu-all.h"
> #include "sysemu/memory_mapping.h"
> +#include "exec/memory.h"
> +#include "exec/address-spaces.h"
>
> static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
> MemoryMapping *mapping)
> @@ -182,6 +186,137 @@ void guest_phys_blocks_init(GuestPhysBlockList *list)
> QTAILQ_INIT(&list->head);
> }
>
> +typedef struct GuestPhysListener {
> + GHashTable *by_target_start;
> + GHashTable *by_target_end;
> + MemoryListener listener;
> +} GuestPhysListener;
> +
> +static void guest_phys_blocks_region_add(MemoryListener *listener,
> + MemoryRegionSection *section)
> +{
> + GuestPhysListener *g;
> + uint64_t section_size;
> + hwaddr target_start, target_end;
> + uint8_t *host_addr;
> + GuestPhysBlock *predecessor, *successor, *block;
> + bool found;
> +
> + /* we only care about RAM */
> + if (!memory_region_is_ram(section->mr)) {
> + return;
> + }
> +
> + g = container_of(listener, GuestPhysListener, listener);
> + section_size = int128_get64(section->size);
> + target_start = section->offset_within_address_space;
> + target_end = target_start + section_size;
> + host_addr = memory_region_get_ram_ptr(section->mr) +
> + section->offset_within_region;
> +
> + /* find continuity in guest physical address space */
> + predecessor = g_hash_table_lookup(g->by_target_end, &target_start);
> + successor = g_hash_table_lookup(g->by_target_start, &target_end);
> +
> + /* we require continuity in host memory too */
> + if (predecessor != NULL) {
> + hwaddr predecessor_size = predecessor->target_end -
> + predecessor->target_start;
> + if (predecessor->host_addr + predecessor_size != host_addr) {
> + predecessor = NULL;
> + }
> + }
> + if (successor != NULL
> + && host_addr + section_size != successor->host_addr) {
> + successor = NULL;
> + }
> +
> + if (predecessor == NULL) {
> + if (successor == NULL) {
> + /* Isolated mapping, allocate it and add it to both tables. */
> + block = g_malloc0(sizeof *block);
> +
> + block->target_end = target_end;
> + g_hash_table_insert(g->by_target_end, &block->target_end, block);
> + } else {
> + /* Mapping has successor only. Merge current into successor by
> + * modifying successor's start. Successor's end doesn't change.
> + */
> + block = successor;
> + found = g_hash_table_steal(g->by_target_start,
> + &block->target_start);
> + g_assert(found);
> + }
> + block->target_start = target_start;
> + block->host_addr = host_addr;
> + g_hash_table_insert(g->by_target_start, &block->target_start, block);
> + return;
> + }
> +
> + if (successor != NULL) {
> + /* Mapping has both predecessor and successor. Delete the successor
> + * and expand the predecessor to cover all three.
> + */
> + target_end = successor->target_end;
> +
> + found = g_hash_table_steal(g->by_target_end, &successor->target_end);
> + g_assert(found);
> + found = g_hash_table_steal(g->by_target_start,
> + &successor->target_start);
> + g_assert(found);
> +
> + g_free(successor);
> + }
> + /* otherwise, mapping has predecessor only */
> +
> + /* Expand predecessor until @target_end. Predecessor's start doesn't
> + * change.
> + */
> + block = predecessor;
> + found = g_hash_table_steal(g->by_target_end, &block->target_end);
> + g_assert(found);
> +
> + block->target_end = target_end;
> + g_hash_table_insert(g->by_target_end, &block->target_end, block);
> +}
> +
> +static void guest_phys_block_link(gpointer key, gpointer value,
> + gpointer user_data)
> +{
> + GuestPhysBlock *block = value;
> + GuestPhysBlockList *list = user_data;
> +
> + QTAILQ_INSERT_TAIL(&list->head, block, next);
> + ++list->num;
> +}
> +
> +void guest_phys_blocks_append(GuestPhysBlockList *list)
> +{
> + GHashFunc hash_func;
> + GEqualFunc equal_func;
> + GuestPhysListener g = { 0 };
> +
> + if (sizeof(hwaddr) == sizeof(uint64_t)) {
> + hash_func = &g_int64_hash;
> + equal_func = &g_int64_equal;
> + } else {
> + hash_func = &g_int_hash;
> + equal_func = &g_int_equal;
> + }
> +
> + g.by_target_start = g_hash_table_new(hash_func, equal_func);
> + g.by_target_end = g_hash_table_new(hash_func, equal_func);
> +
> + g.listener.region_add = &guest_phys_blocks_region_add;
> + memory_listener_register(&g.listener, &address_space_memory);
> + memory_listener_unregister(&g.listener);
> +
> + g_hash_table_foreach(g.by_target_start, &guest_phys_block_link, list);
> +
> + g_hash_table_destroy(g.by_target_end);
> + g_hash_table_destroy(g.by_target_start);
> +}
> +
> static CPUState *find_paging_enabled_cpu(CPUState *start_cpu)
> {
> CPUState *cpu;
>
next prev parent reply other threads:[~2013-08-05 14:23 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-05 8:19 [Qemu-devel] [PATCH v2 for-qmp-1.6 0/4] dump-guest-memory: correct the vmcores Laszlo Ersek
2013-08-05 8:19 ` [Qemu-devel] [PATCH v2 for-qmp-1.6 1/4] dump: clamp guest-provided mapping lengths to ramblock sizes Laszlo Ersek
2013-08-05 8:19 ` [Qemu-devel] [PATCH v2 for-qmp-1.6 2/4] dump: introduce GuestPhysBlockList Laszlo Ersek
2013-08-05 8:19 ` [Qemu-devel] [PATCH v2 for-qmp-1.6 3/4] dump: populate guest_phys_blocks Laszlo Ersek
2013-08-05 14:23 ` Paolo Bonzini [this message]
2013-08-05 8:19 ` [Qemu-devel] [PATCH v2 for-qmp-1.6 4/4] dump: rebase from host-private RAMBlock offsets to guest-physical addresses Laszlo Ersek
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=51FFB562.3080007@redhat.com \
--to=pbonzini@redhat.com \
--cc=lersek@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.