[RFC PATCH 6/6] savevm: Use RAM blocks for basis of migration

Alex Williamson
2010-06-08T19:20:53Z

We don't want to assume a contiguous address space, so migrate based
on RAM blocks instead of a fixed linear address map.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---

arch_init.c | 67 +++++++++++++++++++++++++++++++++++++----------------------
1 files changed, 42 insertions(+), 25 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index 8ba92ec..5780195 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -105,27 +105,26 @@ static int is_dup_page(uint8_t *page, uint8_t ch)

static int ram_save_block(QEMUFile *f)
{
- static ram_addr_t current_addr = 0;
- ram_addr_t saved_addr = current_addr;
- ram_addr_t addr = 0;
- uint64_t total_ram = ram_bytes_total();
+ static RAMBlock *last_block = NULL;
+ static ram_addr_t last_offset = 0;
+ RAMBlock *block = last_block;
+ ram_addr_t offset = last_offset;
+ ram_addr_t current_addr;
int bytes_sent = 0;

- while (addr < total_ram) {
+ if (!block)
+ block = QLIST_FIRST(&ram.blocks);
+
+ current_addr = block->offset + offset;
+
+ do {
if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
- RAMBlock *block;
- ram_addr_t offset;
uint8_t *p;

cpu_physical_memory_reset_dirty(current_addr,
current_addr + TARGET_PAGE_SIZE,
MIGRATION_DIRTY_FLAG);

- QLIST_FOREACH(block, &ram.blocks, next) {
- if (current_addr - block->offset < block->length)
- break;
- }
- offset = current_addr - block->offset;
p = block->host + offset;

if (is_dup_page(p, *p)) {
@@ -142,9 +141,21 @@ static int ram_save_block(QEMUFile *f)

break;
}
- addr += TARGET_PAGE_SIZE;
- current_addr = (saved_addr + addr) % total_ram;
- }
+
+ offset += TARGET_PAGE_SIZE;
+ if (offset >= block->length) {
+ offset = 0;
+ block = QLIST_NEXT(block, next);
+ if (!block)
+ block = QLIST_FIRST(&ram.blocks);
+ }
+
+ current_addr = block->offset + offset;
+
+ } while (current_addr != last_block->offset + last_offset);
+
+ last_block = block;
+ last_offset = offset;

return bytes_sent;
}
@@ -153,13 +164,16 @@ static uint64_t bytes_transferred;

static ram_addr_t ram_save_remaining(void)
{
- ram_addr_t addr;
+ RAMBlock *block;
ram_addr_t count = 0;
- uint64_t total_ram = ram_bytes_total();

- for (addr = 0; addr < total_ram; addr += TARGET_PAGE_SIZE) {
- if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) {
- count++;
+ QLIST_FOREACH(block, &ram.blocks, next) {
+ ram_addr_t addr;
+ for (addr = block->offset; addr < block->offset + block->length;
+ addr += TARGET_PAGE_SIZE) {
+ if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) {
+ count++;
+ }
}
}

@@ -206,20 +220,23 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)

if (stage == 1) {
RAMBlock *block;
- uint64_t total_ram = ram_bytes_total();
bytes_transferred = 0;

/* Make sure all dirty bits are set */
- for (addr = 0; addr < total_ram; addr += TARGET_PAGE_SIZE) {
- if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) {
- cpu_physical_memory_set_dirty(addr);
+ QLIST_FOREACH(block, &ram.blocks, next) {
+ for (addr = block->offset; addr < block->offset + block->length;
+ addr += TARGET_PAGE_SIZE) {
+ if (!cpu_physical_memory_get_dirty(addr,
+ MIGRATION_DIRTY_FLAG)) {
+ cpu_physical_memory_set_dirty(addr);
+ }
}
}

/* Enable dirty memory tracking */
cpu_physical_memory_set_dirty_tracking(1);

- qemu_put_be64(f, total_ram | RAM_SAVE_FLAG_MEM_SIZE);
+ qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);

QLIST_FOREACH(block, &ram.blocks, next) {
qemu_put_buffer(f, (uint8_t *)block->name, sizeof(block->name));