* [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data
@ 2026-03-10 13:55 Fabiano Rosas
2026-03-10 13:55 ` [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1) Fabiano Rosas
` (8 more replies)
0 siblings, 9 replies; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 13:55 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Xu, Laurent Vivier, Paolo Bonzini
When the migration-test is invoked with the '-p' flag (to run a single
test), the glib code won't call the destroy function for the
not-executed tests, causing the MigrationTest wrapper data to leak.
This doesn't affect make check, but affects debugging use-cases where
having a leak pop up in ASAN output is extra annoying.
Fix by adding the tests data to a list and freeing them all at the end
of migration-test execution. Any tests actually dispatched by glib
will have the destroy function called as usual.
Note that migration_test_add_suffix() is altered to call
migration_test_add() so that there's only one place adding the data to
the list.
Performance is not an issue at the moment, we have < 100 tests.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/framework.c | 2 ++
tests/qtest/migration/migration-util.c | 19 ++++++++++++++-----
tests/qtest/migration/migration-util.h | 2 +-
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 0bfc241914..b9371372de 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -1162,5 +1162,7 @@ int migration_env_clean(MigrationTestEnv *env)
}
g_free(tmpfs);
+ migration_tests_free();
+
return ret;
}
diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
index c2462306a1..2648ad7f61 100644
--- a/tests/qtest/migration/migration-util.c
+++ b/tests/qtest/migration/migration-util.c
@@ -38,6 +38,7 @@
#include "linux/kvm.h"
#endif
+GQueue *tests;
static char *SocketAddress_to_str(SocketAddress *addr)
{
@@ -243,6 +244,8 @@ static void migration_test_destroy(gpointer data)
{
MigrationTest *test = (MigrationTest *)data;
+ g_queue_remove(tests, test);
+
g_free(test->data);
g_free(test->name);
g_free(test);
@@ -268,21 +271,27 @@ void migration_test_add(const char *path,
qtest_add_data_func_full(path, test, migration_test_wrapper,
migration_test_destroy);
+ if (!tests) {
+ tests = g_queue_new();
+ }
+ g_queue_push_tail(tests, test);
}
void migration_test_add_suffix(const char *path, const char *suffix,
void (*fn)(char *name, MigrateCommon *args))
{
- MigrationTest *test = g_new0(MigrationTest, 1);
+ g_autofree char *name = NULL;
g_assert(g_str_has_suffix(path, "/"));
g_assert(!g_str_has_prefix(suffix, "/"));
- test->func = fn;
- test->name = g_strconcat(path, suffix, NULL);
+ name = g_strconcat(path, suffix, NULL);
+ migration_test_add(name, fn);
+}
- qtest_add_data_func_full(test->name, test, migration_test_wrapper,
- migration_test_destroy);
+void migration_tests_free(void)
+{
+ g_queue_free_full(tests, migration_test_destroy);
}
#ifdef O_DIRECT
diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
index e73d69bab0..694773e594 100644
--- a/tests/qtest/migration/migration-util.h
+++ b/tests/qtest/migration/migration-util.h
@@ -59,5 +59,5 @@ void migration_test_add_suffix(const char *path, const char *suffix,
void (*fn)(char *name, MigrateCommon *args));
char *migrate_get_connect_uri(QTestState *who);
void migrate_set_ports(QTestState *to, QList *channel_list);
-
+void migration_tests_free(void);
#endif /* MIGRATION_UTIL_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1)
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
@ 2026-03-10 13:55 ` Fabiano Rosas
2026-03-10 19:59 ` Peter Xu
2026-03-11 10:34 ` Prasad Pandit
2026-03-10 13:55 ` [PATCH 3/8] tests/qtest/migration: Fix misuse of listen_uri Fabiano Rosas
` (7 subsequent siblings)
8 siblings, 2 replies; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 13:55 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Xu, Laurent Vivier, Paolo Bonzini
The UUID validation happens early enough during the migration process
that the incoming coroutine hasn't yet yielded once so the
EXIT_FAILURE from the coroutine can trigger ASAN leak detection due to
the temporary socket from qio_net_listener_channel_func() still having
an elevated refcount.
Direct leak of 400 byte(s) in 1 object(s) allocated from:
#0 0x55e668890a07 in malloc asan_malloc_linux.cpp:68:3
#1 0x7f3c7e2b6648 in g_malloc ../glib/gmem.c:130
#2 0x55e66a8ef05f in object_new_with_type ../qom/object.c:767:15
#3 0x55e66a8ef178 in object_new ../qom/object.c:789:12
#4 0x55e66a93bcc6 in qio_channel_socket_new ../io/channel-socket.c:70:31
#5 0x55e66a93f34f in qio_channel_socket_accept ../io/channel-socket.c:401:12
#6 0x55e66a96752a in qio_net_listener_channel_func ../io/net-listener.c:64:12
#7 0x55e66a94bdac in qio_channel_fd_source_dispatch ../io/channel-watch.c:84:12
#8 0x7f3c7e2adf4b in g_main_dispatch ../glib/gmain.c:3476
#9 0x7f3c7e2adf4b in g_main_context_dispatch_unlocked ../glib/gmain.c:4284
#10 0x7f3c7e2b00c8 in g_main_context_dispatch ../glib/gmain.c:4272
Direct leak of 32 byte(s) in 1 object(s) allocated from:
#0 0x55e668890a07 in malloc asan_malloc_linux.cpp:68:3
#1 0x7f3c7e2b6648 in g_malloc ../glib/gmem.c:130
#2 0x7f3c7e2ad40c in g_source_set_callback ../glib/gmain.c:1879
#3 0x55e66a95c4d2 in qio_channel_add_watch_full ../io/channel.c:416:5
#4 0x55e66a95c5a9 in qio_channel_add_watch_source ../io/channel.c:444:10
#5 0x55e66a96380c in qio_net_listener_watch ../io/net-listener.c:166:46
#6 0x55e66a96496a in qio_net_listener_set_client_func_internal ../io/net-listener.c:275:5
#7 0x55e66a963e79 in qio_net_listener_set_client_func_full ../io/net-listener.c:284:5
#8 0x55e669e1b3bb in socket_connect_incoming ../migration/socket.c:165:5
#9 0x55e669d26b9f in migration_connect_incoming ../migration/channel.c:83:13
#10 0x55e669d5f6d2 in qemu_setup_incoming_migration ../migration/migration.c:672:5
#11 0x55e669d5f344 in qmp_migrate_incoming ../migration/migration.c:1771:5
This is inconsequential in production, but let's give ourselves an
easier time and avoid this situation when testing. The uuid_error test
doesn't really need to check the exit code, just the migration state
would be sufficient. Set exit-on-error=false for this test.
While looking at this, add a comment to the source explaining that the
incoming coroutine may block the main loop for a (longer than
expected) while.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration.c | 5 +++++
tests/qtest/migration/misc-tests.c | 4 ++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index f949708629..c77832f851 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -898,6 +898,11 @@ void migration_start_incoming(void)
Coroutine *co = qemu_coroutine_create(process_incoming_migration_co, NULL);
qemu_coroutine_enter(co);
+ /*
+ * This doesn't return right away. The coroutine will run
+ * unimpeded until its first yield, which may happen as late as
+ * the force yield at ram_load_precopy().
+ */
}
int migrate_send_rp_switchover_ack(MigrationIncomingState *mis)
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index 810e9e6549..06da2657d5 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -131,7 +131,7 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
- if (migrate_start(&from, &to, uri, args)) {
+ if (migrate_start(&from, &to, "defer", args)) {
return;
}
@@ -146,10 +146,10 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
+ migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
migrate_qmp(from, to, uri, NULL, "{}");
if (should_fail) {
- qtest_set_expected_status(to, EXIT_FAILURE);
wait_for_migration_fail(from, true);
} else {
wait_for_migration_complete(from);
--
2.51.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 3/8] tests/qtest/migration: Fix misuse of listen_uri
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
2026-03-10 13:55 ` [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1) Fabiano Rosas
@ 2026-03-10 13:55 ` Fabiano Rosas
2026-03-10 15:48 ` Lukas Straub
2026-03-10 13:55 ` [PATCH 4/8] tests/qtest/migration: Stop invoking migrate_incoming from hooks Fabiano Rosas
` (6 subsequent siblings)
8 siblings, 1 reply; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 13:55 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Peter Xu, Lukas Straub, Laurent Vivier,
Paolo Bonzini, Mark Kanda, Ben Chaney
The listen_uri parameter is supposed to be used for the incoming
migration while connect_uri for the outgoing migration. This is well
documented in the header file.
However, due to -incoming "defer", some tests set listen-uri =
"defer", which is fine. But then, being without another parameter to
define the uri to be use in migrate_incoming, some tests have been
misusing connect_uri.
Add a separate flag to denote "defer" and spare the tests from passing
the string. Change the usage of listen_uri to it's original purpose.
Link: https://lore.kernel.org/qemu-devel/20251215220041.12657-28-farosas@suse.de
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/colo-tests.c | 4 ++-
tests/qtest/migration/compression-tests.c | 12 +++----
tests/qtest/migration/cpr-tests.c | 20 +++++++----
tests/qtest/migration/file-tests.c | 41 ++++++++++++++++-------
tests/qtest/migration/framework.c | 12 +++----
tests/qtest/migration/framework.h | 7 ++++
tests/qtest/migration/misc-tests.c | 4 +--
tests/qtest/migration/precopy-tests.c | 14 +++++---
tests/qtest/migration/tls-tests.c | 16 ++++-----
9 files changed, 83 insertions(+), 47 deletions(-)
diff --git a/tests/qtest/migration/colo-tests.c b/tests/qtest/migration/colo-tests.c
index ef880f5114..7c438c196b 100644
--- a/tests/qtest/migration/colo-tests.c
+++ b/tests/qtest/migration/colo-tests.c
@@ -116,9 +116,11 @@ static void test_colo_multifd_common(MigrateCommon *args,
bool failover_during_checkpoint,
bool primary_failover)
{
- args->listen_uri = "defer";
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = hook_start_multifd;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+ args->start.incoming_defer = true;
+
test_colo_common(args, failover_during_checkpoint, primary_failover);
}
diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
index 845e622cd5..eb0b7d6b4b 100644
--- a/tests/qtest/migration/compression-tests.c
+++ b/tests/qtest/migration/compression-tests.c
@@ -33,9 +33,9 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -43,9 +43,9 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
@@ -66,9 +66,9 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -85,9 +85,9 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -104,9 +104,9 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -156,9 +156,9 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 0d97b5b89f..1b3d42e51c 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -32,10 +32,11 @@ static void test_mode_reboot(char *name, MigrateCommon *args)
g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
FILE_TEST_FILENAME);
+ args->listen_uri = uri;
args->connect_uri = uri;
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_mode_reboot;
+ args->start.incoming_defer = true;
args->start.mem_type = MEM_TYPE_SHMEM;
args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
@@ -53,7 +54,7 @@ static void *test_mode_transfer_start(QTestState *from, QTestState *to)
* migration, and cannot connect synchronously to the monitor, so defer
* the target connection.
*/
-static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
+static void test_mode_transfer_common(MigrateCommon *args)
{
g_autofree char *cpr_path = g_strdup_printf("%s/cpr.sock", tmpfs);
g_autofree char *mig_path = g_strdup_printf("%s/migsocket", tmpfs);
@@ -84,7 +85,11 @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
"addr.type=fd,addr.str=%d %s",
cpr_sockfd, opts);
- args->listen_uri = incoming_defer ? "defer" : uri;
+ /*
+ * The URI is used only for the deferred target connection when
+ * !incoming_defer.
+ */
+ args->listen_uri = uri;
args->connect_channels = connect_channels;
args->cpr_channel = cpr_channel;
args->start_hook = test_mode_transfer_start;
@@ -102,12 +107,14 @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
static void test_mode_transfer(char *name, MigrateCommon *args)
{
- test_mode_transfer_common(args, false);
+ args->start.incoming_defer = false;
+ test_mode_transfer_common(args);
}
static void test_mode_transfer_defer(char *name, MigrateCommon *args)
{
- test_mode_transfer_common(args, true);
+ args->start.incoming_defer = true;
+ test_mode_transfer_common(args);
}
static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
@@ -227,11 +234,10 @@ static void test_mode_exec(char *name, MigrateCommon *args)
{
g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
FILE_TEST_FILENAME);
- g_autofree char *listen_uri = g_strdup_printf("defer");
args->connect_uri = uri;
- args->listen_uri = listen_uri;
args->start_hook = test_mode_exec_start;
+ args->start.incoming_defer = true;
args->start.only_source = true;
args->start.opts_source = "-machine aux-ram-share=on -nodefaults";
diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
index 5d1b861cf6..7597ff7552 100644
--- a/tests/qtest/migration/file-tests.c
+++ b/tests/qtest/migration/file-tests.c
@@ -25,7 +25,9 @@ static void test_precopy_file(char *name, MigrateCommon *args)
g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
FILE_TEST_FILENAME);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
+
+ args->start.incoming_defer = true;
test_file_common(args, true);
}
@@ -69,9 +71,11 @@ static void test_precopy_file_offset_fdset(char *name, MigrateCommon *args)
g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
FILE_TEST_OFFSET);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
args->start_hook = migrate_hook_start_file_offset_fdset;
+ args->start.incoming_defer = true;
+
test_file_common(args, false);
}
#endif
@@ -83,7 +87,9 @@ static void test_precopy_file_offset(char *name, MigrateCommon *args)
FILE_TEST_OFFSET);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
+
+ args->start.incoming_defer = true;
test_file_common(args, false);
}
@@ -95,9 +101,11 @@ static void test_precopy_file_offset_bad(char *name, MigrateCommon *args)
tmpfs, FILE_TEST_FILENAME);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
args->result = MIG_TEST_QMP_ERROR;
+ args->start.incoming_defer = true;
+
test_file_common(args, false);
}
@@ -107,8 +115,9 @@ static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args)
FILE_TEST_FILENAME);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
test_file_common(args, false);
@@ -120,8 +129,9 @@ static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args)
FILE_TEST_FILENAME);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
test_file_common(args, true);
@@ -132,8 +142,9 @@ static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args)
g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
FILE_TEST_FILENAME);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
@@ -146,8 +157,9 @@ static void test_multifd_file_mapped_ram(char *name, MigrateCommon *args)
FILE_TEST_FILENAME);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
@@ -168,9 +180,10 @@ static void test_multifd_file_mapped_ram_dio(char *name, MigrateCommon *args)
g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
FILE_TEST_FILENAME);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
args->start_hook = migrate_hook_start_multifd_mapped_ram_dio;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -240,10 +253,11 @@ static void test_multifd_file_mapped_ram_fdset(char *name, MigrateCommon *args)
FILE_TEST_OFFSET);
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset;
args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -255,11 +269,13 @@ static void test_multifd_file_mapped_ram_fdset_dio(char *name,
{
g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
FILE_TEST_OFFSET);
+
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->listen_uri = uri;
args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio;
args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -286,8 +302,9 @@ test_precopy_file_mapped_ram_ignore_shared(char *name, MigrateCommon *args)
{
g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
FILE_TEST_FILENAME);
+ args->listen_uri = uri;
args->connect_uri = uri;
- args->listen_uri = "defer";
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index b9371372de..75605d1791 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -428,7 +428,8 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
"%s %s %s %s",
kvm_opts ? kvm_opts : "",
machine, machine_opts,
- memory_backend, tmpfs, uri,
+ memory_backend, tmpfs,
+ args->incoming_defer ? "defer" : uri,
events,
arch_opts ? arch_opts : "",
args->opts_target ? args->opts_target : "",
@@ -873,8 +874,7 @@ int test_precopy_common(MigrateCommon *args)
* migrate-incoming channels.
*/
if (args->connect_channels) {
- if (args->start.defer_target_connect &&
- !strcmp(args->listen_uri, "defer")) {
+ if (args->start.defer_target_connect && args->start.incoming_defer) {
in_channels = qobject_from_json(args->connect_channels,
&error_abort);
}
@@ -898,8 +898,8 @@ int test_precopy_common(MigrateCommon *args)
if (args->start.defer_target_connect) {
qtest_connect(to);
qtest_qmp_handshake(to, NULL);
- if (!strcmp(args->listen_uri, "defer")) {
- migrate_incoming_qmp(to, args->connect_uri, in_channels, "{}");
+ if (args->start.incoming_defer) {
+ migrate_incoming_qmp(to, NULL, in_channels, "{}");
}
}
@@ -1048,7 +1048,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
* We need to wait for the source to finish before starting the
* destination.
*/
- migrate_incoming_qmp(to, args->connect_uri, NULL, "{}");
+ migrate_incoming_qmp(to, args->listen_uri, NULL, "{}");
wait_for_migration_complete(to);
if (stop_src) {
diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index 80eef75893..f920735d05 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -145,6 +145,13 @@ typedef struct {
* migration_set_capabilities().
*/
bool caps[MIGRATION_CAPABILITY__MAX];
+
+ /*
+ * Whether to use "defer" as the uri for the -incoming command
+ * line option. If set to true, MigrateCommon.listen_uri will be
+ * used for the deferred migrate_incoming call.
+ */
+ bool incoming_defer;
} MigrateStart;
typedef enum PostcopyRecoveryFailStage {
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index 06da2657d5..a1704755d9 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -217,7 +217,6 @@ static void do_test_validate_uri_channel(MigrateCommon *args)
static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer",
args->connect_uri = "tcp:127.0.0.1:0",
args->connect_channels = ("[ { ""'channel-type': 'main',"
" 'addr': { 'transport': 'socket',"
@@ -225,6 +224,7 @@ static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
" 'host': '127.0.0.1',"
" 'port': '0' } } ]"),
+ args->start.incoming_defer = true;
args->start.hide_stderr = true;
do_test_validate_uri_channel(args);
@@ -232,8 +232,8 @@ static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
static void test_validate_uri_channels_none_set(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start.hide_stderr = true;
+ args->start.incoming_defer = true;
do_test_validate_uri_channel(args);
}
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index f17dc5176d..31fd4af1ad 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -282,11 +282,12 @@ static void migrate_hook_end_fd(QTestState *from,
static void test_precopy_fd_socket(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->connect_uri = "fd:fd-mig";
args->start_hook = migrate_hook_start_fd;
args->end_hook = migrate_hook_end_fd;
+ args->start.incoming_defer = true;
+
test_precopy_common(args);
}
#endif /* _WIN32 */
@@ -435,7 +436,6 @@ migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd;
/*
* Multifd is more complicated than most of the features, it
@@ -444,6 +444,7 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
*/
args->live = true;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -451,7 +452,6 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy;
/*
* Multifd is more complicated than most of the features, it
@@ -460,6 +460,7 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
*/
args->live = true;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -467,7 +468,6 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page;
/*
* Multifd is more complicated than most of the features, it
@@ -476,6 +476,7 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
*/
args->live = true;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -483,7 +484,6 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_precopy_tcp_multifd;
args->live = true;
args->connect_channels = ("[ { 'channel-type': 'main',"
@@ -492,6 +492,7 @@ static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args)
" 'host': '127.0.0.1',"
" 'port': '0' } } ]");
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -513,6 +514,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
QTestState *from, *to, *to2;
args->start.hide_stderr = true;
+ args->start.incoming_defer = true;
if (migrate_start(&from, &to, "defer", &args->start)) {
return;
@@ -560,6 +562,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
wait_for_migration_status(from, "cancelled", NULL);
args->start.only_target = true;
+ args->start.incoming_defer = true;
if (migrate_start(&from, &to2, "defer", &args->start)) {
return;
@@ -734,6 +737,7 @@ static void test_cancel_src_after_status(char *test_path, MigrateCommon *args)
QTestState *from, *to;
args->start.hide_stderr = true;
+ args->start.incoming_defer = true;
if (migrate_start(&from, &to, "defer", &args->start)) {
return;
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 4ce7f6c676..40a78bd2d2 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -673,10 +673,10 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
args->end_hook = migrate_hook_end_tls_psk;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -684,12 +684,12 @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
args->end_hook = migrate_hook_end_tls_psk;
args->result = MIG_TEST_FAIL;
args->start.hide_stderr = true;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -698,10 +698,10 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
args->end_hook = migrate_hook_end_tls_psk;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
@@ -712,10 +712,10 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
static void test_multifd_tcp_tls_x509_default_host(char *name,
MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
args->end_hook = migrate_hook_end_tls_x509;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -724,10 +724,10 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
static void test_multifd_tcp_tls_x509_override_host(char *name,
MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
args->end_hook = migrate_hook_end_tls_x509;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -749,11 +749,11 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
* to load migration state, and thus just aborts the migration
* without exiting.
*/
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
args->end_hook = migrate_hook_end_tls_x509;
args->result = MIG_TEST_FAIL;
+ args->start.incoming_defer = true;
args->start.hide_stderr = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -763,10 +763,10 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
args->end_hook = migrate_hook_end_tls_x509;
+ args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
test_precopy_common(args);
@@ -775,11 +775,11 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
MigrateCommon *args)
{
- args->listen_uri = "defer";
args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
args->end_hook = migrate_hook_end_tls_x509;
args->result = MIG_TEST_FAIL;
+ args->start.incoming_defer = true;
args->start.hide_stderr = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
--
2.51.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 4/8] tests/qtest/migration: Stop invoking migrate_incoming from hooks
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
2026-03-10 13:55 ` [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1) Fabiano Rosas
2026-03-10 13:55 ` [PATCH 3/8] tests/qtest/migration: Fix misuse of listen_uri Fabiano Rosas
@ 2026-03-10 13:55 ` Fabiano Rosas
2026-03-10 15:47 ` Lukas Straub
2026-03-10 13:55 ` [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate Fabiano Rosas
` (5 subsequent siblings)
8 siblings, 1 reply; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 13:55 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Peter Xu, Lukas Straub, Laurent Vivier,
Paolo Bonzini
Now that the listen_uri is being properly used, tests can stop calling
migrate_incoming from their hooks. The _common functions and
migrate_start should take care of that.
Reviewed-by: Peter Xu <peterx@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20251215220041.12657-29-farosas@suse.de
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/colo-tests.c | 4 ++++
tests/qtest/migration/compression-tests.c | 6 ++++++
tests/qtest/migration/framework.c | 14 +++++++++++---
tests/qtest/migration/precopy-tests.c | 7 ++++---
tests/qtest/migration/tls-tests.c | 8 ++++++++
5 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/tests/qtest/migration/colo-tests.c b/tests/qtest/migration/colo-tests.c
index 7c438c196b..0d800429c5 100644
--- a/tests/qtest/migration/colo-tests.c
+++ b/tests/qtest/migration/colo-tests.c
@@ -55,6 +55,10 @@ static int test_colo_common(MigrateCommon *args,
data_hook = args->start_hook(from, to);
}
+ if (args->start.incoming_defer) {
+ migrate_incoming_qmp(to, args->listen_uri, NULL, "{}");
+ }
+
migrate_ensure_converge(from);
wait_for_serial("src_serial");
diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
index eb0b7d6b4b..bed39dece0 100644
--- a/tests/qtest/migration/compression-tests.c
+++ b/tests/qtest/migration/compression-tests.c
@@ -33,6 +33,7 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
{
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
args->start.incoming_defer = true;
@@ -43,6 +44,7 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
{
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
args->start.incoming_defer = true;
@@ -66,6 +68,7 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
{
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
args->start.incoming_defer = true;
@@ -85,6 +88,7 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
{
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
args->start.incoming_defer = true;
@@ -104,6 +108,7 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
{
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
args->start.incoming_defer = true;
@@ -156,6 +161,7 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
{
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
args->start.incoming_defer = true;
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 75605d1791..4cc63bba7b 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -837,6 +837,9 @@ int test_precopy_common(MigrateCommon *args)
QObject *out_channels = NULL;
g_assert(!args->cpr_channel || args->connect_channels);
+ if (args->start.incoming_defer) {
+ g_assert(args->listen_uri || args->connect_channels);
+ }
if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
return -1;
@@ -846,6 +849,14 @@ int test_precopy_common(MigrateCommon *args)
data_hook = args->start_hook(from, to);
}
+ if (args->start.incoming_defer && !args->start.defer_target_connect) {
+ if (args->connect_channels) {
+ in_channels = qobject_from_json(args->connect_channels,
+ &error_abort);
+ }
+ migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
+ }
+
/* Wait for the first serial output from the source */
if (args->result == MIG_TEST_SUCCEED) {
wait_for_serial("src_serial");
@@ -1077,9 +1088,6 @@ void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
migrate_set_parameter_str(from, "multifd-compression", method);
migrate_set_parameter_str(to, "multifd-compression", method);
- /* Start incoming migration from the 1st socket */
- migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
-
return NULL;
}
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index 31fd4af1ad..d2302ed692 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -239,9 +239,6 @@ static void *migrate_hook_start_fd(QTestState *from,
" 'arguments': { 'fdname': 'fd-mig' }}");
close(pair[0]);
- /* Start incoming migration from the 1st socket */
- migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}");
-
/* Send the 2nd socket to the target */
qtest_qmp_fds_assert_success(from, &pair[1], 1,
"{ 'execute': 'getfd',"
@@ -283,6 +280,7 @@ static void migrate_hook_end_fd(QTestState *from,
static void test_precopy_fd_socket(char *name, MigrateCommon *args)
{
args->connect_uri = "fd:fd-mig";
+ args->listen_uri = "fd:fd-mig";
args->start_hook = migrate_hook_start_fd;
args->end_hook = migrate_hook_end_fd;
@@ -443,6 +441,7 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
* everything will work alright even if guest page is changing.
*/
args->live = true;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -459,6 +458,7 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
* everything will work alright even if guest page is changing.
*/
args->live = true;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -475,6 +475,7 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
* everything will work alright even if guest page is changing.
*/
args->live = true;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 40a78bd2d2..f636802642 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -675,6 +675,7 @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
{
args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
args->end_hook = migrate_hook_end_tls_psk;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -687,6 +688,7 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
args->end_hook = migrate_hook_end_tls_psk;
args->result = MIG_TEST_FAIL;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.hide_stderr = true;
args->start.incoming_defer = true;
@@ -700,6 +702,7 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
{
args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
args->end_hook = migrate_hook_end_tls_psk;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -714,6 +717,7 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
{
args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
args->end_hook = migrate_hook_end_tls_x509;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -726,6 +730,7 @@ static void test_multifd_tcp_tls_x509_override_host(char *name,
{
args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
args->end_hook = migrate_hook_end_tls_x509;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -752,6 +757,7 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
args->end_hook = migrate_hook_end_tls_x509;
args->result = MIG_TEST_FAIL;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.hide_stderr = true;
@@ -765,6 +771,7 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
{
args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
args->end_hook = migrate_hook_end_tls_x509;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -778,6 +785,7 @@ static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
args->end_hook = migrate_hook_end_tls_x509;
args->result = MIG_TEST_FAIL;
+ args->listen_uri = "tcp:127.0.0.1:0";
args->start.incoming_defer = true;
args->start.hide_stderr = true;
--
2.51.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
` (2 preceding siblings ...)
2026-03-10 13:55 ` [PATCH 4/8] tests/qtest/migration: Stop invoking migrate_incoming from hooks Fabiano Rosas
@ 2026-03-10 13:55 ` Fabiano Rosas
2026-03-10 20:46 ` Peter Xu
2026-03-10 13:55 ` [PATCH 6/8] io: Fix TLS bye task leak Fabiano Rosas
` (4 subsequent siblings)
8 siblings, 1 reply; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 13:55 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Xu, Laurent Vivier, Paolo Bonzini
Some tests can cause QEMU to exit(1) too early while the incoming
coroutine has not yielded for a first time yet. This trips ASAN
because resources related to dispatching the incoming process will
still be allocated in the io/channel.c layer without a
straight-forward way for the migration code to clean them up.
Since this is an issue only affecting testing and leak detection,
let's make sure tests only use MIG_TEST_FAIL_DEST_QUIT_ERR when
strictly necessary.
To make this process easier, force exit-on-error=false for precopy
whenever the expected test result is MIG_TEST_FAIL. The distinction
between the two return codes is exactly that, the latter should never
cause exit(1).
The affected tests for now are the TLS tests "no_hostname" and
"mismatch_host".
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/framework.c | 5 ++++-
tests/qtest/migration/tls-tests.c | 6 ++++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 4cc63bba7b..cfb8409d33 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -854,7 +854,10 @@ int test_precopy_common(MigrateCommon *args)
in_channels = qobject_from_json(args->connect_channels,
&error_abort);
}
- migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
+
+ migrate_incoming_qmp(to, args->listen_uri, in_channels,
+ args->result == MIG_TEST_FAIL ?
+ "{ 'exit-on-error': false }" : "{}");
}
/* Wait for the first serial output from the source */
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index f636802642..6274906ad9 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -525,7 +525,8 @@ static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args)
args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = migrate_hook_start_tls_x509_no_host;
args->end_hook = migrate_hook_end_tls_x509;
- args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
+ args->result = MIG_TEST_FAIL;
+ args->start.incoming_defer = true;
args->start.hide_stderr = true;
@@ -559,7 +560,8 @@ static void test_precopy_tcp_tls_x509_mismatch_host(char *name,
args->listen_uri = "tcp:127.0.0.1:0";
args->start_hook = migrate_hook_start_tls_x509_mismatch_host;
args->end_hook = migrate_hook_end_tls_x509;
- args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
+ args->result = MIG_TEST_FAIL;
+ args->start.incoming_defer = true;
args->start.hide_stderr = true;
--
2.51.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 6/8] io: Fix TLS bye task leak
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
` (3 preceding siblings ...)
2026-03-10 13:55 ` [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate Fabiano Rosas
@ 2026-03-10 13:55 ` Fabiano Rosas
2026-03-10 14:29 ` Daniel P. Berrangé
2026-03-10 13:55 ` [PATCH 7/8] tests/qtest/migration: Fix leak in CPR exec test Fabiano Rosas
` (3 subsequent siblings)
8 siblings, 1 reply; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 13:55 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Xu, Daniel P. Berrangé
Recent fixes to TLS tasks memory handling have left the TLS bye task
uncovered. Fix by freeing the task in the same way the handshake task
is freed.
Direct leak of 704 byte(s) in 4 object(s) allocated from:
#1 0x7f5909b1d6a0 in g_malloc0 ../glib/gmem.c:163
#2 0x557650496d61 in qio_task_new ../io/task.c:58:12
#3 0x557650475d7f in qio_channel_tls_bye ../io/channel-tls.c:352:12
#4 0x55764f7a1bb4 in migration_tls_channel_end ../migration/tls.c:159:5
#5 0x55764f709750 in migration_ioc_shutdown_gracefully ../migration/multifd.c:462:9
#6 0x55764f6fcf53 in multifd_send_terminate_threads ../migration/multifd.c:493:13
#7 0x55764f6fcafb in multifd_send_shutdown ../migration/multifd.c:580:5
#8 0x55764f6e1b14 in migration_cleanup ../migration/migration.c:1323:9
#9 0x55764f6f5bac in migration_cleanup_bh ../migration/migration.c:1350:5
Fixes: d39d0f3acd ("io: fix cleanup for TLS I/O source data on cancellation")
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
io/channel-tls.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/io/channel-tls.c b/io/channel-tls.c
index 940fc3c6d1..31ec4d236d 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -352,7 +352,9 @@ void qio_channel_tls_bye(QIOChannelTLS *ioc, Error **errp)
task = qio_task_new(OBJECT(ioc), propagate_error, errp, NULL);
trace_qio_channel_tls_bye_start(ioc);
- qio_channel_tls_bye_task(ioc, task, NULL);
+ if (qio_channel_tls_bye_task(ioc, task, NULL)) {
+ qio_task_free(task);
+ }
}
static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
--
2.51.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 7/8] tests/qtest/migration: Fix leak in CPR exec test
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
` (4 preceding siblings ...)
2026-03-10 13:55 ` [PATCH 6/8] io: Fix TLS bye task leak Fabiano Rosas
@ 2026-03-10 13:55 ` Fabiano Rosas
2026-03-10 20:46 ` Peter Xu
2026-03-11 9:56 ` Prasad Pandit
2026-03-10 13:55 ` [PATCH 8/8] migration/multifd: Fix leaks of TLS error objects Fabiano Rosas
` (2 subsequent siblings)
8 siblings, 2 replies; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 13:55 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Peter Xu, Mark Kanda, Ben Chaney, Laurent Vivier,
Paolo Bonzini
The string was being dup'ed only to get around the const of the
qdict_get_str() return value.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration/cpr-tests.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 1b3d42e51c..fabdec4ff3 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -161,15 +161,16 @@ static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
static void wait_for_migration_event(QTestState *who, const char *waitfor)
{
QDict *rsp, *data;
- char *status;
bool done = false;
while (!done) {
+ const char *status;
+
rsp = qtest_qmp_eventwait_ref(who, "MIGRATION");
g_assert(qdict_haskey(rsp, "data"));
data = qdict_get_qdict(rsp, "data");
g_assert(qdict_haskey(data, "status"));
- status = g_strdup(qdict_get_str(data, "status"));
+ status = qdict_get_str(data, "status");
g_assert(strcmp(status, "failed"));
done = !strcmp(status, waitfor);
qobject_unref(rsp);
--
2.51.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 8/8] migration/multifd: Fix leaks of TLS error objects
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
` (5 preceding siblings ...)
2026-03-10 13:55 ` [PATCH 7/8] tests/qtest/migration: Fix leak in CPR exec test Fabiano Rosas
@ 2026-03-10 13:55 ` Fabiano Rosas
2026-03-10 20:49 ` Peter Xu
2026-03-11 9:32 ` Prasad Pandit
2026-03-10 19:47 ` [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Peter Xu
2026-03-11 11:56 ` Prasad Pandit
8 siblings, 2 replies; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 13:55 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Xu
The code currently ignores errors from multifd threads that happen
after a first error has already been propagated. Make sure the
subsequent errors are freed appopriately.
This fixes a leak of the TLS session->werr when the certificate
validation fails after multifd threads are already running. The first
writes on the threads will fail deep into the gnutls stack.
No need to check if(err) because the callers are all under a similar
check.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/multifd.c | 27 ++++++++++++---------------
1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/migration/multifd.c b/migration/multifd.c
index 8b9ed84805..035cb70f7b 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -412,28 +412,25 @@ bool multifd_send(MultiFDSendData **send_data)
/* Multifd send side hit an error; remember it and prepare to quit */
static void multifd_send_error_propagate(Error *err)
{
+ MigrationState *s = migrate_get_current();
+
/*
- * We don't want to exit each threads twice. Depending on where
- * we get the error, or if there are two independent errors in two
- * threads at the same time, we can end calling this function
- * twice.
+ * There may be independent errors in each thread. Propagate the
+ * first and free the subsequent ones.
*/
if (qatomic_xchg(&multifd_send_state->exiting, 1)) {
+ error_free(err);
return;
}
- if (err) {
- MigrationState *s = migrate_get_current();
+ migrate_error_propagate(s, err);
- migrate_error_propagate(s, err);
-
- if (s->state == MIGRATION_STATUS_SETUP ||
- s->state == MIGRATION_STATUS_PRE_SWITCHOVER ||
- s->state == MIGRATION_STATUS_DEVICE ||
- s->state == MIGRATION_STATUS_ACTIVE) {
- migrate_set_state(&s->state, s->state,
- MIGRATION_STATUS_FAILING);
- }
+ if (s->state == MIGRATION_STATUS_SETUP ||
+ s->state == MIGRATION_STATUS_PRE_SWITCHOVER ||
+ s->state == MIGRATION_STATUS_DEVICE ||
+ s->state == MIGRATION_STATUS_ACTIVE) {
+ migrate_set_state(&s->state, s->state,
+ MIGRATION_STATUS_FAILING);
}
}
--
2.51.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH 6/8] io: Fix TLS bye task leak
2026-03-10 13:55 ` [PATCH 6/8] io: Fix TLS bye task leak Fabiano Rosas
@ 2026-03-10 14:29 ` Daniel P. Berrangé
0 siblings, 0 replies; 24+ messages in thread
From: Daniel P. Berrangé @ 2026-03-10 14:29 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, Peter Maydell, Peter Xu
On Tue, Mar 10, 2026 at 10:55:38AM -0300, Fabiano Rosas wrote:
> Recent fixes to TLS tasks memory handling have left the TLS bye task
> uncovered. Fix by freeing the task in the same way the handshake task
> is freed.
>
> Direct leak of 704 byte(s) in 4 object(s) allocated from:
> #1 0x7f5909b1d6a0 in g_malloc0 ../glib/gmem.c:163
> #2 0x557650496d61 in qio_task_new ../io/task.c:58:12
> #3 0x557650475d7f in qio_channel_tls_bye ../io/channel-tls.c:352:12
> #4 0x55764f7a1bb4 in migration_tls_channel_end ../migration/tls.c:159:5
> #5 0x55764f709750 in migration_ioc_shutdown_gracefully ../migration/multifd.c:462:9
> #6 0x55764f6fcf53 in multifd_send_terminate_threads ../migration/multifd.c:493:13
> #7 0x55764f6fcafb in multifd_send_shutdown ../migration/multifd.c:580:5
> #8 0x55764f6e1b14 in migration_cleanup ../migration/migration.c:1323:9
> #9 0x55764f6f5bac in migration_cleanup_bh ../migration/migration.c:1350:5
>
> Fixes: d39d0f3acd ("io: fix cleanup for TLS I/O source data on cancellation")
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> io/channel-tls.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Acked-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 4/8] tests/qtest/migration: Stop invoking migrate_incoming from hooks
2026-03-10 13:55 ` [PATCH 4/8] tests/qtest/migration: Stop invoking migrate_incoming from hooks Fabiano Rosas
@ 2026-03-10 15:47 ` Lukas Straub
0 siblings, 0 replies; 24+ messages in thread
From: Lukas Straub @ 2026-03-10 15:47 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, Peter Maydell, Peter Xu, Laurent Vivier,
Paolo Bonzini
[-- Attachment #1: Type: text/plain, Size: 10767 bytes --]
On Tue, 10 Mar 2026 10:55:36 -0300
Fabiano Rosas <farosas@suse.de> wrote:
> Now that the listen_uri is being properly used, tests can stop calling
> migrate_incoming from their hooks. The _common functions and
> migrate_start should take care of that.
>
> Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Lukas Straub <lukasstraub2@web.de>
> Link: https://lore.kernel.org/qemu-devel/20251215220041.12657-29-farosas@suse.de
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> tests/qtest/migration/colo-tests.c | 4 ++++
> tests/qtest/migration/compression-tests.c | 6 ++++++
> tests/qtest/migration/framework.c | 14 +++++++++++---
> tests/qtest/migration/precopy-tests.c | 7 ++++---
> tests/qtest/migration/tls-tests.c | 8 ++++++++
> 5 files changed, 33 insertions(+), 6 deletions(-)
>
> diff --git a/tests/qtest/migration/colo-tests.c b/tests/qtest/migration/colo-tests.c
> index 7c438c196b..0d800429c5 100644
> --- a/tests/qtest/migration/colo-tests.c
> +++ b/tests/qtest/migration/colo-tests.c
> @@ -55,6 +55,10 @@ static int test_colo_common(MigrateCommon *args,
> data_hook = args->start_hook(from, to);
> }
>
> + if (args->start.incoming_defer) {
> + migrate_incoming_qmp(to, args->listen_uri, NULL, "{}");
> + }
> +
> migrate_ensure_converge(from);
> wait_for_serial("src_serial");
>
> diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
> index eb0b7d6b4b..bed39dece0 100644
> --- a/tests/qtest/migration/compression-tests.c
> +++ b/tests/qtest/migration/compression-tests.c
> @@ -33,6 +33,7 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
>
> static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
> {
> + args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
>
> args->start.incoming_defer = true;
> @@ -43,6 +44,7 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
>
> static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
> {
> + args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
>
> args->start.incoming_defer = true;
> @@ -66,6 +68,7 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
>
> static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
> {
> + args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
>
> args->start.incoming_defer = true;
> @@ -85,6 +88,7 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
>
> static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
> {
> + args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
>
> args->start.incoming_defer = true;
> @@ -104,6 +108,7 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
>
> static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
> {
> + args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
>
> args->start.incoming_defer = true;
> @@ -156,6 +161,7 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
>
> static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
> {
> + args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
>
> args->start.incoming_defer = true;
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index 75605d1791..4cc63bba7b 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -837,6 +837,9 @@ int test_precopy_common(MigrateCommon *args)
> QObject *out_channels = NULL;
>
> g_assert(!args->cpr_channel || args->connect_channels);
> + if (args->start.incoming_defer) {
> + g_assert(args->listen_uri || args->connect_channels);
> + }
>
> if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
> return -1;
> @@ -846,6 +849,14 @@ int test_precopy_common(MigrateCommon *args)
> data_hook = args->start_hook(from, to);
> }
>
> + if (args->start.incoming_defer && !args->start.defer_target_connect) {
> + if (args->connect_channels) {
> + in_channels = qobject_from_json(args->connect_channels,
> + &error_abort);
> + }
> + migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
> + }
> +
> /* Wait for the first serial output from the source */
> if (args->result == MIG_TEST_SUCCEED) {
> wait_for_serial("src_serial");
> @@ -1077,9 +1088,6 @@ void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
> migrate_set_parameter_str(from, "multifd-compression", method);
> migrate_set_parameter_str(to, "multifd-compression", method);
>
> - /* Start incoming migration from the 1st socket */
> - migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
> -
> return NULL;
> }
>
> diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
> index 31fd4af1ad..d2302ed692 100644
> --- a/tests/qtest/migration/precopy-tests.c
> +++ b/tests/qtest/migration/precopy-tests.c
> @@ -239,9 +239,6 @@ static void *migrate_hook_start_fd(QTestState *from,
> " 'arguments': { 'fdname': 'fd-mig' }}");
> close(pair[0]);
>
> - /* Start incoming migration from the 1st socket */
> - migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}");
> -
> /* Send the 2nd socket to the target */
> qtest_qmp_fds_assert_success(from, &pair[1], 1,
> "{ 'execute': 'getfd',"
> @@ -283,6 +280,7 @@ static void migrate_hook_end_fd(QTestState *from,
> static void test_precopy_fd_socket(char *name, MigrateCommon *args)
> {
> args->connect_uri = "fd:fd-mig";
> + args->listen_uri = "fd:fd-mig";
> args->start_hook = migrate_hook_start_fd;
> args->end_hook = migrate_hook_end_fd;
>
> @@ -443,6 +441,7 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
> * everything will work alright even if guest page is changing.
> */
> args->live = true;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -459,6 +458,7 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
> * everything will work alright even if guest page is changing.
> */
> args->live = true;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -475,6 +475,7 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
> * everything will work alright even if guest page is changing.
> */
> args->live = true;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
> index 40a78bd2d2..f636802642 100644
> --- a/tests/qtest/migration/tls-tests.c
> +++ b/tests/qtest/migration/tls-tests.c
> @@ -675,6 +675,7 @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
> {
> args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
> args->end_hook = migrate_hook_end_tls_psk;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -687,6 +688,7 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
> args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
> args->end_hook = migrate_hook_end_tls_psk;
> args->result = MIG_TEST_FAIL;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.hide_stderr = true;
> args->start.incoming_defer = true;
> @@ -700,6 +702,7 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
> {
> args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
> args->end_hook = migrate_hook_end_tls_psk;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -714,6 +717,7 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
> {
> args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
> args->end_hook = migrate_hook_end_tls_x509;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -726,6 +730,7 @@ static void test_multifd_tcp_tls_x509_override_host(char *name,
> {
> args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
> args->end_hook = migrate_hook_end_tls_x509;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -752,6 +757,7 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
> args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
> args->end_hook = migrate_hook_end_tls_x509;
> args->result = MIG_TEST_FAIL;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.hide_stderr = true;
> @@ -765,6 +771,7 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
> {
> args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
> args->end_hook = migrate_hook_end_tls_x509;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -778,6 +785,7 @@ static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
> args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
> args->end_hook = migrate_hook_end_tls_x509;
> args->result = MIG_TEST_FAIL;
> + args->listen_uri = "tcp:127.0.0.1:0";
>
> args->start.incoming_defer = true;
> args->start.hide_stderr = true;
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 3/8] tests/qtest/migration: Fix misuse of listen_uri
2026-03-10 13:55 ` [PATCH 3/8] tests/qtest/migration: Fix misuse of listen_uri Fabiano Rosas
@ 2026-03-10 15:48 ` Lukas Straub
0 siblings, 0 replies; 24+ messages in thread
From: Lukas Straub @ 2026-03-10 15:48 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, Peter Maydell, Peter Xu, Laurent Vivier,
Paolo Bonzini, Mark Kanda, Ben Chaney
[-- Attachment #1: Type: text/plain, Size: 27728 bytes --]
On Tue, 10 Mar 2026 10:55:35 -0300
Fabiano Rosas <farosas@suse.de> wrote:
> The listen_uri parameter is supposed to be used for the incoming
> migration while connect_uri for the outgoing migration. This is well
> documented in the header file.
>
> However, due to -incoming "defer", some tests set listen-uri =
> "defer", which is fine. But then, being without another parameter to
> define the uri to be use in migrate_incoming, some tests have been
> misusing connect_uri.
>
> Add a separate flag to denote "defer" and spare the tests from passing
> the string. Change the usage of listen_uri to it's original purpose.
>
> Link: https://lore.kernel.org/qemu-devel/20251215220041.12657-28-farosas@suse.de
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Lukas Straub <lukasstraub2@web.de>
> ---
> tests/qtest/migration/colo-tests.c | 4 ++-
> tests/qtest/migration/compression-tests.c | 12 +++----
> tests/qtest/migration/cpr-tests.c | 20 +++++++----
> tests/qtest/migration/file-tests.c | 41 ++++++++++++++++-------
> tests/qtest/migration/framework.c | 12 +++----
> tests/qtest/migration/framework.h | 7 ++++
> tests/qtest/migration/misc-tests.c | 4 +--
> tests/qtest/migration/precopy-tests.c | 14 +++++---
> tests/qtest/migration/tls-tests.c | 16 ++++-----
> 9 files changed, 83 insertions(+), 47 deletions(-)
>
> diff --git a/tests/qtest/migration/colo-tests.c b/tests/qtest/migration/colo-tests.c
> index ef880f5114..7c438c196b 100644
> --- a/tests/qtest/migration/colo-tests.c
> +++ b/tests/qtest/migration/colo-tests.c
> @@ -116,9 +116,11 @@ static void test_colo_multifd_common(MigrateCommon *args,
> bool failover_during_checkpoint,
> bool primary_failover)
> {
> - args->listen_uri = "defer";
> + args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = hook_start_multifd;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> + args->start.incoming_defer = true;
> +
> test_colo_common(args, failover_during_checkpoint, primary_failover);
> }
>
> diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
> index 845e622cd5..eb0b7d6b4b 100644
> --- a/tests/qtest/migration/compression-tests.c
> +++ b/tests/qtest/migration/compression-tests.c
> @@ -33,9 +33,9 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
>
> static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -43,9 +43,9 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
>
> static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
>
> @@ -66,9 +66,9 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
>
> static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -85,9 +85,9 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
>
> static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -104,9 +104,9 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
>
> static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -156,9 +156,9 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
>
> static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
> index 0d97b5b89f..1b3d42e51c 100644
> --- a/tests/qtest/migration/cpr-tests.c
> +++ b/tests/qtest/migration/cpr-tests.c
> @@ -32,10 +32,11 @@ static void test_mode_reboot(char *name, MigrateCommon *args)
> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> FILE_TEST_FILENAME);
>
> + args->listen_uri = uri;
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_mode_reboot;
>
> + args->start.incoming_defer = true;
> args->start.mem_type = MEM_TYPE_SHMEM;
> args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
>
> @@ -53,7 +54,7 @@ static void *test_mode_transfer_start(QTestState *from, QTestState *to)
> * migration, and cannot connect synchronously to the monitor, so defer
> * the target connection.
> */
> -static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
> +static void test_mode_transfer_common(MigrateCommon *args)
> {
> g_autofree char *cpr_path = g_strdup_printf("%s/cpr.sock", tmpfs);
> g_autofree char *mig_path = g_strdup_printf("%s/migsocket", tmpfs);
> @@ -84,7 +85,11 @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
> "addr.type=fd,addr.str=%d %s",
> cpr_sockfd, opts);
>
> - args->listen_uri = incoming_defer ? "defer" : uri;
> + /*
> + * The URI is used only for the deferred target connection when
> + * !incoming_defer.
> + */
> + args->listen_uri = uri;
> args->connect_channels = connect_channels;
> args->cpr_channel = cpr_channel;
> args->start_hook = test_mode_transfer_start;
> @@ -102,12 +107,14 @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
>
> static void test_mode_transfer(char *name, MigrateCommon *args)
> {
> - test_mode_transfer_common(args, false);
> + args->start.incoming_defer = false;
> + test_mode_transfer_common(args);
> }
>
> static void test_mode_transfer_defer(char *name, MigrateCommon *args)
> {
> - test_mode_transfer_common(args, true);
> + args->start.incoming_defer = true;
> + test_mode_transfer_common(args);
> }
>
> static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
> @@ -227,11 +234,10 @@ static void test_mode_exec(char *name, MigrateCommon *args)
> {
> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> FILE_TEST_FILENAME);
> - g_autofree char *listen_uri = g_strdup_printf("defer");
>
> args->connect_uri = uri;
> - args->listen_uri = listen_uri;
> args->start_hook = test_mode_exec_start;
> + args->start.incoming_defer = true;
>
> args->start.only_source = true;
> args->start.opts_source = "-machine aux-ram-share=on -nodefaults";
> diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
> index 5d1b861cf6..7597ff7552 100644
> --- a/tests/qtest/migration/file-tests.c
> +++ b/tests/qtest/migration/file-tests.c
> @@ -25,7 +25,9 @@ static void test_precopy_file(char *name, MigrateCommon *args)
> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> FILE_TEST_FILENAME);
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
> +
> + args->start.incoming_defer = true;
>
> test_file_common(args, true);
> }
> @@ -69,9 +71,11 @@ static void test_precopy_file_offset_fdset(char *name, MigrateCommon *args)
> g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
> FILE_TEST_OFFSET);
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
> args->start_hook = migrate_hook_start_file_offset_fdset;
>
> + args->start.incoming_defer = true;
> +
> test_file_common(args, false);
> }
> #endif
> @@ -83,7 +87,9 @@ static void test_precopy_file_offset(char *name, MigrateCommon *args)
> FILE_TEST_OFFSET);
>
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
> +
> + args->start.incoming_defer = true;
>
> test_file_common(args, false);
> }
> @@ -95,9 +101,11 @@ static void test_precopy_file_offset_bad(char *name, MigrateCommon *args)
> tmpfs, FILE_TEST_FILENAME);
>
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
> args->result = MIG_TEST_QMP_ERROR;
>
> + args->start.incoming_defer = true;
> +
> test_file_common(args, false);
> }
>
> @@ -107,8 +115,9 @@ static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args)
> FILE_TEST_FILENAME);
>
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
>
> test_file_common(args, false);
> @@ -120,8 +129,9 @@ static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args)
> FILE_TEST_FILENAME);
>
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
>
> test_file_common(args, true);
> @@ -132,8 +142,9 @@ static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args)
> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> FILE_TEST_FILENAME);
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
>
> @@ -146,8 +157,9 @@ static void test_multifd_file_mapped_ram(char *name, MigrateCommon *args)
> FILE_TEST_FILENAME);
>
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
>
> @@ -168,9 +180,10 @@ static void test_multifd_file_mapped_ram_dio(char *name, MigrateCommon *args)
> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> FILE_TEST_FILENAME);
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
> args->start_hook = migrate_hook_start_multifd_mapped_ram_dio;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> @@ -240,10 +253,11 @@ static void test_multifd_file_mapped_ram_fdset(char *name, MigrateCommon *args)
> FILE_TEST_OFFSET);
>
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
> args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset;
> args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> @@ -255,11 +269,13 @@ static void test_multifd_file_mapped_ram_fdset_dio(char *name,
> {
> g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
> FILE_TEST_OFFSET);
> +
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->listen_uri = uri;
> args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio;
> args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> @@ -286,8 +302,9 @@ test_precopy_file_mapped_ram_ignore_shared(char *name, MigrateCommon *args)
> {
> g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
> FILE_TEST_FILENAME);
> + args->listen_uri = uri;
> args->connect_uri = uri;
> - args->listen_uri = "defer";
> + args->start.incoming_defer = true;
>
> args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
> args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index b9371372de..75605d1791 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -428,7 +428,8 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
> "%s %s %s %s",
> kvm_opts ? kvm_opts : "",
> machine, machine_opts,
> - memory_backend, tmpfs, uri,
> + memory_backend, tmpfs,
> + args->incoming_defer ? "defer" : uri,
> events,
> arch_opts ? arch_opts : "",
> args->opts_target ? args->opts_target : "",
> @@ -873,8 +874,7 @@ int test_precopy_common(MigrateCommon *args)
> * migrate-incoming channels.
> */
> if (args->connect_channels) {
> - if (args->start.defer_target_connect &&
> - !strcmp(args->listen_uri, "defer")) {
> + if (args->start.defer_target_connect && args->start.incoming_defer) {
> in_channels = qobject_from_json(args->connect_channels,
> &error_abort);
> }
> @@ -898,8 +898,8 @@ int test_precopy_common(MigrateCommon *args)
> if (args->start.defer_target_connect) {
> qtest_connect(to);
> qtest_qmp_handshake(to, NULL);
> - if (!strcmp(args->listen_uri, "defer")) {
> - migrate_incoming_qmp(to, args->connect_uri, in_channels, "{}");
> + if (args->start.incoming_defer) {
> + migrate_incoming_qmp(to, NULL, in_channels, "{}");
> }
> }
>
> @@ -1048,7 +1048,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
> * We need to wait for the source to finish before starting the
> * destination.
> */
> - migrate_incoming_qmp(to, args->connect_uri, NULL, "{}");
> + migrate_incoming_qmp(to, args->listen_uri, NULL, "{}");
> wait_for_migration_complete(to);
>
> if (stop_src) {
> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
> index 80eef75893..f920735d05 100644
> --- a/tests/qtest/migration/framework.h
> +++ b/tests/qtest/migration/framework.h
> @@ -145,6 +145,13 @@ typedef struct {
> * migration_set_capabilities().
> */
> bool caps[MIGRATION_CAPABILITY__MAX];
> +
> + /*
> + * Whether to use "defer" as the uri for the -incoming command
> + * line option. If set to true, MigrateCommon.listen_uri will be
> + * used for the deferred migrate_incoming call.
> + */
> + bool incoming_defer;
> } MigrateStart;
>
> typedef enum PostcopyRecoveryFailStage {
> diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
> index 06da2657d5..a1704755d9 100644
> --- a/tests/qtest/migration/misc-tests.c
> +++ b/tests/qtest/migration/misc-tests.c
> @@ -217,7 +217,6 @@ static void do_test_validate_uri_channel(MigrateCommon *args)
>
> static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer",
> args->connect_uri = "tcp:127.0.0.1:0",
> args->connect_channels = ("[ { ""'channel-type': 'main',"
> " 'addr': { 'transport': 'socket',"
> @@ -225,6 +224,7 @@ static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
> " 'host': '127.0.0.1',"
> " 'port': '0' } } ]"),
>
> + args->start.incoming_defer = true;
> args->start.hide_stderr = true;
>
> do_test_validate_uri_channel(args);
> @@ -232,8 +232,8 @@ static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
>
> static void test_validate_uri_channels_none_set(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start.hide_stderr = true;
> + args->start.incoming_defer = true;
>
> do_test_validate_uri_channel(args);
> }
> diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
> index f17dc5176d..31fd4af1ad 100644
> --- a/tests/qtest/migration/precopy-tests.c
> +++ b/tests/qtest/migration/precopy-tests.c
> @@ -282,11 +282,12 @@ static void migrate_hook_end_fd(QTestState *from,
>
> static void test_precopy_fd_socket(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->connect_uri = "fd:fd-mig";
> args->start_hook = migrate_hook_start_fd;
> args->end_hook = migrate_hook_end_fd;
>
> + args->start.incoming_defer = true;
> +
> test_precopy_common(args);
> }
> #endif /* _WIN32 */
> @@ -435,7 +436,6 @@ migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
>
> static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd;
> /*
> * Multifd is more complicated than most of the features, it
> @@ -444,6 +444,7 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
> */
> args->live = true;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -451,7 +452,6 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
>
> static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy;
> /*
> * Multifd is more complicated than most of the features, it
> @@ -460,6 +460,7 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
> */
> args->live = true;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -467,7 +468,6 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
>
> static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page;
> /*
> * Multifd is more complicated than most of the features, it
> @@ -476,6 +476,7 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
> */
> args->live = true;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -483,7 +484,6 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
>
> static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_precopy_tcp_multifd;
> args->live = true;
> args->connect_channels = ("[ { 'channel-type': 'main',"
> @@ -492,6 +492,7 @@ static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args)
> " 'host': '127.0.0.1',"
> " 'port': '0' } } ]");
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -513,6 +514,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
> QTestState *from, *to, *to2;
>
> args->start.hide_stderr = true;
> + args->start.incoming_defer = true;
>
> if (migrate_start(&from, &to, "defer", &args->start)) {
> return;
> @@ -560,6 +562,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
> wait_for_migration_status(from, "cancelled", NULL);
>
> args->start.only_target = true;
> + args->start.incoming_defer = true;
>
> if (migrate_start(&from, &to2, "defer", &args->start)) {
> return;
> @@ -734,6 +737,7 @@ static void test_cancel_src_after_status(char *test_path, MigrateCommon *args)
> QTestState *from, *to;
>
> args->start.hide_stderr = true;
> + args->start.incoming_defer = true;
>
> if (migrate_start(&from, &to, "defer", &args->start)) {
> return;
> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
> index 4ce7f6c676..40a78bd2d2 100644
> --- a/tests/qtest/migration/tls-tests.c
> +++ b/tests/qtest/migration/tls-tests.c
> @@ -673,10 +673,10 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
>
> static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
> args->end_hook = migrate_hook_end_tls_psk;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -684,12 +684,12 @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
>
> static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
> args->end_hook = migrate_hook_end_tls_psk;
> args->result = MIG_TEST_FAIL;
>
> args->start.hide_stderr = true;
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -698,10 +698,10 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
> static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
> MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
> args->end_hook = migrate_hook_end_tls_psk;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
>
> @@ -712,10 +712,10 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
> static void test_multifd_tcp_tls_x509_default_host(char *name,
> MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
> args->end_hook = migrate_hook_end_tls_x509;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -724,10 +724,10 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
> static void test_multifd_tcp_tls_x509_override_host(char *name,
> MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
> args->end_hook = migrate_hook_end_tls_x509;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -749,11 +749,11 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
> * to load migration state, and thus just aborts the migration
> * without exiting.
> */
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
> args->end_hook = migrate_hook_end_tls_x509;
> args->result = MIG_TEST_FAIL;
>
> + args->start.incoming_defer = true;
> args->start.hide_stderr = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> @@ -763,10 +763,10 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
> static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
> MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
> args->end_hook = migrate_hook_end_tls_x509;
>
> + args->start.incoming_defer = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
> test_precopy_common(args);
> @@ -775,11 +775,11 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
> static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
> MigrateCommon *args)
> {
> - args->listen_uri = "defer";
> args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
> args->end_hook = migrate_hook_end_tls_x509;
> args->result = MIG_TEST_FAIL;
>
> + args->start.incoming_defer = true;
> args->start.hide_stderr = true;
> args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
` (6 preceding siblings ...)
2026-03-10 13:55 ` [PATCH 8/8] migration/multifd: Fix leaks of TLS error objects Fabiano Rosas
@ 2026-03-10 19:47 ` Peter Xu
2026-03-11 11:56 ` Prasad Pandit
8 siblings, 0 replies; 24+ messages in thread
From: Peter Xu @ 2026-03-10 19:47 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, Peter Maydell, Laurent Vivier, Paolo Bonzini
On Tue, Mar 10, 2026 at 10:55:33AM -0300, Fabiano Rosas wrote:
> When the migration-test is invoked with the '-p' flag (to run a single
> test), the glib code won't call the destroy function for the
> not-executed tests, causing the MigrationTest wrapper data to leak.
>
> This doesn't affect make check, but affects debugging use-cases where
> having a leak pop up in ASAN output is extra annoying.
>
> Fix by adding the tests data to a list and freeing them all at the end
> of migration-test execution. Any tests actually dispatched by glib
> will have the destroy function called as usual.
>
> Note that migration_test_add_suffix() is altered to call
> migration_test_add() so that there's only one place adding the data to
> the list.
>
> Performance is not an issue at the moment, we have < 100 tests.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1)
2026-03-10 13:55 ` [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1) Fabiano Rosas
@ 2026-03-10 19:59 ` Peter Xu
2026-03-11 10:34 ` Prasad Pandit
1 sibling, 0 replies; 24+ messages in thread
From: Peter Xu @ 2026-03-10 19:59 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, Peter Maydell, Laurent Vivier, Paolo Bonzini
On Tue, Mar 10, 2026 at 10:55:34AM -0300, Fabiano Rosas wrote:
> The UUID validation happens early enough during the migration process
> that the incoming coroutine hasn't yet yielded once so the
> EXIT_FAILURE from the coroutine can trigger ASAN leak detection due to
> the temporary socket from qio_net_listener_channel_func() still having
> an elevated refcount.
>
> Direct leak of 400 byte(s) in 1 object(s) allocated from:
> #0 0x55e668890a07 in malloc asan_malloc_linux.cpp:68:3
> #1 0x7f3c7e2b6648 in g_malloc ../glib/gmem.c:130
> #2 0x55e66a8ef05f in object_new_with_type ../qom/object.c:767:15
> #3 0x55e66a8ef178 in object_new ../qom/object.c:789:12
> #4 0x55e66a93bcc6 in qio_channel_socket_new ../io/channel-socket.c:70:31
> #5 0x55e66a93f34f in qio_channel_socket_accept ../io/channel-socket.c:401:12
> #6 0x55e66a96752a in qio_net_listener_channel_func ../io/net-listener.c:64:12
> #7 0x55e66a94bdac in qio_channel_fd_source_dispatch ../io/channel-watch.c:84:12
> #8 0x7f3c7e2adf4b in g_main_dispatch ../glib/gmain.c:3476
> #9 0x7f3c7e2adf4b in g_main_context_dispatch_unlocked ../glib/gmain.c:4284
> #10 0x7f3c7e2b00c8 in g_main_context_dispatch ../glib/gmain.c:4272
>
> Direct leak of 32 byte(s) in 1 object(s) allocated from:
> #0 0x55e668890a07 in malloc asan_malloc_linux.cpp:68:3
> #1 0x7f3c7e2b6648 in g_malloc ../glib/gmem.c:130
> #2 0x7f3c7e2ad40c in g_source_set_callback ../glib/gmain.c:1879
> #3 0x55e66a95c4d2 in qio_channel_add_watch_full ../io/channel.c:416:5
> #4 0x55e66a95c5a9 in qio_channel_add_watch_source ../io/channel.c:444:10
> #5 0x55e66a96380c in qio_net_listener_watch ../io/net-listener.c:166:46
> #6 0x55e66a96496a in qio_net_listener_set_client_func_internal ../io/net-listener.c:275:5
> #7 0x55e66a963e79 in qio_net_listener_set_client_func_full ../io/net-listener.c:284:5
> #8 0x55e669e1b3bb in socket_connect_incoming ../migration/socket.c:165:5
> #9 0x55e669d26b9f in migration_connect_incoming ../migration/channel.c:83:13
> #10 0x55e669d5f6d2 in qemu_setup_incoming_migration ../migration/migration.c:672:5
> #11 0x55e669d5f344 in qmp_migrate_incoming ../migration/migration.c:1771:5
>
> This is inconsequential in production, but let's give ourselves an
> easier time and avoid this situation when testing. The uuid_error test
> doesn't really need to check the exit code, just the migration state
> would be sufficient. Set exit-on-error=false for this test.
>
> While looking at this, add a comment to the source explaining that the
> incoming coroutine may block the main loop for a (longer than
> expected) while.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate
2026-03-10 13:55 ` [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate Fabiano Rosas
@ 2026-03-10 20:46 ` Peter Xu
2026-03-10 21:14 ` Fabiano Rosas
0 siblings, 1 reply; 24+ messages in thread
From: Peter Xu @ 2026-03-10 20:46 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, Peter Maydell, Laurent Vivier, Paolo Bonzini
On Tue, Mar 10, 2026 at 10:55:37AM -0300, Fabiano Rosas wrote:
> Some tests can cause QEMU to exit(1) too early while the incoming
> coroutine has not yielded for a first time yet. This trips ASAN
> because resources related to dispatching the incoming process will
> still be allocated in the io/channel.c layer without a
> straight-forward way for the migration code to clean them up.
>
> Since this is an issue only affecting testing and leak detection,
> let's make sure tests only use MIG_TEST_FAIL_DEST_QUIT_ERR when
> strictly necessary.
>
> To make this process easier, force exit-on-error=false for precopy
> whenever the expected test result is MIG_TEST_FAIL. The distinction
> between the two return codes is exactly that, the latter should never
> cause exit(1).
>
> The affected tests for now are the TLS tests "no_hostname" and
> "mismatch_host".
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> tests/qtest/migration/framework.c | 5 ++++-
> tests/qtest/migration/tls-tests.c | 6 ++++--
> 2 files changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index 4cc63bba7b..cfb8409d33 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -854,7 +854,10 @@ int test_precopy_common(MigrateCommon *args)
> in_channels = qobject_from_json(args->connect_channels,
> &error_abort);
> }
> - migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
> +
> + migrate_incoming_qmp(to, args->listen_uri, in_channels,
> + args->result == MIG_TEST_FAIL ?
> + "{ 'exit-on-error': false }" : "{}");
Can we set exit-on-error unconditionally?
In all cases:
Reviewed-by: Peter Xu <peterx@redhat.com>
> }
>
> /* Wait for the first serial output from the source */
> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
> index f636802642..6274906ad9 100644
> --- a/tests/qtest/migration/tls-tests.c
> +++ b/tests/qtest/migration/tls-tests.c
> @@ -525,7 +525,8 @@ static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args)
> args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = migrate_hook_start_tls_x509_no_host;
> args->end_hook = migrate_hook_end_tls_x509;
> - args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
> + args->result = MIG_TEST_FAIL;
> + args->start.incoming_defer = true;
>
> args->start.hide_stderr = true;
>
> @@ -559,7 +560,8 @@ static void test_precopy_tcp_tls_x509_mismatch_host(char *name,
> args->listen_uri = "tcp:127.0.0.1:0";
> args->start_hook = migrate_hook_start_tls_x509_mismatch_host;
> args->end_hook = migrate_hook_end_tls_x509;
> - args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
> + args->result = MIG_TEST_FAIL;
> + args->start.incoming_defer = true;
>
> args->start.hide_stderr = true;
>
> --
> 2.51.0
>
--
Peter Xu
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 7/8] tests/qtest/migration: Fix leak in CPR exec test
2026-03-10 13:55 ` [PATCH 7/8] tests/qtest/migration: Fix leak in CPR exec test Fabiano Rosas
@ 2026-03-10 20:46 ` Peter Xu
2026-03-11 9:56 ` Prasad Pandit
1 sibling, 0 replies; 24+ messages in thread
From: Peter Xu @ 2026-03-10 20:46 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, Peter Maydell, Mark Kanda, Ben Chaney, Laurent Vivier,
Paolo Bonzini
On Tue, Mar 10, 2026 at 10:55:39AM -0300, Fabiano Rosas wrote:
> The string was being dup'ed only to get around the const of the
> qdict_get_str() return value.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 8/8] migration/multifd: Fix leaks of TLS error objects
2026-03-10 13:55 ` [PATCH 8/8] migration/multifd: Fix leaks of TLS error objects Fabiano Rosas
@ 2026-03-10 20:49 ` Peter Xu
2026-03-11 9:32 ` Prasad Pandit
1 sibling, 0 replies; 24+ messages in thread
From: Peter Xu @ 2026-03-10 20:49 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, Peter Maydell
On Tue, Mar 10, 2026 at 10:55:40AM -0300, Fabiano Rosas wrote:
> The code currently ignores errors from multifd threads that happen
> after a first error has already been propagated. Make sure the
> subsequent errors are freed appopriately.
>
> This fixes a leak of the TLS session->werr when the certificate
> validation fails after multifd threads are already running. The first
> writes on the threads will fail deep into the gnutls stack.
>
> No need to check if(err) because the callers are all under a similar
> check.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate
2026-03-10 20:46 ` Peter Xu
@ 2026-03-10 21:14 ` Fabiano Rosas
2026-03-11 10:36 ` Prasad Pandit
2026-03-11 15:40 ` Peter Xu
0 siblings, 2 replies; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-10 21:14 UTC (permalink / raw)
To: Peter Xu; +Cc: qemu-devel, Peter Maydell, Laurent Vivier, Paolo Bonzini
Peter Xu <peterx@redhat.com> writes:
> On Tue, Mar 10, 2026 at 10:55:37AM -0300, Fabiano Rosas wrote:
>> Some tests can cause QEMU to exit(1) too early while the incoming
>> coroutine has not yielded for a first time yet. This trips ASAN
>> because resources related to dispatching the incoming process will
>> still be allocated in the io/channel.c layer without a
>> straight-forward way for the migration code to clean them up.
>>
>> Since this is an issue only affecting testing and leak detection,
>> let's make sure tests only use MIG_TEST_FAIL_DEST_QUIT_ERR when
>> strictly necessary.
>>
>> To make this process easier, force exit-on-error=false for precopy
>> whenever the expected test result is MIG_TEST_FAIL. The distinction
>> between the two return codes is exactly that, the latter should never
>> cause exit(1).
>>
>> The affected tests for now are the TLS tests "no_hostname" and
>> "mismatch_host".
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>> tests/qtest/migration/framework.c | 5 ++++-
>> tests/qtest/migration/tls-tests.c | 6 ++++--
>> 2 files changed, 8 insertions(+), 3 deletions(-)
>>
>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>> index 4cc63bba7b..cfb8409d33 100644
>> --- a/tests/qtest/migration/framework.c
>> +++ b/tests/qtest/migration/framework.c
>> @@ -854,7 +854,10 @@ int test_precopy_common(MigrateCommon *args)
>> in_channels = qobject_from_json(args->connect_channels,
>> &error_abort);
>> }
>> - migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
>> +
>> + migrate_incoming_qmp(to, args->listen_uri, in_channels,
>> + args->result == MIG_TEST_FAIL ?
>> + "{ 'exit-on-error': false }" : "{}");
>
> Can we set exit-on-error unconditionally?
>
Yeah, what about I just remove MIG_TEST_FAIL_DEST_QUIT_ERR entirely?
Aside from the ones mentioned in this series, there's only one other TLS
test using it. There are two tests setting qtest_set_expected_status(to,
EXIT_FAILURE); after migrate_cancel, but we can just wait for FAILED and
then qtest_quit(to);
> In all cases:
>
> Reviewed-by: Peter Xu <peterx@redhat.com>
>
>> }
>>
>> /* Wait for the first serial output from the source */
>> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
>> index f636802642..6274906ad9 100644
>> --- a/tests/qtest/migration/tls-tests.c
>> +++ b/tests/qtest/migration/tls-tests.c
>> @@ -525,7 +525,8 @@ static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args)
>> args->listen_uri = "tcp:127.0.0.1:0";
>> args->start_hook = migrate_hook_start_tls_x509_no_host;
>> args->end_hook = migrate_hook_end_tls_x509;
>> - args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
>> + args->result = MIG_TEST_FAIL;
>> + args->start.incoming_defer = true;
>>
>> args->start.hide_stderr = true;
>>
>> @@ -559,7 +560,8 @@ static void test_precopy_tcp_tls_x509_mismatch_host(char *name,
>> args->listen_uri = "tcp:127.0.0.1:0";
>> args->start_hook = migrate_hook_start_tls_x509_mismatch_host;
>> args->end_hook = migrate_hook_end_tls_x509;
>> - args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
>> + args->result = MIG_TEST_FAIL;
>> + args->start.incoming_defer = true;
>>
>> args->start.hide_stderr = true;
>>
>> --
>> 2.51.0
>>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 8/8] migration/multifd: Fix leaks of TLS error objects
2026-03-10 13:55 ` [PATCH 8/8] migration/multifd: Fix leaks of TLS error objects Fabiano Rosas
2026-03-10 20:49 ` Peter Xu
@ 2026-03-11 9:32 ` Prasad Pandit
1 sibling, 0 replies; 24+ messages in thread
From: Prasad Pandit @ 2026-03-11 9:32 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, Peter Maydell, Peter Xu
On Tue, 10 Mar 2026 at 19:26, Fabiano Rosas <farosas@suse.de> wrote:
> The code currently ignores errors from multifd threads that happen
> after a first error has already been propagated. Make sure the
> subsequent errors are freed appopriately.
>
> This fixes a leak of the TLS session->werr when the certificate
> validation fails after multifd threads are already running. The first
> writes on the threads will fail deep into the gnutls stack.
>
> No need to check if(err) because the callers are all under a similar
> check.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> migration/multifd.c | 27 ++++++++++++---------------
> 1 file changed, 12 insertions(+), 15 deletions(-)
>
> diff --git a/migration/multifd.c b/migration/multifd.c
> index 8b9ed84805..035cb70f7b 100644
> --- a/migration/multifd.c
> +++ b/migration/multifd.c
> @@ -412,28 +412,25 @@ bool multifd_send(MultiFDSendData **send_data)
> /* Multifd send side hit an error; remember it and prepare to quit */
> static void multifd_send_error_propagate(Error *err)
> {
> + MigrationState *s = migrate_get_current();
> +
> /*
> - * We don't want to exit each threads twice. Depending on where
> - * we get the error, or if there are two independent errors in two
> - * threads at the same time, we can end calling this function
> - * twice.
> + * There may be independent errors in each thread. Propagate the
> + * first and free the subsequent ones.
> */
> if (qatomic_xchg(&multifd_send_state->exiting, 1)) {
> + error_free(err);
> return;
> }
>
> - if (err) {
> - MigrationState *s = migrate_get_current();
> + migrate_error_propagate(s, err);
>
> - migrate_error_propagate(s, err);
> -
> - if (s->state == MIGRATION_STATUS_SETUP ||
> - s->state == MIGRATION_STATUS_PRE_SWITCHOVER ||
> - s->state == MIGRATION_STATUS_DEVICE ||
> - s->state == MIGRATION_STATUS_ACTIVE) {
> - migrate_set_state(&s->state, s->state,
> - MIGRATION_STATUS_FAILING);
> - }
> + if (s->state == MIGRATION_STATUS_SETUP ||
> + s->state == MIGRATION_STATUS_PRE_SWITCHOVER ||
> + s->state == MIGRATION_STATUS_DEVICE ||
> + s->state == MIGRATION_STATUS_ACTIVE) {
> + migrate_set_state(&s->state, s->state,
> + MIGRATION_STATUS_FAILING);
> }
> }
* Look okay.
Reviewed-by: Prasad Pandit <pjp@fedoraproject.org>
Thank you.
---
- Prasad
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 7/8] tests/qtest/migration: Fix leak in CPR exec test
2026-03-10 13:55 ` [PATCH 7/8] tests/qtest/migration: Fix leak in CPR exec test Fabiano Rosas
2026-03-10 20:46 ` Peter Xu
@ 2026-03-11 9:56 ` Prasad Pandit
1 sibling, 0 replies; 24+ messages in thread
From: Prasad Pandit @ 2026-03-11 9:56 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, Peter Maydell, Peter Xu, Mark Kanda, Ben Chaney,
Laurent Vivier, Paolo Bonzini
On Tue, 10 Mar 2026 at 19:26, Fabiano Rosas <farosas@suse.de> wrote:
> The string was being dup'ed only to get around the const of the
> qdict_get_str() return value.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> tests/qtest/migration/cpr-tests.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
> index 1b3d42e51c..fabdec4ff3 100644
> --- a/tests/qtest/migration/cpr-tests.c
> +++ b/tests/qtest/migration/cpr-tests.c
> @@ -161,15 +161,16 @@ static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
> static void wait_for_migration_event(QTestState *who, const char *waitfor)
> {
> QDict *rsp, *data;
> - char *status;
> bool done = false;
>
> while (!done) {
> + const char *status;
> +
> rsp = qtest_qmp_eventwait_ref(who, "MIGRATION");
> g_assert(qdict_haskey(rsp, "data"));
> data = qdict_get_qdict(rsp, "data");
> g_assert(qdict_haskey(data, "status"));
> - status = g_strdup(qdict_get_str(data, "status"));
> + status = qdict_get_str(data, "status");
> g_assert(strcmp(status, "failed"));
> done = !strcmp(status, waitfor);
> qobject_unref(rsp);
> --
> 2.51.0
* Look okay.
Reviewed-by: Prasad Pandit <pjp@fedoraproject.org>
Thank you.
---
- Prasad
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1)
2026-03-10 13:55 ` [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1) Fabiano Rosas
2026-03-10 19:59 ` Peter Xu
@ 2026-03-11 10:34 ` Prasad Pandit
1 sibling, 0 replies; 24+ messages in thread
From: Prasad Pandit @ 2026-03-11 10:34 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, Peter Maydell, Peter Xu, Laurent Vivier,
Paolo Bonzini
On Tue, 10 Mar 2026 at 19:26, Fabiano Rosas <farosas@suse.de> wrote:
> The UUID validation happens early enough during the migration process
> that the incoming coroutine hasn't yet yielded once so the
> EXIT_FAILURE from the coroutine can trigger ASAN leak detection due to
> the temporary socket from qio_net_listener_channel_func() still having
> an elevated refcount.
>
> Direct leak of 400 byte(s) in 1 object(s) allocated from:
> #0 0x55e668890a07 in malloc asan_malloc_linux.cpp:68:3
> #1 0x7f3c7e2b6648 in g_malloc ../glib/gmem.c:130
> #2 0x55e66a8ef05f in object_new_with_type ../qom/object.c:767:15
> #3 0x55e66a8ef178 in object_new ../qom/object.c:789:12
> #4 0x55e66a93bcc6 in qio_channel_socket_new ../io/channel-socket.c:70:31
> #5 0x55e66a93f34f in qio_channel_socket_accept ../io/channel-socket.c:401:12
> #6 0x55e66a96752a in qio_net_listener_channel_func ../io/net-listener.c:64:12
> #7 0x55e66a94bdac in qio_channel_fd_source_dispatch ../io/channel-watch.c:84:12
> #8 0x7f3c7e2adf4b in g_main_dispatch ../glib/gmain.c:3476
> #9 0x7f3c7e2adf4b in g_main_context_dispatch_unlocked ../glib/gmain.c:4284
> #10 0x7f3c7e2b00c8 in g_main_context_dispatch ../glib/gmain.c:4272
>
> Direct leak of 32 byte(s) in 1 object(s) allocated from:
> #0 0x55e668890a07 in malloc asan_malloc_linux.cpp:68:3
> #1 0x7f3c7e2b6648 in g_malloc ../glib/gmem.c:130
> #2 0x7f3c7e2ad40c in g_source_set_callback ../glib/gmain.c:1879
> #3 0x55e66a95c4d2 in qio_channel_add_watch_full ../io/channel.c:416:5
> #4 0x55e66a95c5a9 in qio_channel_add_watch_source ../io/channel.c:444:10
> #5 0x55e66a96380c in qio_net_listener_watch ../io/net-listener.c:166:46
> #6 0x55e66a96496a in qio_net_listener_set_client_func_internal ../io/net-listener.c:275:5
> #7 0x55e66a963e79 in qio_net_listener_set_client_func_full ../io/net-listener.c:284:5
> #8 0x55e669e1b3bb in socket_connect_incoming ../migration/socket.c:165:5
> #9 0x55e669d26b9f in migration_connect_incoming ../migration/channel.c:83:13
> #10 0x55e669d5f6d2 in qemu_setup_incoming_migration ../migration/migration.c:672:5
> #11 0x55e669d5f344 in qmp_migrate_incoming ../migration/migration.c:1771:5
>
> This is inconsequential in production, but let's give ourselves an
> easier time and avoid this situation when testing. The uuid_error test
> doesn't really need to check the exit code, just the migration state
> would be sufficient. Set exit-on-error=false for this test.
>
> While looking at this, add a comment to the source explaining that the
> incoming coroutine may block the main loop for a (longer than
> expected) while.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> migration/migration.c | 5 +++++
> tests/qtest/migration/misc-tests.c | 4 ++--
> 2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/migration/migration.c b/migration/migration.c
> index f949708629..c77832f851 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -898,6 +898,11 @@ void migration_start_incoming(void)
>
> Coroutine *co = qemu_coroutine_create(process_incoming_migration_co, NULL);
> qemu_coroutine_enter(co);
> + /*
> + * This doesn't return right away. The coroutine will run
> + * unimpeded until its first yield, which may happen as late as
> + * the force yield at ram_load_precopy().
> + */
> }
>
> int migrate_send_rp_switchover_ack(MigrationIncomingState *mis)
> diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
> index 810e9e6549..06da2657d5 100644
> --- a/tests/qtest/migration/misc-tests.c
> +++ b/tests/qtest/migration/misc-tests.c
> @@ -131,7 +131,7 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
> g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
> QTestState *from, *to;
>
> - if (migrate_start(&from, &to, uri, args)) {
> + if (migrate_start(&from, &to, "defer", args)) {
> return;
> }
>
> @@ -146,10 +146,10 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
> /* Wait for the first serial output from the source */
> wait_for_serial("src_serial");
>
> + migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
> migrate_qmp(from, to, uri, NULL, "{}");
>
> if (should_fail) {
> - qtest_set_expected_status(to, EXIT_FAILURE);
> wait_for_migration_fail(from, true);
> } else {
> wait_for_migration_complete(from);
> --
* Looks okay.
Reviewed-by: Prasad Pandit <pjp@fedoraproject.org>
Thank you.
---
- Prasad
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate
2026-03-10 21:14 ` Fabiano Rosas
@ 2026-03-11 10:36 ` Prasad Pandit
2026-03-11 15:40 ` Peter Xu
1 sibling, 0 replies; 24+ messages in thread
From: Prasad Pandit @ 2026-03-11 10:36 UTC (permalink / raw)
To: Fabiano Rosas
Cc: Peter Xu, qemu-devel, Peter Maydell, Laurent Vivier,
Paolo Bonzini
On Wed, 11 Mar 2026 at 02:45, Fabiano Rosas <farosas@suse.de> wrote:
> Yeah, what about I just remove MIG_TEST_FAIL_DEST_QUIT_ERR entirely?
> Aside from the ones mentioned in this series, there's only one other TLS
> test using it. There are two tests setting qtest_set_expected_status(to,
> EXIT_FAILURE); after migrate_cancel, but we can just wait for FAILED and
> then qtest_quit(to);
* True +1, sounds better.
---
- Prasad
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
` (7 preceding siblings ...)
2026-03-10 19:47 ` [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Peter Xu
@ 2026-03-11 11:56 ` Prasad Pandit
2026-03-11 12:57 ` Fabiano Rosas
8 siblings, 1 reply; 24+ messages in thread
From: Prasad Pandit @ 2026-03-11 11:56 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, Peter Maydell, Peter Xu, Laurent Vivier,
Paolo Bonzini
On Tue, 10 Mar 2026 at 19:26, Fabiano Rosas <farosas@suse.de> wrote:
> When the migration-test is invoked with the '-p' flag (to run a single
> test), the glib code won't call the destroy function for the
> not-executed tests, causing the MigrationTest wrapper data to leak.
* With -p, only test data for that test should be loaded, right?
Freeing the data for non-executed tests does not seem right.
> This doesn't affect make check, but affects debugging use-cases where
> having a leak pop up in ASAN output is extra annoying.
>
> Fix by adding the tests data to a list and freeing them all at the end
> of migration-test execution. Any tests actually dispatched by glib
> will have the destroy function called as usual.
>
> Note that migration_test_add_suffix() is altered to call
> migration_test_add() so that there's only one place adding the data to
> the list.
>
> Performance is not an issue at the moment, we have < 100 tests.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> tests/qtest/migration/framework.c | 2 ++
> tests/qtest/migration/migration-util.c | 19 ++++++++++++++-----
> tests/qtest/migration/migration-util.h | 2 +-
> 3 files changed, 17 insertions(+), 6 deletions(-)
>
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index 0bfc241914..b9371372de 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -1162,5 +1162,7 @@ int migration_env_clean(MigrationTestEnv *env)
> }
> g_free(tmpfs);
>
> + migration_tests_free();
> +
> return ret;
> }
> diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
> index c2462306a1..2648ad7f61 100644
> --- a/tests/qtest/migration/migration-util.c
> +++ b/tests/qtest/migration/migration-util.c
> @@ -38,6 +38,7 @@
> #include "linux/kvm.h"
> #endif
>
> +GQueue *tests;
>
> static char *SocketAddress_to_str(SocketAddress *addr)
> {
> @@ -243,6 +244,8 @@ static void migration_test_destroy(gpointer data)
> {
> MigrationTest *test = (MigrationTest *)data;
>
> + g_queue_remove(tests, test);
> +
> g_free(test->data);
> g_free(test->name);
> g_free(test);
> @@ -268,21 +271,27 @@ void migration_test_add(const char *path,
>
> qtest_add_data_func_full(path, test, migration_test_wrapper,
> migration_test_destroy);
> + if (!tests) {
> + tests = g_queue_new();
> + }
> + g_queue_push_tail(tests, test);
> }
>
> void migration_test_add_suffix(const char *path, const char *suffix,
> void (*fn)(char *name, MigrateCommon *args))
> {
> - MigrationTest *test = g_new0(MigrationTest, 1);
> + g_autofree char *name = NULL;
>
> g_assert(g_str_has_suffix(path, "/"));
> g_assert(!g_str_has_prefix(suffix, "/"));
>
> - test->func = fn;
> - test->name = g_strconcat(path, suffix, NULL);
> + name = g_strconcat(path, suffix, NULL);
> + migration_test_add(name, fn);
> +}
>
> - qtest_add_data_func_full(test->name, test, migration_test_wrapper,
> - migration_test_destroy);
> +void migration_tests_free(void)
> +{
> + g_queue_free_full(tests, migration_test_destroy);
> }
>
> #ifdef O_DIRECT
> diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
> index e73d69bab0..694773e594 100644
> --- a/tests/qtest/migration/migration-util.h
> +++ b/tests/qtest/migration/migration-util.h
> @@ -59,5 +59,5 @@ void migration_test_add_suffix(const char *path, const char *suffix,
> void (*fn)(char *name, MigrateCommon *args));
> char *migrate_get_connect_uri(QTestState *who);
> void migrate_set_ports(QTestState *to, QList *channel_list);
> -
> +void migration_tests_free(void);
> #endif /* MIGRATION_UTIL_H */
> --
* Change looks okay. Still I think there could be a way to load only
the data required for the specific test.
Reviewed-by: Prasad Pandit <pjp@fedoraproject.org>
Thank you.
---
- Prasad
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data
2026-03-11 11:56 ` Prasad Pandit
@ 2026-03-11 12:57 ` Fabiano Rosas
0 siblings, 0 replies; 24+ messages in thread
From: Fabiano Rosas @ 2026-03-11 12:57 UTC (permalink / raw)
To: Prasad Pandit
Cc: qemu-devel, Peter Maydell, Peter Xu, Laurent Vivier,
Paolo Bonzini
Prasad Pandit <ppandit@redhat.com> writes:
> On Tue, 10 Mar 2026 at 19:26, Fabiano Rosas <farosas@suse.de> wrote:
>> When the migration-test is invoked with the '-p' flag (to run a single
>> test), the glib code won't call the destroy function for the
>> not-executed tests, causing the MigrationTest wrapper data to leak.
>
> * With -p, only test data for that test should be loaded, right?
> Freeing the data for non-executed tests does not seem right.
>
Hm, I don't know what you mean by loaded. Glib will call only the
specific test, passing the data that was registered along with that
test. That registration is done beforehand with the glib_add_data_func
functions. We need to allocate that somehow. If we allocated it, we must
free it.
Ideally, glib would provide a hook for setup and another one for
teardown, which would work like (I think) you expect. But it doesn't do
that. The "destroy" hook is semantically "undo what was done in the
test", not free resources allocated outside of glib.
Some simpler tests can avoid dynamically allocation, but migration-test
is a bit more complex, so I don't see a way to do that at the moment.
>> This doesn't affect make check, but affects debugging use-cases where
>> having a leak pop up in ASAN output is extra annoying.
>>
>> Fix by adding the tests data to a list and freeing them all at the end
>> of migration-test execution. Any tests actually dispatched by glib
>> will have the destroy function called as usual.
>>
>> Note that migration_test_add_suffix() is altered to call
>> migration_test_add() so that there's only one place adding the data to
>> the list.
>>
>> Performance is not an issue at the moment, we have < 100 tests.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>> tests/qtest/migration/framework.c | 2 ++
>> tests/qtest/migration/migration-util.c | 19 ++++++++++++++-----
>> tests/qtest/migration/migration-util.h | 2 +-
>> 3 files changed, 17 insertions(+), 6 deletions(-)
>>
>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>> index 0bfc241914..b9371372de 100644
>> --- a/tests/qtest/migration/framework.c
>> +++ b/tests/qtest/migration/framework.c
>> @@ -1162,5 +1162,7 @@ int migration_env_clean(MigrationTestEnv *env)
>> }
>> g_free(tmpfs);
>>
>> + migration_tests_free();
>> +
>> return ret;
>> }
>> diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
>> index c2462306a1..2648ad7f61 100644
>> --- a/tests/qtest/migration/migration-util.c
>> +++ b/tests/qtest/migration/migration-util.c
>> @@ -38,6 +38,7 @@
>> #include "linux/kvm.h"
>> #endif
>>
>> +GQueue *tests;
>>
>> static char *SocketAddress_to_str(SocketAddress *addr)
>> {
>> @@ -243,6 +244,8 @@ static void migration_test_destroy(gpointer data)
>> {
>> MigrationTest *test = (MigrationTest *)data;
>>
>> + g_queue_remove(tests, test);
>> +
>> g_free(test->data);
>> g_free(test->name);
>> g_free(test);
>> @@ -268,21 +271,27 @@ void migration_test_add(const char *path,
>>
>> qtest_add_data_func_full(path, test, migration_test_wrapper,
>> migration_test_destroy);
>> + if (!tests) {
>> + tests = g_queue_new();
>> + }
>> + g_queue_push_tail(tests, test);
>> }
>>
>> void migration_test_add_suffix(const char *path, const char *suffix,
>> void (*fn)(char *name, MigrateCommon *args))
>> {
>> - MigrationTest *test = g_new0(MigrationTest, 1);
>> + g_autofree char *name = NULL;
>>
>> g_assert(g_str_has_suffix(path, "/"));
>> g_assert(!g_str_has_prefix(suffix, "/"));
>>
>> - test->func = fn;
>> - test->name = g_strconcat(path, suffix, NULL);
>> + name = g_strconcat(path, suffix, NULL);
>> + migration_test_add(name, fn);
>> +}
>>
>> - qtest_add_data_func_full(test->name, test, migration_test_wrapper,
>> - migration_test_destroy);
>> +void migration_tests_free(void)
>> +{
>> + g_queue_free_full(tests, migration_test_destroy);
>> }
>>
>> #ifdef O_DIRECT
>> diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
>> index e73d69bab0..694773e594 100644
>> --- a/tests/qtest/migration/migration-util.h
>> +++ b/tests/qtest/migration/migration-util.h
>> @@ -59,5 +59,5 @@ void migration_test_add_suffix(const char *path, const char *suffix,
>> void (*fn)(char *name, MigrateCommon *args));
>> char *migrate_get_connect_uri(QTestState *who);
>> void migrate_set_ports(QTestState *to, QList *channel_list);
>> -
>> +void migration_tests_free(void);
>> #endif /* MIGRATION_UTIL_H */
>> --
>
> * Change looks okay. Still I think there could be a way to load only
> the data required for the specific test.
> Reviewed-by: Prasad Pandit <pjp@fedoraproject.org>
>
> Thank you.
> ---
> - Prasad
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate
2026-03-10 21:14 ` Fabiano Rosas
2026-03-11 10:36 ` Prasad Pandit
@ 2026-03-11 15:40 ` Peter Xu
1 sibling, 0 replies; 24+ messages in thread
From: Peter Xu @ 2026-03-11 15:40 UTC (permalink / raw)
To: Fabiano Rosas; +Cc: qemu-devel, Peter Maydell, Laurent Vivier, Paolo Bonzini
On Tue, Mar 10, 2026 at 06:14:30PM -0300, Fabiano Rosas wrote:
> Peter Xu <peterx@redhat.com> writes:
>
> > On Tue, Mar 10, 2026 at 10:55:37AM -0300, Fabiano Rosas wrote:
> >> Some tests can cause QEMU to exit(1) too early while the incoming
> >> coroutine has not yielded for a first time yet. This trips ASAN
> >> because resources related to dispatching the incoming process will
> >> still be allocated in the io/channel.c layer without a
> >> straight-forward way for the migration code to clean them up.
> >>
> >> Since this is an issue only affecting testing and leak detection,
> >> let's make sure tests only use MIG_TEST_FAIL_DEST_QUIT_ERR when
> >> strictly necessary.
> >>
> >> To make this process easier, force exit-on-error=false for precopy
> >> whenever the expected test result is MIG_TEST_FAIL. The distinction
> >> between the two return codes is exactly that, the latter should never
> >> cause exit(1).
> >>
> >> The affected tests for now are the TLS tests "no_hostname" and
> >> "mismatch_host".
> >>
> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> >> ---
> >> tests/qtest/migration/framework.c | 5 ++++-
> >> tests/qtest/migration/tls-tests.c | 6 ++++--
> >> 2 files changed, 8 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> >> index 4cc63bba7b..cfb8409d33 100644
> >> --- a/tests/qtest/migration/framework.c
> >> +++ b/tests/qtest/migration/framework.c
> >> @@ -854,7 +854,10 @@ int test_precopy_common(MigrateCommon *args)
> >> in_channels = qobject_from_json(args->connect_channels,
> >> &error_abort);
> >> }
> >> - migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
> >> +
> >> + migrate_incoming_qmp(to, args->listen_uri, in_channels,
> >> + args->result == MIG_TEST_FAIL ?
> >> + "{ 'exit-on-error': false }" : "{}");
> >
> > Can we set exit-on-error unconditionally?
> >
>
> Yeah, what about I just remove MIG_TEST_FAIL_DEST_QUIT_ERR entirely?
> Aside from the ones mentioned in this series, there's only one other TLS
> test using it. There are two tests setting qtest_set_expected_status(to,
> EXIT_FAILURE); after migrate_cancel, but we can just wait for FAILED and
> then qtest_quit(to);
Ah yes we have one left.. Sounds good, can also be done on top if you will
queue this.
--
Peter Xu
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2026-03-11 15:41 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-10 13:55 [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Fabiano Rosas
2026-03-10 13:55 ` [PATCH 2/8] tests/qtest/migration: Change validate_uuid test to not trigger exit(1) Fabiano Rosas
2026-03-10 19:59 ` Peter Xu
2026-03-11 10:34 ` Prasad Pandit
2026-03-10 13:55 ` [PATCH 3/8] tests/qtest/migration: Fix misuse of listen_uri Fabiano Rosas
2026-03-10 15:48 ` Lukas Straub
2026-03-10 13:55 ` [PATCH 4/8] tests/qtest/migration: Stop invoking migrate_incoming from hooks Fabiano Rosas
2026-03-10 15:47 ` Lukas Straub
2026-03-10 13:55 ` [PATCH 5/8] tests/qtest/migration: Force exit-on-error=false when appropriate Fabiano Rosas
2026-03-10 20:46 ` Peter Xu
2026-03-10 21:14 ` Fabiano Rosas
2026-03-11 10:36 ` Prasad Pandit
2026-03-11 15:40 ` Peter Xu
2026-03-10 13:55 ` [PATCH 6/8] io: Fix TLS bye task leak Fabiano Rosas
2026-03-10 14:29 ` Daniel P. Berrangé
2026-03-10 13:55 ` [PATCH 7/8] tests/qtest/migration: Fix leak in CPR exec test Fabiano Rosas
2026-03-10 20:46 ` Peter Xu
2026-03-11 9:56 ` Prasad Pandit
2026-03-10 13:55 ` [PATCH 8/8] migration/multifd: Fix leaks of TLS error objects Fabiano Rosas
2026-03-10 20:49 ` Peter Xu
2026-03-11 9:32 ` Prasad Pandit
2026-03-10 19:47 ` [PATCH 1/8] tests/qtest/migration: Fix leak of migration tests data Peter Xu
2026-03-11 11:56 ` Prasad Pandit
2026-03-11 12:57 ` Fabiano Rosas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox