|
@@ -111,32 +111,28 @@ MigrationState *migrate_get_current(void)
|
|
return ¤t_migration;
|
|
return ¤t_migration;
|
|
}
|
|
}
|
|
|
|
|
|
-/* For incoming */
|
|
|
|
-static MigrationIncomingState *mis_current;
|
|
|
|
-
|
|
|
|
MigrationIncomingState *migration_incoming_get_current(void)
|
|
MigrationIncomingState *migration_incoming_get_current(void)
|
|
{
|
|
{
|
|
- return mis_current;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-MigrationIncomingState *migration_incoming_state_new(QEMUFile* f)
|
|
|
|
-{
|
|
|
|
- mis_current = g_new0(MigrationIncomingState, 1);
|
|
|
|
- mis_current->from_src_file = f;
|
|
|
|
- mis_current->state = MIGRATION_STATUS_NONE;
|
|
|
|
- QLIST_INIT(&mis_current->loadvm_handlers);
|
|
|
|
- qemu_mutex_init(&mis_current->rp_mutex);
|
|
|
|
- qemu_event_init(&mis_current->main_thread_load_event, false);
|
|
|
|
|
|
+ static bool once;
|
|
|
|
+ static MigrationIncomingState mis_current;
|
|
|
|
|
|
- return mis_current;
|
|
|
|
|
|
+ if (!once) {
|
|
|
|
+ mis_current.state = MIGRATION_STATUS_NONE;
|
|
|
|
+ memset(&mis_current, 0, sizeof(MigrationIncomingState));
|
|
|
|
+ QLIST_INIT(&mis_current.loadvm_handlers);
|
|
|
|
+ qemu_mutex_init(&mis_current.rp_mutex);
|
|
|
|
+ qemu_event_init(&mis_current.main_thread_load_event, false);
|
|
|
|
+ once = true;
|
|
|
|
+ }
|
|
|
|
+ return &mis_current;
|
|
}
|
|
}
|
|
|
|
|
|
void migration_incoming_state_destroy(void)
|
|
void migration_incoming_state_destroy(void)
|
|
{
|
|
{
|
|
- qemu_event_destroy(&mis_current->main_thread_load_event);
|
|
|
|
- loadvm_free_handlers(mis_current);
|
|
|
|
- g_free(mis_current);
|
|
|
|
- mis_current = NULL;
|
|
|
|
|
|
+ struct MigrationIncomingState *mis = migration_incoming_get_current();
|
|
|
|
+
|
|
|
|
+ qemu_event_destroy(&mis->main_thread_load_event);
|
|
|
|
+ loadvm_free_handlers(mis);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -382,11 +378,11 @@ static void process_incoming_migration_bh(void *opaque)
|
|
static void process_incoming_migration_co(void *opaque)
|
|
static void process_incoming_migration_co(void *opaque)
|
|
{
|
|
{
|
|
QEMUFile *f = opaque;
|
|
QEMUFile *f = opaque;
|
|
- MigrationIncomingState *mis;
|
|
|
|
|
|
+ MigrationIncomingState *mis = migration_incoming_get_current();
|
|
PostcopyState ps;
|
|
PostcopyState ps;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- mis = migration_incoming_state_new(f);
|
|
|
|
|
|
+ mis->from_src_file = f;
|
|
postcopy_state_set(POSTCOPY_INCOMING_NONE);
|
|
postcopy_state_set(POSTCOPY_INCOMING_NONE);
|
|
migrate_set_state(&mis->state, MIGRATION_STATUS_NONE,
|
|
migrate_set_state(&mis->state, MIGRATION_STATUS_NONE,
|
|
MIGRATION_STATUS_ACTIVE);
|
|
MIGRATION_STATUS_ACTIVE);
|
|
@@ -1605,6 +1601,7 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
|
|
QIOChannelBuffer *bioc;
|
|
QIOChannelBuffer *bioc;
|
|
QEMUFile *fb;
|
|
QEMUFile *fb;
|
|
int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
|
|
int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
|
|
|
|
+ bool restart_block = false;
|
|
migrate_set_state(&ms->state, MIGRATION_STATUS_ACTIVE,
|
|
migrate_set_state(&ms->state, MIGRATION_STATUS_ACTIVE,
|
|
MIGRATION_STATUS_POSTCOPY_ACTIVE);
|
|
MIGRATION_STATUS_POSTCOPY_ACTIVE);
|
|
|
|
|
|
@@ -1624,6 +1621,7 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
+ restart_block = true;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Cause any non-postcopiable, but iterative devices to
|
|
* Cause any non-postcopiable, but iterative devices to
|
|
@@ -1680,6 +1678,18 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
|
|
|
|
|
|
/* <><> end of stuff going into the package */
|
|
/* <><> end of stuff going into the package */
|
|
|
|
|
|
|
|
+ /* Last point of recovery; as soon as we send the package the destination
|
|
|
|
+ * can open devices and potentially start running.
|
|
|
|
+ * Lets just check again we've not got any errors.
|
|
|
|
+ */
|
|
|
|
+ ret = qemu_file_get_error(ms->to_dst_file);
|
|
|
|
+ if (ret) {
|
|
|
|
+ error_report("postcopy_start: Migration stream errored (pre package)");
|
|
|
|
+ goto fail_closefb;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ restart_block = false;
|
|
|
|
+
|
|
/* Now send that blob */
|
|
/* Now send that blob */
|
|
if (qemu_savevm_send_packaged(ms->to_dst_file, bioc->data, bioc->usage)) {
|
|
if (qemu_savevm_send_packaged(ms->to_dst_file, bioc->data, bioc->usage)) {
|
|
goto fail_closefb;
|
|
goto fail_closefb;
|
|
@@ -1717,6 +1727,17 @@ fail_closefb:
|
|
fail:
|
|
fail:
|
|
migrate_set_state(&ms->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
|
|
migrate_set_state(&ms->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
|
|
MIGRATION_STATUS_FAILED);
|
|
MIGRATION_STATUS_FAILED);
|
|
|
|
+ if (restart_block) {
|
|
|
|
+ /* A failure happened early enough that we know the destination hasn't
|
|
|
|
+ * accessed block devices, so we're safe to recover.
|
|
|
|
+ */
|
|
|
|
+ Error *local_err = NULL;
|
|
|
|
+
|
|
|
|
+ bdrv_invalidate_cache_all(&local_err);
|
|
|
|
+ if (local_err) {
|
|
|
|
+ error_report_err(local_err);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
qemu_mutex_unlock_iothread();
|
|
qemu_mutex_unlock_iothread();
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|