error_report_err(error_copy(err));
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
- migrate_set_error(s, err);
- error_free(err);
+
+ migrate_error_propagate(s, err);
+ /* We must reset the error because it'll be reused later */
err = NULL;
/* Note, we can go from state COMPLETED to FAILED */
fail:
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
- migrate_set_error(s, local_err);
- error_free(local_err);
-
+ migrate_error_propagate(s, local_err);
migration_incoming_state_destroy();
if (mis->exit_on_error) {
migration_cleanup(opaque);
}
-void migrate_set_error(MigrationState *s, const Error *error)
+/*
+ * Propagate the Error* object to migration core. The caller mustn't
+ * reference the error pointer after the function returned, because the
+ * Error* object might be freed.
+ */
+void migrate_error_propagate(MigrationState *s, Error *error)
{
QEMU_LOCK_GUARD(&s->error_mutex);
-
trace_migrate_error(error_get_pretty(error));
if (!s->error) {
- s->error = error_copy(error);
+ s->error = error;
+ } else {
+ error_free(error);
}
}
}
migrate_set_state(&s->state, current, next);
- migrate_set_error(s, error);
- error_free(error);
+ migrate_error_propagate(s, error);
}
void migration_cancel(void)
/* Tell the core migration that we're pausing */
error_setg(&error, "Postcopy migration is paused by the user");
- migrate_set_error(ms, error);
- error_free(error);
+ migrate_error_propagate(ms, error);
qemu_mutex_lock(&ms->qemu_file_lock);
if (ms->to_dst_file) {
out:
if (err) {
- migrate_set_error(ms, err);
- error_free(err);
+ migrate_error_propagate(ms, err);
trace_source_return_path_thread_bad_end();
}
fail:
if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(s, local_err);
} else if (ret) {
error_setg_errno(&local_err, -ret, "Error in migration completion");
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(s, local_err);
}
if (s->state != MIGRATION_STATUS_CANCELLING) {
}
if (local_error) {
- migrate_set_error(s, local_error);
- error_free(local_error);
+ migrate_error_propagate(s, local_error);
}
if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret) {
if (must_precopy <= s->threshold_size &&
can_switchover && qatomic_read(&s->start_postcopy)) {
if (postcopy_start(s, &local_err)) {
- migrate_set_error(s, local_err);
+ migrate_error_propagate(s, error_copy(local_err));
error_report_err(local_err);
}
return MIG_ITERATE_SKIP;
* devices to unplug. This to preserve migration state transitions.
*/
if (ret) {
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(s, local_err);
migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
goto out;
* devices to unplug. This to preserve migration state transitions.
*/
if (ret) {
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(s, local_err);
migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
goto fail_setup;
return;
fail:
- migrate_set_error(s, local_err);
+ migrate_error_propagate(s, error_copy(local_err));
if (s->state != MIGRATION_STATUS_CANCELLING) {
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
}
bool migration_has_all_channels(void);
-void migrate_set_error(MigrationState *s, const Error *error);
+void migrate_error_propagate(MigrationState *s, Error *error);
bool migrate_has_error(MigrationState *s);
void migration_connect(MigrationState *s, Error *error_in);
Error *local_err = NULL;
if (!data->hdlr(data, &local_err)) {
- MigrationState *s = migrate_get_current();
-
/*
* Can't call abort_device_state_save_threads() here since new
* save threads could still be in process of being launched
* In case of multiple save threads failing which thread error
* return we end setting is purely arbitrary.
*/
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(migrate_get_current(), local_err);
}
return 0;
if (err) {
MigrationState *s = migrate_get_current();
- migrate_set_error(s, err);
- error_free(err);
+
+ migrate_error_propagate(s, err);
+
if (s->state == MIGRATION_STATUS_SETUP ||
s->state == MIGRATION_STATUS_PRE_SWITCHOVER ||
s->state == MIGRATION_STATUS_DEVICE ||
Error *local_err = NULL;
if (!multifd_send_cleanup_channel(p, &local_err)) {
- migrate_set_error(migrate_get_current(), local_err);
- error_free(local_err);
+ migrate_error_propagate(migrate_get_current(), local_err);
}
}
p->write_flags = 0;
if (!multifd_new_send_channel_create(p, &local_err)) {
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(s, local_err);
ret = -1;
}
}
ret = multifd_send_state->ops->send_setup(p, &local_err);
if (ret) {
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(s, local_err);
goto err;
}
assert(p->iov);
if (err) {
MigrationState *s = migrate_get_current();
- migrate_set_error(s, err);
- error_free(err);
+
+ migrate_error_propagate(s, err);
+
if (s->state == MIGRATION_STATUS_SETUP ||
s->state == MIGRATION_STATUS_ACTIVE) {
migrate_set_state(&s->state, s->state,
QIOChannel *ioc, Error *local_err)
{
if (local_err) {
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(s, local_err);
} else {
migration_ioc_register_yank(ioc);
s->postcopy_qemufile_src = qemu_file_new_output(ioc);
* exit depending on if postcopy-exit-on-error is true, but the
* migration cannot be recovered.
*/
- migrate_set_error(migr, local_err);
+ migrate_error_propagate(migr, error_copy(local_err));
error_report_err(local_err);
migrate_set_state(&mis->state, mis->state, MIGRATION_STATUS_FAILED);
goto out;
* Abort and indicate a proper reason.
*/
error_setg(&err, "RAM block '%s' resized during precopy.", rb->idstr);
- migrate_set_error(migrate_get_current(), err);
- error_free(err);
-
+ migrate_error_propagate(migrate_get_current(), err);
migration_cancel();
}
int qemu_savevm_send_packaged(QEMUFile *f, const uint8_t *buf, size_t len)
{
uint32_t tmp;
- MigrationState *ms = migrate_get_current();
Error *local_err = NULL;
if (len > MAX_VM_CMD_PACKAGED_SIZE) {
error_setg(&local_err, "%s: Unreasonably large packaged state: %zu",
__func__, len);
- migrate_set_error(ms, local_err);
+ migrate_error_propagate(migrate_get_current(),
+ error_copy(local_err));
error_report_err(local_err);
return -1;
}
if (se->vmsd && se->vmsd->early_setup) {
ret = vmstate_save(f, se, vmdesc, errp);
if (ret) {
- migrate_set_error(ms, *errp);
+ migrate_error_propagate(ms, error_copy(*errp));
qemu_file_set_error(f, ret);
break;
}
ret = vmstate_save(f, se, vmdesc, &local_err);
if (ret) {
- migrate_set_error(ms, local_err);
+ migrate_error_propagate(ms, error_copy(local_err));
error_report_err(local_err);
qemu_file_set_error(f, ret);
return ret;
int qemu_save_device_state(QEMUFile *f)
{
- MigrationState *ms = migrate_get_current();
Error *local_err = NULL;
SaveStateEntry *se;
}
ret = vmstate_save(f, se, NULL, &local_err);
if (ret) {
- migrate_set_error(ms, local_err);
+ migrate_error_propagate(migrate_get_current(),
+ error_copy(local_err));
error_report_err(local_err);
return ret;
}
Error *local_err = NULL;
if (!data->function(data->opaque, &mis->load_threads_abort, &local_err)) {
- MigrationState *s = migrate_get_current();
-
/*
* Can't set load_threads_abort here since processing of main migration
* channel data could still be happening, resulting in launching of new
* In case of multiple load threads failing which thread error
* return we end setting is purely arbitrary.
*/
- migrate_set_error(s, local_err);
- error_free(local_err);
+ migrate_error_propagate(migrate_get_current(), local_err);
}
return 0;