@@ -502,8 +502,10 @@ bool ram_save_block(QEMUFile *f, bool last_stage)
if (offset >= block->length) {
offset = 0;
block = QLIST_NEXT(block, next);
- if (!block)
+ if (!block) {
block = QLIST_FIRST(&ram_list.blocks);
+ migrate_get_current()->precopy_count++;
+ }
}
} while (block != last_block || offset != last_offset);
@@ -619,7 +621,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
acct_clear();
}
- if (!params->postcopy) {
+ if (!(params->postcopy && params->precopy_count == 0)) {
memory_global_dirty_log_start();
migration_bitmap_sync();
}
@@ -322,6 +322,10 @@ int postcopy_outgoing_create_read_socket(MigrationState *s)
void postcopy_outgoing_state_begin(QEMUFile *f, const MigrationParams *params)
{
uint64_t options = 0;
+ if (params->precopy_count > 0) {
+ options |= POSTCOPY_OPTION_PRECOPY;
+ }
+
qemu_put_ubyte(f, QEMU_VM_POSTCOPY_INIT);
qemu_put_be32(f, sizeof(options));
qemu_put_be64(f, options);
@@ -337,12 +341,36 @@ void postcopy_outgoing_state_complete(
int postcopy_outgoing_ram_save_iterate(QEMUFile *f, void *opaque)
{
- qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
- return 1;
+ int ret;
+ MigrationState *s = migrate_get_current();
+ if (s->params.precopy_count == 0) {
+ qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
+ return 1;
+ }
+
+ ret = ram_save_iterate(f);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 1) {
+ DPRINTF("precopy worked\n");
+ return ret;
+ }
+ if (ram_bytes_remaining() == 0) {
+ DPRINTF("no more precopy\n");
+ return 1;
+ }
+ return s->precopy_count >= s->params.precopy_count? 1: 0;
}
int postcopy_outgoing_ram_save_complete(QEMUFile *f, void *opaque)
{
+ MigrationState *s = migrate_get_current();
+ if (s->params.precopy_count > 0) {
+ /* Make sure all dirty bits are set */
+ migration_bitmap_sync();
+ memory_global_dirty_log_stop();
+ }
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
return 0;
}
@@ -544,6 +572,7 @@ static void postcopy_outgoing_recv_handler(void *opaque)
PostcopyOutgoingState *postcopy_outgoing_begin(MigrationState *ms)
{
PostcopyOutgoingState *s = g_new(PostcopyOutgoingState, 1);
+ const RAMBlock *block;
DPRINTF("outgoing begin\n");
qemu_buffered_file_drain(ms->file);
@@ -553,9 +582,64 @@ PostcopyOutgoingState *postcopy_outgoing_begin(MigrationState *ms)
s->mig_read = ms->file_read;
s->mig_buffered_write = ms->file;
- /* Make sure all dirty bits are set */
- memory_global_dirty_log_stop();
- migration_bitmap_init();
+ if (ms->params.precopy_count > 0) {
+ QEMUFile *f = ms->file;
+ uint64_t last_long =
+ BITS_TO_LONGS(last_ram_offset() >> TARGET_PAGE_BITS);
+
+ /* send dirty bitmap */
+ qemu_mutex_lock_ramlist();
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ const unsigned long *bitmap = migration_bitmap_get();
+ uint64_t length;
+ uint64_t start;
+ uint64_t end;
+ uint64_t i;
+
+ qemu_put_byte(f, strlen(block->idstr));
+ qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
+ qemu_put_be64(f, block->offset);
+ qemu_put_be64(f, block->length);
+
+ start = (block->offset >> TARGET_PAGE_BITS);
+ end = (block->offset + block->length) >> TARGET_PAGE_BITS;
+
+ length = BITS_TO_LONGS(end - (start & ~63)) * sizeof(unsigned long);
+ length = DIV_ROUND_UP(length, sizeof(uint64_t)) * sizeof(uint64_t);
+ qemu_put_be64(f, length);
+ DPRINTF("dirty bitmap %s 0x%"PRIx64" 0x%"PRIx64" 0x%"PRIx64"\n",
+ block->idstr, block->offset, block->length, length);
+
+ start /= BITS_PER_LONG;
+ end = DIV_ROUND_UP(end, BITS_PER_LONG);
+ assert(end <= last_long);
+
+ for (i = start; i < end;
+ i += sizeof(uint64_t) / sizeof(unsigned long)) {
+ uint64_t val;
+#if HOST_LONG_BITS == 64
+ val = bitmap[i];
+#elif HOST_LONG_BITS == 32
+ if (i + 1 < last_long) {
+ val = bitmap[i] | ((uint64_t)bitmap[i + 1] << 32);
+ } else {
+ val = bitmap[i];
+ }
+#else
+# error "unsupported"
+#endif
+ qemu_put_be64(f, val);
+ }
+ }
+ qemu_mutex_unlock_ramlist();
+
+ /* terminator */
+ qemu_put_byte(f, 0); /* idstr len */
+ qemu_put_be64(f, 0); /* block offset */
+ qemu_put_be64(f, 0); /* block length */
+ qemu_put_be64(f, 0); /* bitmap len */
+ DPRINTF("sent dirty bitmap\n");
+ }
qemu_set_fd_handler(s->fd_read,
&postcopy_outgoing_recv_handler, NULL, s);
@@ -58,6 +58,7 @@ struct MigrationState
int fd_read;
QEMUFile *file_read; /* connection from the detination */
PostcopyOutgoingState *postcopy;
+ int precopy_count;
};
void process_incoming_migration(QEMUFile *f);
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> --- arch_init.c | 6 ++-- migration-postcopy.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++--- migration.h | 1 + 3 files changed, 94 insertions(+), 7 deletions(-)