int64_t cur_dirty;
int64_t completed_sectors;
int64_t total_sectors;
- int64_t dirty;
QSIMPLEQ_ENTRY(BlkMigDevState) entry;
unsigned long *aio_bitmap;
} BlkMigDevState;
int64_t total_sector_sum;
int prev_progress;
int bulk_completed;
- long double prev_time_offset;
} BlkMigState;
static BlkMigState block_mig_state;
static void blk_mig_read_cb(void *opaque, int ret)
{
- long double curr_time = qemu_get_clock_ns(rt_clock);
BlkMigBlock *blk = opaque;
blk->ret = ret;
- block_mig_state.prev_time_offset = curr_time;
-
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
- if (block_mig_state.submitted == 0) {
- block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
- }
-
blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);
block_mig_state.submitted++;
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
- if (block_mig_state.submitted == 0) {
- block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
- }
-
blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);
block_mig_state.submitted++;
set_dirty_tracking(1);
ret = flush_blks(f);
- if (ret) {
- blk_mig_cleanup();
- return ret;
- }
-
blk_mig_reset_dirty_cursor();
-
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
- return 0;
+ return ret;
}
static int block_save_iterate(QEMUFile *f, void *opaque)
{
int ret;
+ int64_t last_ftell = qemu_ftell(f);
DPRINTF("Enter save live iterate submitted %d transferred %d\n",
block_mig_state.submitted, block_mig_state.transferred);
ret = flush_blks(f);
if (ret) {
- blk_mig_cleanup();
return ret;
}
}
} else {
ret = blk_mig_save_dirty_block(f, 1);
+ if (ret < 0) {
+ return ret;
+ }
if (ret != 0) {
/* no more dirty blocks */
break;
}
}
}
- if (ret) {
- blk_mig_cleanup();
- return ret;
- }
ret = flush_blks(f);
if (ret) {
- blk_mig_cleanup();
return ret;
}
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
- return 0;
+ return qemu_ftell(f) - last_ftell;
}
static int block_save_complete(QEMUFile *f, void *opaque)
ret = flush_blks(f);
if (ret) {
- blk_mig_cleanup();
return ret;
}
do {
ret = blk_mig_save_dirty_block(f, 0);
+ if (ret < 0) {
+ return ret;
+ }
} while (ret == 0);
- blk_mig_cleanup();
- if (ret) {
- return ret;
- }
/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
+ blk_mig_cleanup();
return 0;
}
static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
{
+ /* Estimate pending number of bytes to send */
+ uint64_t pending = get_remaining_dirty() +
+ block_mig_state.submitted * BLOCK_SIZE +
+ block_mig_state.read_done * BLOCK_SIZE;
+
+ /* Report at least one block pending during bulk phase */
+ if (pending == 0 && !block_mig_state.bulk_completed) {
+ pending = BLOCK_SIZE;
+ }
- DPRINTF("Enter save live pending %ld\n", get_remaining_dirty());
-
- return get_remaining_dirty();
+ DPRINTF("Enter save live pending %" PRIu64 "\n", pending);
+ return pending;
}
static int block_load(QEMUFile *f, void *opaque, int version_id)