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>
This commit is contained in:
Alex Williamson 2010-06-25 11:09:57 -06:00 committed by Anthony Liguori
parent 97ab12d466
commit e44359c35e
1 changed files with 42 additions and 25 deletions

View File

@ -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));