Skip to content

Commit

Permalink
Merge remote-tracking branch 'quintela/migration-next-20121017' into …
Browse files Browse the repository at this point in the history
…staging

* quintela/migration-next-20121017: (41 commits)
  cpus: create qemu_in_vcpu_thread()
  savevm: make qemu_file_put_notify() return errors
  savevm: un-export qemu_file_set_error()
  block-migration: handle errors with the return codes correctly
  block-migration:  Switch meaning of return value
  block-migration: make flush_blks() return errors
  buffered_file: buffered_put_buffer() don't need to set last_error
  savevm: Only qemu_fflush() can generate errors
  savevm: make qemu_fill_buffer() be consistent
  savevm: unexport qemu_ftell()
  savevm: unfold qemu_fclose_internal()
  savevm: make qemu_fflush() return an error code
  savevm: Remove qemu_fseek()
  virtio-net: use qemu_get_buffer() in a temp buffer
  savevm: unexport qemu_fflush
  migration: make migrate_fd_wait_for_unfreeze() return errors
  buffered_file: make buffered_flush return the error code
  buffered_file: callers of buffered_flush() already check for errors
  buffered_file: We can access directly to bandwidth_limit
  buffered_file: unfold migrate_fd_close
  ...
  • Loading branch information
Anthony Liguori committed Oct 22, 2012
2 parents d3e2efc + aa723c2 commit f526f3c
Show file tree
Hide file tree
Showing 17 changed files with 319 additions and 272 deletions.
141 changes: 109 additions & 32 deletions arch_init.c
Expand Up @@ -31,6 +31,8 @@
#include "config.h"
#include "monitor.h"
#include "sysemu.h"
#include "bitops.h"
#include "bitmap.h"
#include "arch_init.h"
#include "audio/audio.h"
#include "hw/pc.h"
Expand All @@ -45,6 +47,7 @@
#include "hw/pcspk.h"
#include "qemu/page_cache.h"
#include "qmp-commands.h"
#include "trace.h"

#ifdef DEBUG_ARCH_INIT
#define DPRINTF(fmt, ...) \
Expand Down Expand Up @@ -330,6 +333,78 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,

static RAMBlock *last_block;
static ram_addr_t last_offset;
static unsigned long *migration_bitmap;
static uint64_t migration_dirty_pages;

static inline bool migration_bitmap_test_and_reset_dirty(MemoryRegion *mr,
ram_addr_t offset)
{
bool ret;
int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS;

ret = test_and_clear_bit(nr, migration_bitmap);

if (ret) {
migration_dirty_pages--;
}
return ret;
}

static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
ram_addr_t offset)
{
bool ret;
int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS;

ret = test_and_set_bit(nr, migration_bitmap);

if (!ret) {
migration_dirty_pages++;
}
return ret;
}

static void migration_bitmap_sync(void)
{
RAMBlock *block;
ram_addr_t addr;
uint64_t num_dirty_pages_init = migration_dirty_pages;
MigrationState *s = migrate_get_current();
static int64_t start_time;
static int64_t num_dirty_pages_period;
int64_t end_time;

if (!start_time) {
start_time = qemu_get_clock_ms(rt_clock);
}

trace_migration_bitmap_sync_start();
memory_global_sync_dirty_bitmap(get_system_memory());

QLIST_FOREACH(block, &ram_list.blocks, next) {
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
migration_bitmap_set_dirty(block->mr, addr);
}
}
memory_region_reset_dirty(block->mr, 0, block->length,
DIRTY_MEMORY_MIGRATION);
}
trace_migration_bitmap_sync_end(migration_dirty_pages
- num_dirty_pages_init);
num_dirty_pages_period += migration_dirty_pages - num_dirty_pages_init;
end_time = qemu_get_clock_ms(rt_clock);

/* more than 1 second = 1000 millisecons */
if (end_time > start_time + 1000) {
s->dirty_pages_rate = num_dirty_pages_period * 1000
/ (end_time - start_time);
start_time = end_time;
num_dirty_pages_period = 0;
}
}


/*
* ram_save_block: Writes a page of memory to the stream f
Expand All @@ -352,14 +427,10 @@ static int ram_save_block(QEMUFile *f, bool last_stage)

do {
mr = block->mr;
if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
if (migration_bitmap_test_and_reset_dirty(mr, offset)) {
uint8_t *p;
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;

memory_region_reset_dirty(mr, offset, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION);

p = memory_region_get_ram_ptr(mr) + offset;

if (is_dup_page(p)) {
Expand Down Expand Up @@ -409,7 +480,7 @@ static uint64_t bytes_transferred;

static ram_addr_t ram_save_remaining(void)
{
return ram_list.dirty_pages;
return migration_dirty_pages;
}

uint64_t ram_bytes_remaining(void)
Expand Down Expand Up @@ -481,17 +552,27 @@ static void ram_migration_cancel(void *opaque)
migration_end();
}


static void reset_ram_globals(void)
{
last_block = NULL;
last_offset = 0;
sort_ram_list();
}

#define MAX_WAIT 50 /* ms, half buffered_file limit */

static int ram_save_setup(QEMUFile *f, void *opaque)
{
ram_addr_t addr;
RAMBlock *block;
int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS;

migration_bitmap = bitmap_new(ram_pages);
bitmap_set(migration_bitmap, 1, ram_pages);
migration_dirty_pages = ram_pages;

bytes_transferred = 0;
last_block = NULL;
last_offset = 0;
sort_ram_list();
reset_ram_globals();

if (migrate_use_xbzrle()) {
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
Expand All @@ -506,17 +587,8 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
acct_clear();
}

/* Make sure all dirty bits are set */
QLIST_FOREACH(block, &ram_list.blocks, next) {
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
}
}
}

memory_global_dirty_log_start();
migration_bitmap_sync();

qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);

Expand All @@ -537,7 +609,8 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
double bwidth = 0;
int ret;
int i;
uint64_t expected_time;
uint64_t expected_downtime;
MigrationState *s = migrate_get_current();

bytes_transferred_last = bytes_transferred;
bwidth = qemu_get_clock_ns(rt_clock);
Expand Down Expand Up @@ -576,31 +649,32 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;

/* if we haven't transferred anything this round, force expected_time to a
* a very high value, but without crashing */
/* if we haven't transferred anything this round, force
* expected_downtime to a very high value, but without
* crashing */
if (bwidth == 0) {
bwidth = 0.000001;
}

qemu_put_be64(f, RAM_SAVE_FLAG_EOS);

expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
expected_downtime = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
DPRINTF("ram_save_live: expected(%" PRIu64 ") <= max(" PRIu64 ")?\n",
expected_downtime, migrate_max_downtime());

DPRINTF("ram_save_live: expected(%" PRIu64 ") <= max(%" PRIu64 ")?\n",
expected_time, migrate_max_downtime());
if (expected_downtime <= migrate_max_downtime()) {
migration_bitmap_sync();
expected_downtime = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
s->expected_downtime = expected_downtime / 1000000; /* ns -> ms */

if (expected_time <= migrate_max_downtime()) {
memory_global_sync_dirty_bitmap(get_system_memory());
expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;

return expected_time <= migrate_max_downtime();
return expected_downtime <= migrate_max_downtime();
}
return 0;
}

static int ram_save_complete(QEMUFile *f, void *opaque)
{
memory_global_sync_dirty_bitmap(get_system_memory());
migration_bitmap_sync();

/* try transferring iterative blocks of memory */

Expand All @@ -619,6 +693,9 @@ static int ram_save_complete(QEMUFile *f, void *opaque)

qemu_put_be64(f, RAM_SAVE_FLAG_EOS);

g_free(migration_bitmap);
migration_bitmap = NULL;

return 0;
}

Expand Down
56 changes: 28 additions & 28 deletions block-migration.c
Expand Up @@ -423,30 +423,34 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,

error:
DPRINTF("Error reading sector %" PRId64 "\n", sector);
qemu_file_set_error(f, ret);
g_free(blk->buf);
g_free(blk);
return 0;
return ret;
}

/* return value:
* 0: too much data for max_downtime
* 1: few enough data for max_downtime
*/
static int blk_mig_save_dirty_block(QEMUFile *f, int is_async)
{
BlkMigDevState *bmds;
int ret = 0;
int ret = 1;

QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
if (mig_save_device_dirty(f, bmds, is_async) == 0) {
ret = 1;
ret = mig_save_device_dirty(f, bmds, is_async);
if (ret <= 0) {
break;
}
}

return ret;
}

static void flush_blks(QEMUFile* f)
static int flush_blks(QEMUFile *f)
{
BlkMigBlock *blk;
int ret = 0;

DPRINTF("%s Enter submitted %d read_done %d transferred %d\n",
__FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
Expand All @@ -457,7 +461,7 @@ static void flush_blks(QEMUFile* f)
break;
}
if (blk->ret < 0) {
qemu_file_set_error(f, blk->ret);
ret = blk->ret;
break;
}
blk_send(f, blk);
Expand All @@ -474,6 +478,7 @@ static void flush_blks(QEMUFile* f)
DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
block_mig_state.submitted, block_mig_state.read_done,
block_mig_state.transferred);
return ret;
}

static int64_t get_remaining_dirty(void)
Expand Down Expand Up @@ -555,9 +560,7 @@ static int block_save_setup(QEMUFile *f, void *opaque)
/* start track dirty blocks */
set_dirty_tracking(1);

flush_blks(f);

ret = qemu_file_get_error(f);
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
Expand All @@ -577,9 +580,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
DPRINTF("Enter save live iterate submitted %d transferred %d\n",
block_mig_state.submitted, block_mig_state.transferred);

flush_blks(f);

ret = qemu_file_get_error(f);
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
Expand All @@ -598,16 +599,19 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
block_mig_state.bulk_completed = 1;
}
} else {
if (blk_mig_save_dirty_block(f, 1) == 0) {
ret = blk_mig_save_dirty_block(f, 1);
if (ret != 0) {
/* no more dirty blocks */
break;
}
}
}
if (ret) {
blk_mig_cleanup();
return ret;
}

flush_blks(f);

ret = qemu_file_get_error(f);
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
Expand All @@ -625,9 +629,7 @@ static int block_save_complete(QEMUFile *f, void *opaque)
DPRINTF("Enter save live complete submitted %d transferred %d\n",
block_mig_state.submitted, block_mig_state.transferred);

flush_blks(f);

ret = qemu_file_get_error(f);
ret = flush_blks(f);
if (ret) {
blk_mig_cleanup();
return ret;
Expand All @@ -639,18 +641,16 @@ static int block_save_complete(QEMUFile *f, void *opaque)
all async read completed */
assert(block_mig_state.submitted == 0);

while (blk_mig_save_dirty_block(f, 0) != 0) {
/* Do nothing */
}
blk_mig_cleanup();

/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
do {
ret = blk_mig_save_dirty_block(f, 0);
} while (ret == 0);

ret = qemu_file_get_error(f);
blk_mig_cleanup();
if (ret) {
return ret;
}
/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);

DPRINTF("Block migration completed\n");

Expand Down

0 comments on commit f526f3c

Please sign in to comment.