aboutsummaryrefslogtreecommitdiff
path: root/migration
diff options
context:
space:
mode:
Diffstat (limited to 'migration')
-rw-r--r--migration/exec.c3
-rw-r--r--migration/fd.c3
-rw-r--r--migration/migration.c46
-rw-r--r--migration/ram.c32
-rw-r--r--migration/ram.h2
-rw-r--r--migration/savevm.c24
-rw-r--r--migration/socket.c5
7 files changed, 68 insertions, 47 deletions
diff --git a/migration/exec.c b/migration/exec.c
index 0bbeb63..375d2e1 100644
--- a/migration/exec.c
+++ b/migration/exec.c
@@ -49,9 +49,6 @@ static gboolean exec_accept_incoming_migration(QIOChannel *ioc,
{
migration_channel_process_incoming(ioc);
object_unref(OBJECT(ioc));
- if (!migrate_use_multifd()) {
- migration_incoming_process();
- }
return G_SOURCE_REMOVE;
}
diff --git a/migration/fd.c b/migration/fd.c
index fee34ff..a7c13df 100644
--- a/migration/fd.c
+++ b/migration/fd.c
@@ -49,9 +49,6 @@ static gboolean fd_accept_incoming_migration(QIOChannel *ioc,
{
migration_channel_process_incoming(ioc);
object_unref(OBJECT(ioc));
- if (!migrate_use_multifd()) {
- migration_incoming_process();
- }
return G_SOURCE_REMOVE;
}
diff --git a/migration/migration.c b/migration/migration.c
index 94d71f8..8d56d56 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -466,7 +466,8 @@ void migration_incoming_process(void)
qemu_coroutine_enter(co);
}
-void migration_fd_process_incoming(QEMUFile *f)
+/* Returns true if recovered from a paused migration, otherwise false */
+static bool postcopy_try_recover(QEMUFile *f)
{
MigrationIncomingState *mis = migration_incoming_get_current();
@@ -491,23 +492,52 @@ void migration_fd_process_incoming(QEMUFile *f)
* that source is ready to reply to page requests.
*/
qemu_sem_post(&mis->postcopy_pause_sem_dst);
- } else {
- /* New incoming migration */
- migration_incoming_setup(f);
- migration_incoming_process();
+ return true;
+ }
+
+ return false;
+}
+
+void migration_fd_process_incoming(QEMUFile *f)
+{
+ if (postcopy_try_recover(f)) {
+ return;
}
+
+ migration_incoming_setup(f);
+ migration_incoming_process();
}
void migration_ioc_process_incoming(QIOChannel *ioc)
{
MigrationIncomingState *mis = migration_incoming_get_current();
+ bool start_migration;
if (!mis->from_src_file) {
+ /* The first connection (multifd may have multiple) */
QEMUFile *f = qemu_fopen_channel_input(ioc);
+
+ /* If it's a recovery, we're done */
+ if (postcopy_try_recover(f)) {
+ return;
+ }
+
migration_incoming_setup(f);
- return;
+
+ /*
+ * Common migration only needs one channel, so we can start
+ * right now. Multifd needs more than one channel, we wait.
+ */
+ start_migration = !migrate_use_multifd();
+ } else {
+ /* Multiple connections */
+ assert(migrate_use_multifd());
+ start_migration = multifd_recv_new_channel(ioc);
+ }
+
+ if (start_migration) {
+ migration_incoming_process();
}
- multifd_recv_new_channel(ioc);
}
/**
@@ -881,6 +911,8 @@ static void fill_destination_migration_info(MigrationInfo *info)
case MIGRATION_STATUS_CANCELLED:
case MIGRATION_STATUS_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_ACTIVE:
+ case MIGRATION_STATUS_POSTCOPY_PAUSED:
+ case MIGRATION_STATUS_POSTCOPY_RECOVER:
case MIGRATION_STATUS_FAILED:
case MIGRATION_STATUS_COLO:
info->has_status = true;
diff --git a/migration/ram.c b/migration/ram.c
index 1cd98d6..52dd678 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -235,7 +235,7 @@ int64_t ramblock_recv_bitmap_send(QEMUFile *file,
bitmap_to_le(le_bitmap, block->receivedmap, nbits);
/* Size of the bitmap, in bytes */
- size = nbits / 8;
+ size = DIV_ROUND_UP(nbits, 8);
/*
* size is always aligned to 8 bytes for 64bit machines, but it
@@ -1311,7 +1311,8 @@ bool multifd_recv_all_channels_created(void)
return thread_count == atomic_read(&multifd_recv_state->count);
}
-void multifd_recv_new_channel(QIOChannel *ioc)
+/* Return true if multifd is ready for the migration, otherwise false */
+bool multifd_recv_new_channel(QIOChannel *ioc)
{
MultiFDRecvParams *p;
Error *local_err = NULL;
@@ -1320,7 +1321,7 @@ void multifd_recv_new_channel(QIOChannel *ioc)
id = multifd_recv_initial_packet(ioc, &local_err);
if (id < 0) {
multifd_recv_terminate_threads(local_err);
- return;
+ return false;
}
p = &multifd_recv_state->params[id];
@@ -1328,7 +1329,7 @@ void multifd_recv_new_channel(QIOChannel *ioc)
error_setg(&local_err, "multifd: received id '%d' already setup'",
id);
multifd_recv_terminate_threads(local_err);
- return;
+ return false;
}
p->c = ioc;
object_ref(OBJECT(ioc));
@@ -1339,9 +1340,7 @@ void multifd_recv_new_channel(QIOChannel *ioc)
qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p,
QEMU_THREAD_JOINABLE);
atomic_inc(&multifd_recv_state->count);
- if (multifd_recv_state->count == migrate_multifd_channels()) {
- migration_incoming_process();
- }
+ return multifd_recv_state->count == migrate_multifd_channels();
}
/**
@@ -3581,7 +3580,7 @@ static int ram_load_postcopy(QEMUFile *f)
{
int flags = 0, ret = 0;
bool place_needed = false;
- bool matching_page_sizes = false;
+ bool matches_target_page_size = false;
MigrationIncomingState *mis = migration_incoming_get_current();
/* Temporary page that is later 'placed' */
void *postcopy_host_page = postcopy_get_tmp_page(mis);
@@ -3621,7 +3620,7 @@ static int ram_load_postcopy(QEMUFile *f)
ret = -EINVAL;
break;
}
- matching_page_sizes = block->page_size == TARGET_PAGE_SIZE;
+ matches_target_page_size = block->page_size == TARGET_PAGE_SIZE;
/*
* Postcopy requires that we place whole host pages atomically;
* these may be huge pages for RAMBlocks that are backed by
@@ -3669,12 +3668,17 @@ static int ram_load_postcopy(QEMUFile *f)
case RAM_SAVE_FLAG_PAGE:
all_zero = false;
- if (!place_needed || !matching_page_sizes) {
+ if (!matches_target_page_size) {
+ /* For huge pages, we always use temporary buffer */
qemu_get_buffer(f, page_buffer, TARGET_PAGE_SIZE);
} else {
- /* Avoids the qemu_file copy during postcopy, which is
- * going to do a copy later; can only do it when we
- * do this read in one go (matching page sizes)
+ /*
+ * For small pages that matches target page size, we
+ * avoid the qemu_file copy. Instead we directly use
+ * the buffer of QEMUFile to place the page. Note: we
+ * cannot do any QEMUFile operation before using that
+ * buffer to make sure the buffer is valid when
+ * placing the page.
*/
qemu_get_buffer_in_place(f, (uint8_t **)&place_source,
TARGET_PAGE_SIZE);
@@ -3940,7 +3944,7 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block)
int ret = -EINVAL;
QEMUFile *file = s->rp_state.from_dst_file;
unsigned long *le_bitmap, nbits = block->used_length >> TARGET_PAGE_BITS;
- uint64_t local_size = nbits / 8;
+ uint64_t local_size = DIV_ROUND_UP(nbits, 8);
uint64_t size, end_mark;
trace_ram_dirty_bitmap_reload_begin(block->idstr);
diff --git a/migration/ram.h b/migration/ram.h
index d386f4d..457bf54 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -46,7 +46,7 @@ int multifd_save_cleanup(Error **errp);
int multifd_load_setup(void);
int multifd_load_cleanup(Error **errp);
bool multifd_recv_all_channels_created(void);
-void multifd_recv_new_channel(QIOChannel *ioc);
+bool multifd_recv_new_channel(QIOChannel *ioc);
uint64_t ram_pagesize_summary(void);
int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len);
diff --git a/migration/savevm.c b/migration/savevm.c
index c2f34ff..7f92567 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -81,8 +81,8 @@ enum qemu_vm_cmd {
MIG_CMD_POSTCOPY_RAM_DISCARD, /* A list of pages to discard that
were previously sent during
precopy but are dirty. */
- MIG_CMD_POSTCOPY_RESUME, /* resume postcopy on dest */
MIG_CMD_PACKAGED, /* Send a wrapped stream within this stream */
+ MIG_CMD_POSTCOPY_RESUME, /* resume postcopy on dest */
MIG_CMD_RECV_BITMAP, /* Request for recved bitmap on dst */
MIG_CMD_MAX
};
@@ -2194,9 +2194,6 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis)
/* Clear the triggered bit to allow one recovery */
mis->postcopy_recover_triggered = false;
- migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
- MIGRATION_STATUS_POSTCOPY_PAUSED);
-
assert(mis->from_src_file);
qemu_file_shutdown(mis->from_src_file);
qemu_fclose(mis->from_src_file);
@@ -2209,6 +2206,9 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis)
mis->to_src_file = NULL;
qemu_mutex_unlock(&mis->rp_mutex);
+ migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
+ MIGRATION_STATUS_POSTCOPY_PAUSED);
+
/* Notify the fault thread for the invalidated file handle */
postcopy_fault_thread_notify(mis);
@@ -2276,18 +2276,14 @@ out:
qemu_file_set_error(f, ret);
/*
- * Detect whether it is:
- *
- * 1. postcopy running (after receiving all device data, which
- * must be in POSTCOPY_INCOMING_RUNNING state. Note that
- * POSTCOPY_INCOMING_LISTENING is still not enough, it's
- * still receiving device states).
- * 2. network failure (-EIO)
- *
- * If so, we try to wait for a recovery.
+ * If we are during an active postcopy, then we pause instead
+ * of bail out to at least keep the VM's dirty data. Note
+ * that POSTCOPY_INCOMING_LISTENING stage is still not enough,
+ * during which we're still receiving device states and we
+ * still haven't yet started the VM on destination.
*/
if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING &&
- ret == -EIO && postcopy_pause_incoming(mis)) {
+ postcopy_pause_incoming(mis)) {
/* Reset f to point to the newly created channel */
f = mis->from_src_file;
goto retry;
diff --git a/migration/socket.c b/migration/socket.c
index 3456eb7..f4c8174 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -168,12 +168,7 @@ static void socket_accept_incoming_migration(QIONetListener *listener,
if (migration_has_all_channels()) {
/* Close listening socket as its no longer needed */
qio_net_listener_disconnect(listener);
-
object_unref(OBJECT(listener));
-
- if (!migrate_use_multifd()) {
- migration_incoming_process();
- }
}
}