On Fri, 9 Jan 2026 at 18:14, Fabiano Rosas <[email protected]> wrote:
> Encapsulate the MigrationChannelList parsing in a new
> migrate_channels_parse() located at channel.c.
>
> This also makes the memory management of the MigrationAddress more
> uniform. Previously, half the parsing code (uri parsing) would
> allocate memory for the address while the other half (channel parsing)
> would instead pass the original QAPI object along. After this patch,
> the MigrationAddress is always QAPI_CLONEd, so the callers can use
> g_autoptr(MigrationAddress) in all cases.
>
> Reviewed-by: Peter Xu <[email protected]>
> Signed-off-by: Fabiano Rosas <[email protected]>
> ---
> migration/channel.c | 45 ++++++++++++++++++++++++++++++++++++++
> migration/channel.h | 5 +++++
> migration/migration.c | 50 ++++++++++++-------------------------------
> 3 files changed, 64 insertions(+), 36 deletions(-)
>
> diff --git a/migration/channel.c b/migration/channel.c
> index 56c80b5cdf..8b71b3f430 100644
> --- a/migration/channel.c
> +++ b/migration/channel.c
> @@ -11,6 +11,7 @@
> */
>
> #include "qemu/osdep.h"
> +#include "qemu/cutils.h"
> #include "channel.h"
> #include "exec.h"
> #include "fd.h"
> @@ -20,7 +21,9 @@
> #include "migration.h"
> #include "multifd.h"
> #include "options.h"
> +#include "qapi/clone-visitor.h"
> #include "qapi/qapi-types-migration.h"
> +#include "qapi/qapi-visit-migration.h"
> #include "qapi/error.h"
> #include "qemu-file.h"
> #include "qemu/yank.h"
> @@ -280,3 +283,45 @@ int migration_channel_read_peek(QIOChannel *ioc,
>
> return 0;
> }
> +
> +bool migrate_channels_parse(MigrationChannelList *channels,
> + MigrationChannel **main_channelp,
> + MigrationChannel **cpr_channelp,
> + Error **errp)
> +{
> + MigrationChannel *channelv[MIGRATION_CHANNEL_TYPE__MAX] = { NULL };
> + bool single_channel = cpr_channelp ? false : true;
> +
> + if (single_channel && channels->next) {
> + error_setg(errp, "Channel list must have only one entry, "
> + "for type 'main'");
> + return false;
> + }
* Instead of the single_channel variable above, we could say
(!cpr_channelp && channels->next)? and avoid the single_channel
variable.
> + for ( ; channels; channels = channels->next) {
> + MigrationChannelType type;
> +
> + type = channels->value->channel_type;
> + if (channelv[type]) {
> + error_setg(errp, "Channel list has more than one %s entry",
> + MigrationChannelType_str(type));
> + return false;
> + }
> + channelv[type] = channels->value;
> + }
> +
> + if (cpr_channelp) {
> + *cpr_channelp = QAPI_CLONE(MigrationChannel,
> + channelv[MIGRATION_CHANNEL_TYPE_CPR]);
> + }
> +
> + *main_channelp = QAPI_CLONE(MigrationChannel,
> + channelv[MIGRATION_CHANNEL_TYPE_MAIN]);
> +
> + if (!(*main_channelp)->addr) {
> + error_setg(errp, "Channel list has no main entry");
> + return false;
> + }
> +
> + return true;
> +}
> diff --git a/migration/channel.h b/migration/channel.h
> index 8264fe327d..5110fb45a4 100644
> --- a/migration/channel.h
> +++ b/migration/channel.h
> @@ -42,4 +42,9 @@ bool migration_has_all_channels(void);
> void migration_connect_outgoing(MigrationState *s, MigrationAddress *addr,
> Error **errp);
> void migration_connect_incoming(MigrationAddress *addr, Error **errp);
> +
> +bool migrate_channels_parse(MigrationChannelList *channels,
> + MigrationChannel **main_channelp,
> + MigrationChannel **cpr_channelp,
> + Error **errp);
> #endif
> diff --git a/migration/migration.c b/migration/migration.c
> index 3c93fb23cc..98c1f38e8e 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -741,8 +741,7 @@ static void qemu_setup_incoming_migration(const char
> *uri, bool has_channels,
> MigrationChannelList *channels,
> Error **errp)
> {
> - g_autoptr(MigrationChannel) channel = NULL;
> - MigrationAddress *addr = NULL;
> + g_autoptr(MigrationChannel) main_ch = NULL;
> MigrationIncomingState *mis = migration_incoming_get_current();
>
> /*
> @@ -754,25 +753,20 @@ static void qemu_setup_incoming_migration(const char
> *uri, bool has_channels,
> }
>
> if (channels) {
> - /* To verify that Migrate channel list has only item */
> - if (channels->next) {
> - error_setg(errp, "Channel list must have only one entry, "
> - "for type 'main'");
> + if (!migrate_channels_parse(channels, &main_ch, NULL, errp)) {
> return;
> }
> - addr = channels->value->addr;
> }
>
> if (uri) {
> /* caller uses the old URI syntax */
> - if (!migrate_uri_parse(uri, &channel, errp)) {
> + if (!migrate_uri_parse(uri, &main_ch, errp)) {
> return;
> }
> - addr = channel->addr;
> }
>
> /* transport mechanism not suitable for migration? */
> - if (!migration_transport_compatible(addr, errp)) {
> + if (!migration_transport_compatible(main_ch->addr, errp)) {
> return;
> }
>
> @@ -780,7 +774,7 @@ static void qemu_setup_incoming_migration(const char
> *uri, bool has_channels,
> return;
> }
>
> - migration_connect_incoming(addr, errp);
> + migration_connect_incoming(main_ch->addr, errp);
>
> /* Close cpr socket to tell source that we are listening */
> cpr_state_close();
> @@ -2116,10 +2110,8 @@ void qmp_migrate(const char *uri, bool has_channels,
> bool has_resume, bool resume, Error **errp)
> {
> MigrationState *s = migrate_get_current();
> - g_autoptr(MigrationChannel) channel = NULL;
> - MigrationAddress *addr = NULL;
> - MigrationChannel *channelv[MIGRATION_CHANNEL_TYPE__MAX] = { NULL };
> - MigrationChannel *cpr_channel = NULL;
> + g_autoptr(MigrationChannel) main_ch = NULL;
> + g_autoptr(MigrationChannel) cpr_ch = NULL;
>
> /*
> * Having preliminary checks for uri and channel
> @@ -2130,38 +2122,24 @@ void qmp_migrate(const char *uri, bool has_channels,
> }
>
> if (channels) {
> - for ( ; channels; channels = channels->next) {
> - MigrationChannelType type = channels->value->channel_type;
> -
> - if (channelv[type]) {
> - error_setg(errp, "Channel list has more than one %s entry",
> - MigrationChannelType_str(type));
> - return;
> - }
> - channelv[type] = channels->value;
> - }
> - cpr_channel = channelv[MIGRATION_CHANNEL_TYPE_CPR];
> - addr = channelv[MIGRATION_CHANNEL_TYPE_MAIN]->addr;
> - if (!addr) {
> - error_setg(errp, "Channel list has no main entry");
> + if (!migrate_channels_parse(channels, &main_ch, &cpr_ch, errp)) {
> return;
> }
> }
>
> if (uri) {
> /* caller uses the old URI syntax */
> - if (!migrate_uri_parse(uri, &channel, errp)) {
> + if (!migrate_uri_parse(uri, &main_ch, errp)) {
> return;
> }
> - addr = channel->addr;
> }
>
> /* transport mechanism not suitable for migration? */
> - if (!migration_transport_compatible(addr, errp)) {
> + if (!migration_transport_compatible(main_ch->addr, errp)) {
> return;
> }
>
> - if (migrate_mode() == MIG_MODE_CPR_TRANSFER && !cpr_channel) {
> + if (migrate_mode() == MIG_MODE_CPR_TRANSFER && !cpr_ch) {
> error_setg(errp, "missing 'cpr' migration channel");
> return;
> }
* This check for (_CPR_TRANSFER && !cpr_ch) and error could be moved
to migrate_channels_parse() as is done for the main_ch.
> @@ -2178,7 +2156,7 @@ void qmp_migrate(const char *uri, bool has_channels,
> */
> Error *local_err = NULL;
>
> - if (!cpr_state_save(cpr_channel, &local_err)) {
> + if (!cpr_state_save(cpr_ch, &local_err)) {
> goto out;
> }
>
> @@ -2194,10 +2172,10 @@ void qmp_migrate(const char *uri, bool has_channels,
> */
> if (migrate_mode() == MIG_MODE_CPR_TRANSFER) {
> migrate_hup_add(s, cpr_state_ioc(),
> (GSourceFunc)qmp_migrate_finish_cb,
> - QAPI_CLONE(MigrationAddress, addr));
> + QAPI_CLONE(MigrationAddress, main_ch->addr));
>
> } else {
> - qmp_migrate_finish(addr, errp);
> + qmp_migrate_finish(main_ch->addr, errp);
> }
>
> out:
> --
* Otherwise it looks okay.
Reviewed-by: Prasad Pandit <[email protected]>
Thank you.
---
- Prasad