Message ID | 20240304012634.95520-26-peterx@redhat.com |
---|---|
State | New |
Headers | show |
Series | [PULL,01/27] migration: massage cpr-reboot documentation | expand |
On Mon, 4 Mar 2024 at 01:28, <peterx@redhat.com> wrote: > > From: Fabiano Rosas <farosas@suse.de> > > If we receive a file descriptor that points to a regular file, there's > nothing stopping us from doing multifd migration with mapped-ram to > that file. > > Enable the fd: URI to work with multifd + mapped-ram. > > Note that the fds passed into multifd are duplicated because we want > to avoid cross-thread effects when doing cleanup (i.e. close(fd)). The > original fd doesn't need to be duplicated because monitor_get_fd() > transfers ownership to the caller. > > Signed-off-by: Fabiano Rosas <farosas@suse.de> > Reviewed-by: Peter Xu <peterx@redhat.com> > Link: https://lore.kernel.org/r/20240229153017.2221-23-farosas@suse.de > Signed-off-by: Peter Xu <peterx@redhat.com> Hi; Coverity points out some issues with this commit (CID 1539961, 1539965): > @@ -73,4 +98,23 @@ void fd_start_incoming_migration(const char *fdname, Error **errp) > fd_accept_incoming_migration, > NULL, NULL, > g_main_context_get_thread_default()); > + > + if (migrate_multifd()) { > + int channels = migrate_multifd_channels(); > + > + while (channels--) { > + ioc = QIO_CHANNEL(qio_channel_file_new_fd(dup(fd))); dup() can fail and return -1, but we don't check for failure and pass the return value directly to qio_channel_file_new_fd(), which will call lseek() on it, which isn't valid. > + > + if (QIO_CHANNEL_FILE(ioc)->fd == -1) { > + error_setg(errp, "Failed to duplicate fd %d", fd); > + return; > + } > + > + qio_channel_set_name(ioc, "migration-fd-incoming"); > + qio_channel_add_watch_full(ioc, G_IO_IN, > + fd_accept_incoming_migration, > + NULL, NULL, > + g_main_context_get_thread_default()); > + } > + } > @@ -53,15 +54,20 @@ bool file_send_channel_create(gpointer opaque, Error **errp) > { > QIOChannelFile *ioc; > int flags = O_WRONLY; > - bool ret = true; > - > - ioc = qio_channel_file_new_path(outgoing_args.fname, flags, 0, errp); > - if (!ioc) { > - ret = false; > - goto out; > + bool ret = false; > + int fd = fd_args_get_fd(); > + > + if (fd && fd != -1) { > + ioc = qio_channel_file_new_fd(dup(fd)); Similarly here. > + } else { > + ioc = qio_channel_file_new_path(outgoing_args.fname, flags, 0, errp); > + if (!ioc) { > + goto out; > + } > } > > multifd_channel_connect(opaque, QIO_CHANNEL(ioc)); > + ret = true; > > out: > /* thanks -- PMM
On Mon, 11 Mar 2024 at 11:50, Peter Maydell <peter.maydell@linaro.org> wrote: > > On Mon, 4 Mar 2024 at 01:28, <peterx@redhat.com> wrote: > > > > From: Fabiano Rosas <farosas@suse.de> > > > > If we receive a file descriptor that points to a regular file, there's > > nothing stopping us from doing multifd migration with mapped-ram to > > that file. > > > > Enable the fd: URI to work with multifd + mapped-ram. > > > > Note that the fds passed into multifd are duplicated because we want > > to avoid cross-thread effects when doing cleanup (i.e. close(fd)). The > > original fd doesn't need to be duplicated because monitor_get_fd() > > transfers ownership to the caller. > > > > Signed-off-by: Fabiano Rosas <farosas@suse.de> > > Reviewed-by: Peter Xu <peterx@redhat.com> > > Link: https://lore.kernel.org/r/20240229153017.2221-23-farosas@suse.de > > Signed-off-by: Peter Xu <peterx@redhat.com> > > Hi; Coverity points out some issues with this commit (CID 1539961, 1539965): Oh, and also CID 1539960: there's a third instance of dup() with no error checking in another commit. thanks -- PMM
On Mon, Mar 04, 2024 at 09:26:32AM +0800, peterx@redhat.com wrote: > From: Fabiano Rosas <farosas@suse.de> > > If we receive a file descriptor that points to a regular file, there's > nothing stopping us from doing multifd migration with mapped-ram to > that file. > > Enable the fd: URI to work with multifd + mapped-ram. > > Note that the fds passed into multifd are duplicated because we want > to avoid cross-thread effects when doing cleanup (i.e. close(fd)). The > original fd doesn't need to be duplicated because monitor_get_fd() > transfers ownership to the caller. > > Signed-off-by: Fabiano Rosas <farosas@suse.de> > Reviewed-by: Peter Xu <peterx@redhat.com> > Link: https://lore.kernel.org/r/20240229153017.2221-23-farosas@suse.de > Signed-off-by: Peter Xu <peterx@redhat.com> > --- > migration/fd.h | 2 ++ > migration/fd.c | 44 +++++++++++++++++++++++++++++++++++++++++++ > migration/file.c | 18 ++++++++++++------ > migration/migration.c | 4 ++++ > migration/multifd.c | 2 ++ > 5 files changed, 64 insertions(+), 6 deletions(-) > > @@ -73,4 +98,23 @@ void fd_start_incoming_migration(const char *fdname, Error **errp) > fd_accept_incoming_migration, > NULL, NULL, > g_main_context_get_thread_default()); > + > + if (migrate_multifd()) { > + int channels = migrate_multifd_channels(); > + > + while (channels--) { > + ioc = QIO_CHANNEL(qio_channel_file_new_fd(dup(fd))); > + > + if (QIO_CHANNEL_FILE(ioc)->fd == -1) { > + error_setg(errp, "Failed to duplicate fd %d", fd); > + return; > + } I'd suggest that Peter's comment about failure checks be fixed by introducing a new constructor that handles the dup + error reporting. QIOChannel *qio_channel_file_new_dupfd(int fd, Error **errp;) so we're not repeating the error reporting multiple places. > + > + qio_channel_set_name(ioc, "migration-fd-incoming"); > + qio_channel_add_watch_full(ioc, G_IO_IN, > + fd_accept_incoming_migration, > + NULL, NULL, > + g_main_context_get_thread_default()); > + } > + } > } With regards, Daniel
On Mon, Mar 11, 2024 at 12:03:41PM +0000, Daniel P. Berrangé wrote: > On Mon, Mar 04, 2024 at 09:26:32AM +0800, peterx@redhat.com wrote: > > From: Fabiano Rosas <farosas@suse.de> > > > > If we receive a file descriptor that points to a regular file, there's > > nothing stopping us from doing multifd migration with mapped-ram to > > that file. > > > > Enable the fd: URI to work with multifd + mapped-ram. > > > > Note that the fds passed into multifd are duplicated because we want > > to avoid cross-thread effects when doing cleanup (i.e. close(fd)). The > > original fd doesn't need to be duplicated because monitor_get_fd() > > transfers ownership to the caller. > > > > Signed-off-by: Fabiano Rosas <farosas@suse.de> > > Reviewed-by: Peter Xu <peterx@redhat.com> > > Link: https://lore.kernel.org/r/20240229153017.2221-23-farosas@suse.de > > Signed-off-by: Peter Xu <peterx@redhat.com> > > --- > > migration/fd.h | 2 ++ > > migration/fd.c | 44 +++++++++++++++++++++++++++++++++++++++++++ > > migration/file.c | 18 ++++++++++++------ > > migration/migration.c | 4 ++++ > > migration/multifd.c | 2 ++ > > 5 files changed, 64 insertions(+), 6 deletions(-) > > > > > @@ -73,4 +98,23 @@ void fd_start_incoming_migration(const char *fdname, Error **errp) > > fd_accept_incoming_migration, > > NULL, NULL, > > g_main_context_get_thread_default()); > > + > > + if (migrate_multifd()) { > > + int channels = migrate_multifd_channels(); > > + > > + while (channels--) { > > + ioc = QIO_CHANNEL(qio_channel_file_new_fd(dup(fd))); > > + > > + if (QIO_CHANNEL_FILE(ioc)->fd == -1) { > > + error_setg(errp, "Failed to duplicate fd %d", fd); > > + return; > > + } > > I'd suggest that Peter's comment about failure checks be fixed > by introducing a new constructor that handles the dup + error > reporting. > > QIOChannel *qio_channel_file_new_dupfd(int fd, Error **errp;) > > so we're not repeating the error reporting multiple places. Indeed that looks cleaner. At the meantime, I just noticed there seems to have an IOC leak on incoming side.. file_start_incoming_migration(): do { QIOChannel *ioc = QIO_CHANNEL(fioc); qio_channel_set_name(ioc, "migration-file-incoming"); qio_channel_add_watch_full(ioc, G_IO_IN, file_accept_incoming_migration, NULL, NULL, g_main_context_get_thread_default()); fioc = qio_channel_file_new_fd(dup(fioc->fd)); <-------------------- here if (!fioc || fioc->fd == -1) { error_setg(errp, "Error creating migration incoming channel"); break; } } while (++i < channels); Fabiano, would you send patches to address these issues (split if both issues exist)? Thanks,
diff --git a/migration/fd.h b/migration/fd.h index b901bc014e..0c0a18d9e7 100644 --- a/migration/fd.h +++ b/migration/fd.h @@ -20,4 +20,6 @@ void fd_start_incoming_migration(const char *fdname, Error **errp); void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp); +void fd_cleanup_outgoing_migration(void); +int fd_args_get_fd(void); #endif diff --git a/migration/fd.c b/migration/fd.c index 0eb677dcae..d4ae72d132 100644 --- a/migration/fd.c +++ b/migration/fd.c @@ -15,18 +15,41 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "channel.h" #include "fd.h" #include "migration.h" #include "monitor/monitor.h" +#include "io/channel-file.h" #include "io/channel-util.h" +#include "options.h" #include "trace.h" +static struct FdOutgoingArgs { + int fd; +} outgoing_args; + +int fd_args_get_fd(void) +{ + return outgoing_args.fd; +} + +void fd_cleanup_outgoing_migration(void) +{ + if (outgoing_args.fd > 0) { + close(outgoing_args.fd); + outgoing_args.fd = -1; + } +} + void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp) { QIOChannel *ioc; int fd = monitor_get_fd(monitor_cur(), fdname, errp); + + outgoing_args.fd = -1; + if (fd == -1) { return; } @@ -38,6 +61,8 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error ** return; } + outgoing_args.fd = fd; + qio_channel_set_name(ioc, "migration-fd-outgoing"); migration_channel_connect(s, ioc, NULL, NULL); object_unref(OBJECT(ioc)); @@ -73,4 +98,23 @@ void fd_start_incoming_migration(const char *fdname, Error **errp) fd_accept_incoming_migration, NULL, NULL, g_main_context_get_thread_default()); + + if (migrate_multifd()) { + int channels = migrate_multifd_channels(); + + while (channels--) { + ioc = QIO_CHANNEL(qio_channel_file_new_fd(dup(fd))); + + if (QIO_CHANNEL_FILE(ioc)->fd == -1) { + error_setg(errp, "Failed to duplicate fd %d", fd); + return; + } + + qio_channel_set_name(ioc, "migration-fd-incoming"); + qio_channel_add_watch_full(ioc, G_IO_IN, + fd_accept_incoming_migration, + NULL, NULL, + g_main_context_get_thread_default()); + } + } } diff --git a/migration/file.c b/migration/file.c index 499d2782fe..164b079966 100644 --- a/migration/file.c +++ b/migration/file.c @@ -11,6 +11,7 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "channel.h" +#include "fd.h" #include "file.h" #include "migration.h" #include "io/channel-file.h" @@ -53,15 +54,20 @@ bool file_send_channel_create(gpointer opaque, Error **errp) { QIOChannelFile *ioc; int flags = O_WRONLY; - bool ret = true; - - ioc = qio_channel_file_new_path(outgoing_args.fname, flags, 0, errp); - if (!ioc) { - ret = false; - goto out; + bool ret = false; + int fd = fd_args_get_fd(); + + if (fd && fd != -1) { + ioc = qio_channel_file_new_fd(dup(fd)); + } else { + ioc = qio_channel_file_new_path(outgoing_args.fname, flags, 0, errp); + if (!ioc) { + goto out; + } } multifd_channel_connect(opaque, QIO_CHANNEL(ioc)); + ret = true; out: /* diff --git a/migration/migration.c b/migration/migration.c index b9baab543a..a49fcd53ee 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -140,6 +140,10 @@ static bool transport_supports_multi_channels(MigrationAddress *addr) if (addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) { SocketAddress *saddr = &addr->u.socket; + if (saddr->type == SOCKET_ADDRESS_TYPE_FD) { + return migrate_mapped_ram(); + } + return (saddr->type == SOCKET_ADDRESS_TYPE_INET || saddr->type == SOCKET_ADDRESS_TYPE_UNIX || saddr->type == SOCKET_ADDRESS_TYPE_VSOCK); diff --git a/migration/multifd.c b/migration/multifd.c index 419feb7df1..b4e5a9dfcc 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -17,6 +17,7 @@ #include "exec/ramblock.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "fd.h" #include "file.h" #include "migration.h" #include "migration-stats.h" @@ -731,6 +732,7 @@ static bool multifd_send_cleanup_channel(MultiFDSendParams *p, Error **errp) static void multifd_send_cleanup_state(void) { file_cleanup_outgoing_migration(); + fd_cleanup_outgoing_migration(); socket_cleanup_outgoing_migration(); qemu_sem_destroy(&multifd_send_state->channels_created); qemu_sem_destroy(&multifd_send_state->channels_ready);