Skip to content

Commit

Permalink
migration: stable ram block ordering
Browse files Browse the repository at this point in the history
This makes ram block ordering under migration stable, ordered by offset.
This is especially useful for migration to exec, for debugging.

Signed-off-by: Michael S. Tsirkin <[email protected]>
Tested-by: Jason Wang <[email protected]>
  • Loading branch information
mstsirkin committed Dec 2, 2010
1 parent c924f36 commit b2e0a13
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 3 deletions.
35 changes: 35 additions & 0 deletions arch_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
#include <stdint.h>
#include <stdarg.h>
#include <stdlib.h>
#ifndef _WIN32
#include <sys/types.h>
#include <sys/mman.h>
Expand Down Expand Up @@ -212,6 +213,39 @@ uint64_t ram_bytes_total(void)
return total;
}

static int block_compar(const void *a, const void *b)
{
RAMBlock * const *ablock = a;
RAMBlock * const *bblock = b;
if ((*ablock)->offset < (*bblock)->offset) {
return -1;
} else if ((*ablock)->offset > (*bblock)->offset) {
return 1;
}
return 0;
}

static void sort_ram_list(void)
{
RAMBlock *block, *nblock, **blocks;
int n;
n = 0;
QLIST_FOREACH(block, &ram_list.blocks, next) {
++n;
}
blocks = qemu_malloc(n * sizeof *blocks);
n = 0;
QLIST_FOREACH_SAFE(block, &ram_list.blocks, next, nblock) {
blocks[n++] = block;
QLIST_REMOVE(block, next);
}
qsort(blocks, n, sizeof *blocks, block_compar);
while (--n >= 0) {
QLIST_INSERT_HEAD(&ram_list.blocks, blocks[n], next);
}
qemu_free(blocks);
}

int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
{
ram_addr_t addr;
Expand All @@ -234,6 +268,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
bytes_transferred = 0;
last_block = NULL;
last_offset = 0;
sort_ram_list();

/* Make sure all dirty bits are set */
QLIST_FOREACH(block, &ram_list.blocks, next) {
Expand Down
3 changes: 3 additions & 0 deletions cpu-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size);
void qemu_ram_free(ram_addr_t addr);
/* This should only be used for ram local to a device. */
void *qemu_get_ram_ptr(ram_addr_t addr);
/* Same but slower, to use for migration, where the order of
* RAMBlocks must not change. */
void *qemu_safe_ram_ptr(ram_addr_t addr);
/* This should not be used by devices. */
int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
Expand Down
24 changes: 22 additions & 2 deletions exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -2030,10 +2030,10 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,

/* we modify the TLB cache so that the dirty bit will be set again
when accessing the range */
start1 = (unsigned long)qemu_get_ram_ptr(start);
start1 = (unsigned long)qemu_safe_ram_ptr(start);
/* Chek that we don't span multiple blocks - this breaks the
address comparisons below. */
if ((unsigned long)qemu_get_ram_ptr(end - 1) - start1
if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
!= (end - 1) - start) {
abort();
}
Expand Down Expand Up @@ -2858,6 +2858,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
new_block->length = size;

QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
fprintf(stderr, "alloc ram %s len 0x%x\n", new_block->idstr, (int)new_block->length);

ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
last_ram_offset() >> TARGET_PAGE_BITS);
Expand Down Expand Up @@ -2931,6 +2932,25 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
return NULL;
}

/* Return a host pointer to ram allocated with qemu_ram_alloc.
* Same as qemu_get_ram_ptr but avoid reordering ramblocks.
*/
void *qemu_safe_ram_ptr(ram_addr_t addr)
{
RAMBlock *block;

QLIST_FOREACH(block, &ram_list.blocks, next) {
if (addr - block->offset < block->length) {
return block->host + (addr - block->offset);
}
}

fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
abort();

return NULL;
}

int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
{
RAMBlock *block;
Expand Down
2 changes: 1 addition & 1 deletion kvm-all.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
mem.slot = slot->slot;
mem.guest_phys_addr = slot->start_addr;
mem.memory_size = slot->memory_size;
mem.userspace_addr = (unsigned long)qemu_get_ram_ptr(slot->phys_offset);
mem.userspace_addr = (unsigned long)qemu_safe_ram_ptr(slot->phys_offset);
mem.flags = slot->flags;
if (s->migration_log) {
mem.flags |= KVM_MEM_LOG_DIRTY_PAGES;
Expand Down

0 comments on commit b2e0a13

Please sign in to comment.