return status == MIGRATION_STATUS_POSTCOPY_PAUSED ||
status == MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP;
}
+
+/*
+ * Triggered by a postcopy_listen command; this thread takes over reading
+ * the input stream, leaving the main thread free to carry on loading the rest
+ * of the device state (from RAM).
+ */
+void *postcopy_ram_listen_thread(void *opaque)
+{
+ MigrationIncomingState *mis = migration_incoming_get_current();
+ QEMUFile *f = mis->from_src_file;
+ int load_res;
+ MigrationState *migr = migrate_get_current();
+ Error *local_err = NULL;
+
+ object_ref(OBJECT(migr));
+
+ migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
+ MIGRATION_STATUS_POSTCOPY_ACTIVE);
+ qemu_event_set(&mis->thread_sync_event);
+ trace_postcopy_ram_listen_thread_start();
+
+ rcu_register_thread();
+ /*
+ * Because we're a thread and not a coroutine we can't yield
+ * in qemu_file, and thus we must be blocking now.
+ */
+ qemu_file_set_blocking(f, true, &error_fatal);
+
+ /* TODO: sanity check that only postcopiable data will be loaded here */
+ load_res = qemu_loadvm_state_main(f, mis, &local_err);
+
+ /*
+ * This is tricky, but, mis->from_src_file can change after it
+ * returns, when postcopy recovery happened. In the future, we may
+ * want a wrapper for the QEMUFile handle.
+ */
+ f = mis->from_src_file;
+
+ /* And non-blocking again so we don't block in any cleanup */
+ qemu_file_set_blocking(f, false, &error_fatal);
+
+ trace_postcopy_ram_listen_thread_exit();
+ if (load_res < 0) {
+ qemu_file_set_error(f, load_res);
+ dirty_bitmap_mig_cancel_incoming();
+ if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING &&
+ !migrate_postcopy_ram() && migrate_dirty_bitmaps())
+ {
+ error_report("%s: loadvm failed during postcopy: %d: %s. All states "
+ "are migrated except dirty bitmaps. Some dirty "
+ "bitmaps may be lost, and present migrated dirty "
+ "bitmaps are correctly migrated and valid.",
+ __func__, load_res, error_get_pretty(local_err));
+ g_clear_pointer(&local_err, error_free);
+ load_res = 0; /* prevent further exit() */
+ } else {
+ error_prepend(&local_err,
+ "loadvm failed during postcopy: %d: ", load_res);
+ migrate_set_error(migr, local_err);
+ g_clear_pointer(&local_err, error_report_err);
+ migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
+ MIGRATION_STATUS_FAILED);
+ }
+ }
+ if (load_res >= 0) {
+ /*
+ * This looks good, but it's possible that the device loading in the
+ * main thread hasn't finished yet, and so we might not be in 'RUN'
+ * state yet; wait for the end of the main thread.
+ */
+ qemu_event_wait(&mis->main_thread_load_event);
+ }
+ postcopy_ram_incoming_cleanup(mis);
+
+ if (load_res < 0) {
+ /*
+ * If something went wrong then we have a bad state so exit;
+ * depending how far we got it might be possible at this point
+ * to leave the guest running and fire MCEs for pages that never
+ * arrived as a desperate recovery step.
+ */
+ rcu_unregister_thread();
+ exit(EXIT_FAILURE);
+ }
+
+ migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
+ MIGRATION_STATUS_COMPLETED);
+ /*
+ * If everything has worked fine, then the main thread has waited
+ * for us to start, and we're the last use of the mis.
+ * (If something broke then qemu will have to exit anyway since it's
+ * got a bad migration state).
+ */
+ bql_lock();
+ migration_incoming_state_destroy();
+ bql_unlock();
+
+ rcu_unregister_thread();
+ mis->have_listen_thread = false;
+ postcopy_state_set(POSTCOPY_INCOMING_END);
+
+ object_unref(OBJECT(migr));
+
+ return NULL;
+}
return 0;
}
-/*
- * Triggered by a postcopy_listen command; this thread takes over reading
- * the input stream, leaving the main thread free to carry on loading the rest
- * of the device state (from RAM).
- * (TODO:This could do with being in a postcopy file - but there again it's
- * just another input loop, not that postcopy specific)
- */
-static void *postcopy_ram_listen_thread(void *opaque)
-{
- MigrationIncomingState *mis = migration_incoming_get_current();
- QEMUFile *f = mis->from_src_file;
- int load_res;
- MigrationState *migr = migrate_get_current();
- Error *local_err = NULL;
-
- object_ref(OBJECT(migr));
-
- migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
- MIGRATION_STATUS_POSTCOPY_ACTIVE);
- qemu_event_set(&mis->thread_sync_event);
- trace_postcopy_ram_listen_thread_start();
-
- rcu_register_thread();
- /*
- * Because we're a thread and not a coroutine we can't yield
- * in qemu_file, and thus we must be blocking now.
- */
- qemu_file_set_blocking(f, true, &error_fatal);
-
- /* TODO: sanity check that only postcopiable data will be loaded here */
- load_res = qemu_loadvm_state_main(f, mis, &local_err);
-
- /*
- * This is tricky, but, mis->from_src_file can change after it
- * returns, when postcopy recovery happened. In the future, we may
- * want a wrapper for the QEMUFile handle.
- */
- f = mis->from_src_file;
-
- /* And non-blocking again so we don't block in any cleanup */
- qemu_file_set_blocking(f, false, &error_fatal);
-
- trace_postcopy_ram_listen_thread_exit();
- if (load_res < 0) {
- qemu_file_set_error(f, load_res);
- dirty_bitmap_mig_cancel_incoming();
- if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING &&
- !migrate_postcopy_ram() && migrate_dirty_bitmaps())
- {
- error_report("%s: loadvm failed during postcopy: %d: %s. All states "
- "are migrated except dirty bitmaps. Some dirty "
- "bitmaps may be lost, and present migrated dirty "
- "bitmaps are correctly migrated and valid.",
- __func__, load_res, error_get_pretty(local_err));
- g_clear_pointer(&local_err, error_free);
- load_res = 0; /* prevent further exit() */
- } else {
- error_prepend(&local_err,
- "loadvm failed during postcopy: %d: ", load_res);
- migrate_set_error(migr, local_err);
- g_clear_pointer(&local_err, error_report_err);
- migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
- MIGRATION_STATUS_FAILED);
- }
- }
- if (load_res >= 0) {
- /*
- * This looks good, but it's possible that the device loading in the
- * main thread hasn't finished yet, and so we might not be in 'RUN'
- * state yet; wait for the end of the main thread.
- */
- qemu_event_wait(&mis->main_thread_load_event);
- }
- postcopy_ram_incoming_cleanup(mis);
-
- if (load_res < 0) {
- /*
- * If something went wrong then we have a bad state so exit;
- * depending how far we got it might be possible at this point
- * to leave the guest running and fire MCEs for pages that never
- * arrived as a desperate recovery step.
- */
- rcu_unregister_thread();
- exit(EXIT_FAILURE);
- }
-
- migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
- MIGRATION_STATUS_COMPLETED);
- /*
- * If everything has worked fine, then the main thread has waited
- * for us to start, and we're the last use of the mis.
- * (If something broke then qemu will have to exit anyway since it's
- * got a bad migration state).
- */
- bql_lock();
- migration_incoming_state_destroy();
- bql_unlock();
-
- rcu_unregister_thread();
- mis->have_listen_thread = false;
- postcopy_state_set(POSTCOPY_INCOMING_END);
-
- object_unref(OBJECT(migr));
-
- return NULL;
-}
-
/* After this message we must be able to immediately receive postcopy data */
static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis,
Error **errp)