aboutsummaryrefslogtreecommitdiff
path: root/arch_init.c
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2010-06-25 11:09:57 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2010-07-06 10:36:28 -0500
commite44359c35efbcd5ba9abf94bdd544a744046925a (patch)
tree2ced5fab15186224d67de59a7192c677981f6db4 /arch_init.c
parent97ab12d46622d239b439e77d3c193cd775a37984 (diff)
savevm: Use RAM blocks for basis of migration
We don't want to assume a contiguous address space, so migrate based on RAM blocks instead of a fixed linear address map. This will allow us to have holes in the ram_addr_t namespace, so we can implement qemu_ram_free(). Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'arch_init.c')
-rw-r--r--arch_init.c67
1 files changed, 42 insertions, 25 deletions
diff --git a/arch_init.c b/arch_init.c
index 37aad9d17b..186645b418 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_list.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_list.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)) {
@@ -146,9 +145,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_list.blocks);
+ }
+
+ current_addr = block->offset + offset;
+
+ } while (current_addr != last_block->offset + last_offset);
+
+ last_block = block;
+ last_offset = offset;
return bytes_sent;
}
@@ -157,13 +168,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_list.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++;
+ }
}
}
@@ -210,20 +224,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_list.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_list.blocks, next) {
qemu_put_byte(f, strlen(block->idstr));