migration: Handle error in the early async paths

Simplify migration_channel_connect() and migration_connect() to not
take an error as input. Move the error handling into the paths that
generate the error.

To achieve this, call migration_connect_error_propagate() from
socket.c and tls.c, which are the async paths.

For the sync paths, the handling is done as normal by returning all
the way to qmp_migrate_finish(), except that now the sync paths don't
pass the error forward into migration_connect() anymore.

Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Prasad Pandit <pjp@fedoraproject.org>
Link: https://lore.kernel.org/qemu-devel/20260123141656.6765-13-farosas@suse.de
Signed-off-by: Fabiano Rosas <farosas@suse.de>
This commit is contained in:
Fabiano Rosas
2026-01-23 11:16:42 -03:00
parent 6b587af5ec
commit b6ef92ddbd
12 changed files with 50 additions and 61 deletions

View File

@@ -60,38 +60,35 @@ void migration_channel_process_incoming(QIOChannel *ioc)
*
* @s: Current migration state
* @ioc: Channel to which we are connecting
* @error: Error indicating failure to connect, free'd here
*/
void migration_channel_connect(MigrationState *s,
QIOChannel *ioc,
Error *error)
void migration_channel_connect(MigrationState *s, QIOChannel *ioc)
{
trace_migration_set_outgoing_channel(
ioc, object_get_typename(OBJECT(ioc)), error);
trace_migration_set_outgoing_channel(ioc, object_get_typename(OBJECT(ioc)));
if (!error) {
if (migrate_channel_requires_tls_upgrade(ioc)) {
migration_tls_channel_connect(s, ioc, &error);
if (migrate_channel_requires_tls_upgrade(ioc)) {
Error *local_err = NULL;
if (!error) {
/* tls_channel_connect will call back to this
* function after the TLS handshake,
* so we mustn't call migration_connect until then
*/
return;
}
} else {
QEMUFile *f = qemu_file_new_output(ioc);
migration_ioc_register_yank(ioc);
qemu_mutex_lock(&s->qemu_file_lock);
s->to_dst_file = f;
qemu_mutex_unlock(&s->qemu_file_lock);
migration_tls_channel_connect(s, ioc, &local_err);
if (local_err) {
migration_connect_error_propagate(s, local_err);
}
/*
* async: the above will call back to this function after
* the TLS handshake is successfully completed.
*/
return;
}
migration_connect(s, error);
QEMUFile *f = qemu_file_new_output(ioc);
migration_ioc_register_yank(ioc);
qemu_mutex_lock(&s->qemu_file_lock);
s->to_dst_file = f;
qemu_mutex_unlock(&s->qemu_file_lock);
migration_connect(s);
}

View File

@@ -20,9 +20,7 @@
void migration_channel_process_incoming(QIOChannel *ioc);
void migration_channel_connect(MigrationState *s,
QIOChannel *ioc,
Error *error_in);
void migration_channel_connect(MigrationState *s, QIOChannel *ioc);
int migration_channel_read_peek(QIOChannel *ioc,
const char *buf,

View File

@@ -55,7 +55,7 @@ void exec_start_outgoing_migration(MigrationState *s, strList *command,
}
qio_channel_set_name(ioc, "migration-exec-outgoing");
migration_channel_connect(s, ioc, NULL);
migration_channel_connect(s, ioc);
object_unref(OBJECT(ioc));
}

View File

@@ -72,7 +72,7 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **
}
qio_channel_set_name(ioc, "migration-fd-outgoing");
migration_channel_connect(s, ioc, NULL);
migration_channel_connect(s, ioc);
object_unref(OBJECT(ioc));
}

View File

@@ -122,7 +122,7 @@ void file_start_outgoing_migration(MigrationState *s,
return;
}
qio_channel_set_name(ioc, "migration-file-outgoing");
migration_channel_connect(s, ioc, NULL);
migration_channel_connect(s, ioc);
}
static gboolean file_accept_incoming_migration(QIOChannel *ioc,

View File

@@ -1569,7 +1569,7 @@ static void migrate_error_free(MigrationState *s)
s->error = NULL;
}
static void migration_connect_error_propagate(MigrationState *s, Error *error)
void migration_connect_error_propagate(MigrationState *s, Error *error)
{
MigrationStatus current = s->state;
MigrationStatus next = MIGRATION_STATUS_NONE;
@@ -4020,7 +4020,7 @@ fail_setup:
return NULL;
}
void migration_connect(MigrationState *s, Error *error_in)
void migration_connect(MigrationState *s)
{
Error *local_err = NULL;
uint64_t rate_limit;
@@ -4028,13 +4028,6 @@ void migration_connect(MigrationState *s, Error *error_in)
int ret;
s->expected_downtime = migrate_downtime_limit();
if (error_in) {
migration_connect_error_propagate(s, error_in);
if (s->error) {
error_report_err(error_copy(s->error));
}
return;
}
if (resume) {
/* This is a resumed migration */

View File

@@ -533,10 +533,11 @@ void migration_incoming_process(void);
bool migration_has_all_channels(void);
void migration_connect_error_propagate(MigrationState *s, Error *error);
void migrate_error_propagate(MigrationState *s, Error *error);
bool migrate_has_error(MigrationState *s);
void migration_connect(MigrationState *s, Error *error_in);
void migration_connect(MigrationState *s);
int migration_call_notifiers(MigrationEventType type, Error **errp);

View File

@@ -3996,7 +3996,7 @@ void rdma_start_outgoing_migration(void *opaque,
s->to_dst_file = rdma_new_output(rdma);
s->rdma_migration = true;
migration_connect(s, NULL);
migration_connect(s);
return;
return_path_err:
qemu_rdma_cleanup(rdma);

View File

@@ -59,24 +59,25 @@ static void socket_outgoing_migration(QIOTask *task,
gpointer opaque)
{
struct SocketConnectData *data = opaque;
QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
g_autoptr(QIOChannel) sioc = QIO_CHANNEL(qio_task_get_source(task));
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
trace_migration_socket_outgoing_error(error_get_pretty(err));
goto out;
goto fail;
}
trace_migration_socket_outgoing_connected();
if (migrate_zero_copy_send() &&
!qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) {
error_setg(&err, "Zero copy send feature not detected in host kernel");
goto fail;
}
out:
migration_channel_connect(data->s, sioc, err);
object_unref(OBJECT(sioc));
trace_migration_socket_outgoing_connected();
migration_channel_connect(data->s, sioc);
return;
fail:
trace_migration_socket_outgoing_error(error_get_pretty(err));
migration_connect_error_propagate(data->s, err);
}
void socket_start_outgoing_migration(MigrationState *s,

View File

@@ -104,16 +104,17 @@ static void migration_tls_outgoing_handshake(QIOTask *task,
gpointer opaque)
{
MigrationState *s = opaque;
QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task));
g_autoptr(QIOChannel) ioc = QIO_CHANNEL(qio_task_get_source(task));
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
} else {
trace_migration_tls_outgoing_handshake_complete();
migration_connect_error_propagate(s, err);
return;
}
migration_channel_connect(s, ioc, err);
object_unref(OBJECT(ioc));
trace_migration_tls_outgoing_handshake_complete();
migration_channel_connect(s, ioc);
}
QIOChannelTLS *migration_tls_client_create(QIOChannel *ioc,
@@ -129,8 +130,7 @@ QIOChannelTLS *migration_tls_client_create(QIOChannel *ioc,
return qio_channel_tls_new_client(ioc, creds, migrate_tls_hostname(), errp);
}
void migration_tls_channel_connect(MigrationState *s,
QIOChannel *ioc,
void migration_tls_channel_connect(MigrationState *s, QIOChannel *ioc,
Error **errp)
{
QIOChannelTLS *tioc;

View File

@@ -29,8 +29,7 @@ void migration_tls_channel_process_incoming(QIOChannel *ioc, Error **errp);
QIOChannelTLS *migration_tls_client_create(QIOChannel *ioc,
Error **errp);
void migration_tls_channel_connect(MigrationState *s,
QIOChannel *ioc,
void migration_tls_channel_connect(MigrationState *s, QIOChannel *ioc,
Error **errp);
void migration_tls_channel_end(QIOChannel *ioc, Error **errp);
/* Whether the QIO channel requires further TLS handshake? */

View File

@@ -204,7 +204,7 @@ migration_transferred_bytes(uint64_t qemu_file, uint64_t multifd, uint64_t rdma)
# channel.c
migration_set_incoming_channel(void *ioc, const char *ioctype) "ioc=%p ioctype=%s"
migration_set_outgoing_channel(void *ioc, const char *ioctype, void *err) "ioc=%p ioctype=%s err=%p"
migration_set_outgoing_channel(void *ioc, const char *ioctype) "ioc=%p ioctype=%s"
# global_state.c
migrate_state_too_big(void) ""