diff --git a/migration/channel.c b/migration/channel.c index 1e4778455d..1e2935f926 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -37,26 +37,40 @@ void migration_connect_outgoing(MigrationState *s, MigrationAddress *addr, Error **errp) { + g_autoptr(QIOChannel) ioc = NULL; + if (addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) { SocketAddress *saddr = &addr->u.socket; if (saddr->type == SOCKET_ADDRESS_TYPE_INET || saddr->type == SOCKET_ADDRESS_TYPE_UNIX || saddr->type == SOCKET_ADDRESS_TYPE_VSOCK) { socket_connect_outgoing(s, saddr, errp); + /* + * async: after the socket is connected, calls + * migration_channel_connect_outgoing() directly. + */ + return; + } else if (saddr->type == SOCKET_ADDRESS_TYPE_FD) { - fd_connect_outgoing(s, saddr->u.fd.str, errp); + ioc = fd_connect_outgoing(s, saddr->u.fd.str, errp); } #ifdef CONFIG_RDMA } else if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) { - rdma_connect_outgoing(s, &addr->u.rdma, errp); + ioc = rdma_connect_outgoing(s, &addr->u.rdma, errp); #endif } else if (addr->transport == MIGRATION_ADDRESS_TYPE_EXEC) { - exec_connect_outgoing(s, addr->u.exec.args, errp); + ioc = exec_connect_outgoing(s, addr->u.exec.args, errp); } else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) { - file_connect_outgoing(s, &addr->u.file, errp); + ioc = file_connect_outgoing(s, &addr->u.file, errp); } else { error_setg(errp, "uri is not a valid migration protocol"); } + + if (ioc) { + migration_channel_connect_outgoing(s, ioc); + } + + return; } void migration_connect_incoming(MigrationAddress *addr, Error **errp) @@ -81,6 +95,12 @@ void migration_connect_incoming(MigrationAddress *addr, Error **errp) } else { error_setg(errp, "unknown migration protocol"); } + + /* + * async: the above routines all wait for the incoming connection + * and call back to migration_channel_process_incoming() to start + * the migration. + */ } bool migration_has_main_and_multifd_channels(void) diff --git a/migration/exec.c b/migration/exec.c index c3085e803e..a1a7ede3b4 100644 --- a/migration/exec.c +++ b/migration/exec.c @@ -40,7 +40,8 @@ const char *exec_get_cmd_path(void) } #endif -void exec_connect_outgoing(MigrationState *s, strList *command, Error **errp) +QIOChannel *exec_connect_outgoing(MigrationState *s, strList *command, + Error **errp) { QIOChannel *ioc = NULL; g_auto(GStrv) argv = strv_from_str_list(command); @@ -50,12 +51,11 @@ void exec_connect_outgoing(MigrationState *s, strList *command, Error **errp) trace_migration_exec_outgoing(new_command); ioc = QIO_CHANNEL(qio_channel_command_new_spawn(args, O_RDWR, errp)); if (!ioc) { - return; + return NULL; } qio_channel_set_name(ioc, "migration-exec-outgoing"); - migration_channel_connect_outgoing(s, ioc); - object_unref(OBJECT(ioc)); + return ioc; } static gboolean exec_accept_incoming_migration(QIOChannel *ioc, diff --git a/migration/exec.h b/migration/exec.h index e7e8e475ac..3e39270dce 100644 --- a/migration/exec.h +++ b/migration/exec.h @@ -20,10 +20,13 @@ #ifndef QEMU_MIGRATION_EXEC_H #define QEMU_MIGRATION_EXEC_H +#include "io/channel.h" + #ifdef WIN32 const char *exec_get_cmd_path(void); #endif void exec_connect_incoming(strList *host_port, Error **errp); -void exec_connect_outgoing(MigrationState *s, strList *host_port, Error **errp); +QIOChannel *exec_connect_outgoing(MigrationState *s, strList *host_port, + Error **errp); #endif diff --git a/migration/fd.c b/migration/fd.c index 530aac1a5b..f05f95992f 100644 --- a/migration/fd.c +++ b/migration/fd.c @@ -50,30 +50,31 @@ static bool migration_fd_valid(int fd) return false; } -void fd_connect_outgoing(MigrationState *s, const char *fdname, Error **errp) +QIOChannel *fd_connect_outgoing(MigrationState *s, const char *fdname, + Error **errp) { - QIOChannel *ioc; + QIOChannel *ioc = NULL; int fd = monitor_get_fd(monitor_cur(), fdname, errp); if (fd == -1) { - return; + goto out; } if (!migration_fd_valid(fd)) { error_setg(errp, "fd: migration to a file is not supported." " Use file: instead."); - return; + goto out; } trace_migration_fd_outgoing(fd); ioc = qio_channel_new_fd(fd, errp); if (!ioc) { close(fd); - return; + goto out; } qio_channel_set_name(ioc, "migration-fd-outgoing"); - migration_channel_connect_outgoing(s, ioc); - object_unref(OBJECT(ioc)); +out: + return ioc; } static gboolean fd_accept_incoming_migration(QIOChannel *ioc, diff --git a/migration/fd.h b/migration/fd.h index 7211629270..ce0b751273 100644 --- a/migration/fd.h +++ b/migration/fd.h @@ -16,8 +16,11 @@ #ifndef QEMU_MIGRATION_FD_H #define QEMU_MIGRATION_FD_H + +#include "io/channel.h" + void fd_connect_incoming(const char *fdname, Error **errp); -void fd_connect_outgoing(MigrationState *s, const char *fdname, - Error **errp); +QIOChannel *fd_connect_outgoing(MigrationState *s, const char *fdname, + Error **errp); #endif diff --git a/migration/file.c b/migration/file.c index b7b0fb5194..5618aced49 100644 --- a/migration/file.c +++ b/migration/file.c @@ -93,36 +93,38 @@ out: return ret; } -void file_connect_outgoing(MigrationState *s, - FileMigrationArgs *file_args, Error **errp) +QIOChannel *file_connect_outgoing(MigrationState *s, + FileMigrationArgs *file_args, Error **errp) { - g_autoptr(QIOChannelFile) fioc = NULL; + QIOChannelFile *fioc = NULL; g_autofree char *filename = g_strdup(file_args->filename); uint64_t offset = file_args->offset; - QIOChannel *ioc; + QIOChannel *ioc = NULL; trace_migration_file_outgoing(filename); fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY, 0600, errp); if (!fioc) { - return; + goto out; } if (ftruncate(fioc->fd, offset)) { error_setg_errno(errp, errno, "failed to truncate migration file to offset %" PRIx64, offset); - return; + goto out; } outgoing_args.fname = g_strdup(filename); ioc = QIO_CHANNEL(fioc); if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) { - return; + ioc = NULL; + goto out; } qio_channel_set_name(ioc, "migration-file-outgoing"); - migration_channel_connect_outgoing(s, ioc); +out: + return ioc; } static gboolean file_accept_incoming_migration(QIOChannel *ioc, diff --git a/migration/file.h b/migration/file.h index 9b1e874bb7..5936c64fea 100644 --- a/migration/file.h +++ b/migration/file.h @@ -9,14 +9,15 @@ #define QEMU_MIGRATION_FILE_H #include "qapi/qapi-types-migration.h" +#include "io/channel.h" #include "io/task.h" #include "channel.h" #include "multifd.h" void file_connect_incoming(FileMigrationArgs *file_args, Error **errp); -void file_connect_outgoing(MigrationState *s, - FileMigrationArgs *file_args, Error **errp); +QIOChannel *file_connect_outgoing(MigrationState *s, + FileMigrationArgs *file_args, Error **errp); int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp); void file_cleanup_outgoing_migration(void); bool file_send_channel_create(gpointer opaque, Error **errp); diff --git a/migration/rdma.c b/migration/rdma.c index e628a20aec..55ab85650a 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3933,8 +3933,8 @@ err: g_free(rdma); } -void rdma_connect_outgoing(void *opaque, - InetSocketAddress *host_port, Error **errp) +QIOChannel *rdma_connect_outgoing(void *opaque, + InetSocketAddress *host_port, Error **errp) { MigrationState *s = opaque; RDMAContext *rdma_return_path = NULL; @@ -3944,7 +3944,7 @@ void rdma_connect_outgoing(void *opaque, /* Avoid ram_block_discard_disable(), cannot change during migration. */ if (ram_block_discard_is_required()) { error_setg(errp, "RDMA: cannot disable RAM discard"); - return; + return NULL; } rdma = qemu_rdma_data_init(host_port, errp); @@ -3994,12 +3994,11 @@ void rdma_connect_outgoing(void *opaque, trace_rdma_connect_outgoing_after_rdma_connect(); s->rdma_migration = true; - migration_outgoing_setup(rdma_new_output(rdma)); - migration_start_outgoing(s); - return; + return rdma_new_output(rdma); return_path_err: qemu_rdma_cleanup(rdma); err: g_free(rdma); g_free(rdma_return_path); + return NULL; } diff --git a/migration/rdma.h b/migration/rdma.h index 170c25cf44..8a6515f130 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -21,8 +21,8 @@ #include "system/memory.h" -void rdma_connect_outgoing(void *opaque, InetSocketAddress *host_port, - Error **errp); +QIOChannel *rdma_connect_outgoing(void *opaque, InetSocketAddress *host_port, + Error **errp); void rdma_connect_incoming(InetSocketAddress *host_port, Error **errp);