aboutsummaryrefslogtreecommitdiff
path: root/migration/migration.c
diff options
context:
space:
mode:
Diffstat (limited to 'migration/migration.c')
-rw-r--r--migration/migration.c116
1 files changed, 81 insertions, 35 deletions
diff --git a/migration/migration.c b/migration/migration.c
index e1ac4d7..a63b46b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -74,11 +74,7 @@
#define INMIGRATE_DEFAULT_EXIT_ON_ERROR true
-static NotifierWithReturnList migration_state_notifiers[] = {
- NOTIFIER_ELEM_INIT(migration_state_notifiers, MIG_MODE_NORMAL),
- NOTIFIER_ELEM_INIT(migration_state_notifiers, MIG_MODE_CPR_REBOOT),
- NOTIFIER_ELEM_INIT(migration_state_notifiers, MIG_MODE_CPR_TRANSFER),
-};
+static GSList *migration_state_notifiers[MIG_MODE__MAX];
/* Messages sent on the return path from destination to source */
enum mig_rp_message_type {
@@ -337,6 +333,7 @@ void migration_object_init(void)
ram_mig_init();
dirty_bitmap_mig_init();
+ cpr_exec_init();
/* Initialize cpu throttle timers */
cpu_throttle_init();
@@ -623,22 +620,22 @@ void migration_incoming_disable_colo(void)
migration_colo_enabled = false;
}
-int migration_incoming_enable_colo(void)
+int migration_incoming_enable_colo(Error **errp)
{
#ifndef CONFIG_REPLICATION
- error_report("ENABLE_COLO command come in migration stream, but the "
- "replication module is not built in");
+ error_setg(errp, "ENABLE_COLO command come in migration stream, but the "
+ "replication module is not built in");
return -ENOTSUP;
#endif
if (!migrate_colo()) {
- error_report("ENABLE_COLO command come in migration stream, but x-colo "
- "capability is not set");
+ error_setg(errp, "ENABLE_COLO command come in migration stream"
+ ", but x-colo capability is not set");
return -EINVAL;
}
if (ram_block_discard_disable(true)) {
- error_report("COLO: cannot disable RAM discard");
+ error_setg(errp, "COLO: cannot disable RAM discard");
return -EBUSY;
}
migration_colo_enabled = true;
@@ -881,7 +878,7 @@ process_incoming_migration_co(void *opaque)
MIGRATION_STATUS_ACTIVE);
mis->loadvm_co = qemu_coroutine_self();
- ret = qemu_loadvm_state(mis->from_src_file);
+ ret = qemu_loadvm_state(mis->from_src_file, &local_err);
mis->loadvm_co = NULL;
trace_vmstate_downtime_checkpoint("dst-precopy-loadvm-completed");
@@ -908,7 +905,8 @@ process_incoming_migration_co(void *opaque)
}
if (ret < 0) {
- error_setg(&local_err, "load of migration failed: %s", strerror(-ret));
+ error_prepend(&local_err, "load of migration failed: %s: ",
+ strerror(-ret));
goto fail;
}
@@ -935,6 +933,15 @@ fail:
}
exit(EXIT_FAILURE);
+ } else {
+ /*
+ * Report the error here in case that QEMU abruptly exits
+ * when postcopy is enabled.
+ */
+ WITH_QEMU_LOCK_GUARD(&s->error_mutex) {
+ error_report_err(s->error);
+ s->error = NULL;
+ }
}
out:
/* Pairs with the refcount taken in qmp_migrate_incoming() */
@@ -1665,23 +1672,51 @@ void migration_cancel(void)
}
}
+static int get_modes(MigMode mode, va_list ap);
+
+static void add_notifiers(NotifierWithReturn *notify, int modes)
+{
+ for (MigMode mode = 0; mode < MIG_MODE__MAX; mode++) {
+ if (modes & BIT(mode)) {
+ migration_state_notifiers[mode] =
+ g_slist_prepend(migration_state_notifiers[mode], notify);
+ }
+ }
+}
+
+void migration_add_notifier_modes(NotifierWithReturn *notify,
+ MigrationNotifyFunc func, MigMode mode, ...)
+{
+ int modes;
+ va_list ap;
+
+ va_start(ap, mode);
+ modes = get_modes(mode, ap);
+ va_end(ap);
+
+ notify->notify = (NotifierWithReturnFunc)func;
+ add_notifiers(notify, modes);
+}
+
void migration_add_notifier_mode(NotifierWithReturn *notify,
MigrationNotifyFunc func, MigMode mode)
{
- notify->notify = (NotifierWithReturnFunc)func;
- notifier_with_return_list_add(&migration_state_notifiers[mode], notify);
+ migration_add_notifier_modes(notify, func, mode, -1);
}
void migration_add_notifier(NotifierWithReturn *notify,
MigrationNotifyFunc func)
{
- migration_add_notifier_mode(notify, func, MIG_MODE_NORMAL);
+ migration_add_notifier_modes(notify, func, MIG_MODE_NORMAL, -1);
}
void migration_remove_notifier(NotifierWithReturn *notify)
{
if (notify->notify) {
- notifier_with_return_remove(notify);
+ for (MigMode mode = 0; mode < MIG_MODE__MAX; mode++) {
+ migration_blockers[mode] =
+ g_slist_remove(migration_state_notifiers[mode], notify);
+ }
notify->notify = NULL;
}
}
@@ -1691,18 +1726,29 @@ int migration_call_notifiers(MigrationState *s, MigrationEventType type,
{
MigMode mode = s->parameters.mode;
MigrationEvent e;
+ NotifierWithReturn *notifier;
+ GSList *elem, *next;
int ret;
e.type = type;
- ret = notifier_with_return_list_notify(&migration_state_notifiers[mode],
- &e, errp);
- assert(!ret || type == MIG_EVENT_PRECOPY_SETUP);
- return ret;
+
+ for (elem = migration_state_notifiers[mode]; elem; elem = next) {
+ next = elem->next;
+ notifier = (NotifierWithReturn *)elem->data;
+ ret = notifier->notify(notifier, &e, errp);
+ if (ret) {
+ assert(type == MIG_EVENT_PRECOPY_SETUP);
+ return ret;
+ }
+ }
+
+ return 0;
}
bool migration_has_failed(MigrationState *s)
{
- return (s->state == MIGRATION_STATUS_CANCELLED ||
+ return (s->state == MIGRATION_STATUS_CANCELLING ||
+ s->state == MIGRATION_STATUS_CANCELLED ||
s->state == MIGRATION_STATUS_FAILED);
}
@@ -1762,7 +1808,8 @@ bool migrate_mode_is_cpr(MigrationState *s)
{
MigMode mode = s->parameters.mode;
return mode == MIG_MODE_CPR_REBOOT ||
- mode == MIG_MODE_CPR_TRANSFER;
+ mode == MIG_MODE_CPR_TRANSFER ||
+ mode == MIG_MODE_CPR_EXEC;
}
int migrate_init(MigrationState *s, Error **errp)
@@ -2111,6 +2158,12 @@ static bool migrate_prepare(MigrationState *s, bool resume, Error **errp)
return false;
}
+ if (migrate_mode() == MIG_MODE_CPR_EXEC &&
+ !s->parameters.has_cpr_exec_command) {
+ error_setg(errp, "cpr-exec mode requires setting cpr-exec-command");
+ return false;
+ }
+
if (migration_is_blocked(errp)) {
return false;
}
@@ -2646,12 +2699,9 @@ out:
return NULL;
}
-static int open_return_path_on_source(MigrationState *ms)
+static void open_return_path_on_source(MigrationState *ms)
{
ms->rp_state.from_dst_file = qemu_file_get_return_path(ms->to_dst_file);
- if (!ms->rp_state.from_dst_file) {
- return -1;
- }
trace_open_return_path_on_source();
@@ -2660,8 +2710,6 @@ static int open_return_path_on_source(MigrationState *ms)
ms->rp_state.rp_thread_created = true;
trace_open_return_path_on_source_continue();
-
- return 0;
}
/* Return true if error detected, or false otherwise */
@@ -2872,8 +2920,9 @@ static int postcopy_start(MigrationState *ms, Error **errp)
fail_closefb:
qemu_fclose(fb);
fail:
- migrate_set_state(&ms->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
- MIGRATION_STATUS_FAILED);
+ if (ms->state != MIGRATION_STATUS_CANCELLING) {
+ migrate_set_state(&ms->state, ms->state, MIGRATION_STATUS_FAILED);
+ }
migration_block_activate(NULL);
migration_call_notifiers(ms, MIG_EVENT_PRECOPY_FAILED, NULL);
bql_unlock();
@@ -4012,10 +4061,7 @@ void migration_connect(MigrationState *s, Error *error_in)
* QEMU uses the return path.
*/
if (migrate_postcopy_ram() || migrate_return_path()) {
- if (open_return_path_on_source(s)) {
- error_setg(&local_err, "Unable to open return-path for postcopy");
- goto fail;
- }
+ open_return_path_on_source(s);
}
/*