Files
qemu-qemu/migration/channel.c
Fabiano Rosas b6ef92ddbd 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>
2026-01-23 11:32:17 -03:00

136 lines
3.5 KiB
C

/*
* QEMU live migration channel operations
*
* Copyright Red Hat, Inc. 2016
*
* Authors:
* Daniel P. Berrange <berrange@redhat.com>
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu/osdep.h"
#include "channel.h"
#include "tls.h"
#include "migration.h"
#include "qemu-file.h"
#include "trace.h"
#include "qapi/error.h"
#include "io/channel-tls.h"
#include "io/channel-socket.h"
#include "qemu/yank.h"
#include "yank_functions.h"
/**
* @migration_channel_process_incoming - Create new incoming migration channel
*
* Notice that TLS is special. For it we listen in a listener socket,
* and then create a new client socket from the TLS library.
*
* @ioc: Channel to which we are connecting
*/
void migration_channel_process_incoming(QIOChannel *ioc)
{
MigrationIncomingState *mis = migration_incoming_get_current();
Error *local_err = NULL;
trace_migration_set_incoming_channel(
ioc, object_get_typename(OBJECT(ioc)));
if (migrate_channel_requires_tls_upgrade(ioc)) {
migration_tls_channel_process_incoming(ioc, &local_err);
} else {
migration_ioc_register_yank(ioc);
migration_ioc_process_incoming(ioc, &local_err);
}
if (local_err) {
error_report_err(local_err);
migrate_set_state(&mis->state, mis->state, MIGRATION_STATUS_FAILED);
if (mis->exit_on_error) {
exit(EXIT_FAILURE);
}
}
}
/**
* @migration_channel_connect - Create new outgoing migration channel
*
* @s: Current migration state
* @ioc: Channel to which we are connecting
*/
void migration_channel_connect(MigrationState *s, QIOChannel *ioc)
{
trace_migration_set_outgoing_channel(ioc, object_get_typename(OBJECT(ioc)));
if (migrate_channel_requires_tls_upgrade(ioc)) {
Error *local_err = NULL;
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;
}
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);
}
/**
* @migration_channel_read_peek - Peek at migration channel, without
* actually removing it from channel buffer.
*
* @ioc: the channel object
* @buf: the memory region to read data into
* @buflen: the number of bytes to read in @buf
* @errp: pointer to a NULL-initialized error object
*
* Returns 0 if successful, returns -1 and sets @errp if fails.
*/
int migration_channel_read_peek(QIOChannel *ioc,
const char *buf,
const size_t buflen,
Error **errp)
{
ssize_t len = 0;
struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
while (true) {
len = qio_channel_readv_full(ioc, &iov, 1, NULL, NULL,
QIO_CHANNEL_READ_FLAG_MSG_PEEK, errp);
if (len < 0 && len != QIO_CHANNEL_ERR_BLOCK) {
return -1;
}
if (len == 0) {
error_setg(errp, "Failed to peek at channel");
return -1;
}
if (len == buflen) {
break;
}
qio_channel_wait_cond(ioc, G_IO_IN);
}
return 0;
}