From nobody Sun Jul 26 10:07:05 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1783602085; cv=none; d=zohomail.com; s=zohoarc; b=R1k6bVw2oBe8mxTAmwcTHRv7ZfxV+H3/y0Id3yGUjLeJbGF6SFcBw8HJXDbSfnU1WJYTVAOi+4RVVnXMg24IFziPfYdMlJLXwLjS4diKnB2R04k9hdNPtl6NRtBLC7heLRHToVGQhuTruV5NLbyqw2W3RP/eFenexjG8N0BES38= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783602085; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=lkGkC2aHmdrtLDzb/HV2Nyjr4DO6xZ+D9HeDhIbAcCc=; b=V55PhGphSjQSzaBl90FNRleq0SalM43XIHd5Gq5C6ypkhI3XbYaiu/rtkrQGn/VHDFqfCypqzqVd/VqfLtCfl2+wCzdK4+EbbOQ7gpb3gViHUSdoGlL/sBlAR4+rUqW5wANv1N0L5on3kcMA4n6D8HswqDu8FHjAtWkcyFEaHeE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1783602085925559.3670092031904; Thu, 9 Jul 2026 06:01:25 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1whoN9-0001fa-OW; Thu, 09 Jul 2026 09:00:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1whoMy-0001c2-88 for qemu-devel@nongnu.org; Thu, 09 Jul 2026 09:00:53 -0400 Received: from mail-pg1-x52d.google.com ([2607:f8b0:4864:20::52d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1whoMu-0008W3-Tl for qemu-devel@nongnu.org; Thu, 09 Jul 2026 09:00:47 -0400 Received: by mail-pg1-x52d.google.com with SMTP id 41be03b00d2f7-c9e7391839cso1525395a12.0 for ; Thu, 09 Jul 2026 06:00:44 -0700 (PDT) Received: from C02G720XMD6P.sg.corp.seagroup.com ([111.223.92.222]) by smtp.googlemail.com with ESMTPSA id 5a478bee46e88-31174ac14f2sm32908611eec.27.2026.07.09.06.00.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Jul 2026 06:00:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783602043; x=1784206843; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=lkGkC2aHmdrtLDzb/HV2Nyjr4DO6xZ+D9HeDhIbAcCc=; b=V00+BiXj48ZfmAd3JvvcQRQNdL4yo+KsFl+SAI1tL/vY0OkCTJ+a9r/PFbjSK/Hl1h VFtsgtEy/ITKNoSq5KIWc6RcJMTffvA0DrZ5I2FsvKMeM6/2OgupXe55zhcEkh+ZjhjB f+SYztfUxfAppK0/9IHUkaKhl+ZX56yH5tcfvZO7IGzoYaO2arCI3tTDmrxSjNtT8jo4 Cf4yPj2W21vyc8KcsaQkD2pYGl10m9dv76KFlfmRprKKD1c9aK1nzWko/Aq1vHU5wvPB nIqWEjJqTMDnpXEb0dN0A0WTajurdESIyXGvh8wfhQSYJi9nSey83ipnXgOEC7snolOV m2eA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783602043; x=1784206843; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=lkGkC2aHmdrtLDzb/HV2Nyjr4DO6xZ+D9HeDhIbAcCc=; b=anguP3kEC98hlaO6uVjl2BBxZSCkneWvWCzFbuZ2z1mJMURMY3WPHl9+xDUr22+wa1 J2loe7FtNBabuQMevtNRy6xWd3nCyvi2wxxwQhLowqutK5y+vl04xTDFquCdzRiOlraV vD49VYxRwRcyhXimFrFISKoAf6jZ1ytYRPHl9nm5yBYCrP+/ZSqFdouSS7yPSJkIPD5J FZEkUbumQyKUqA1/KPS9jfXLfrJAzlZnTAqkIM1SL62sh7efKLNTTrZEN8INGkKjo/Md oUSthWReJPgQeJsv38/LRBHvFjK9rKmAx8wH+ZsNgxpbdkXb6z4Ibw6OnVKoYKHs+KjX gKrA== X-Forwarded-Encrypted: i=1; AHgh+RoflmWp9FNXqEIyNDggUh76yeudHAzqkKsMRFlUyNrnGaHF9wUo0zCRXmkeElrHKHKbD2LDlmGMajMi@nongnu.org X-Gm-Message-State: AOJu0YxFAmqArXOuWR+3koc3PiscMENc3AHXUisnqkmI8Lp8GL4XgNJt 8kkqsh64/5XI1m6VJC6WwuchKEY2aebVwUo0QVH7PBE1IwELoDHjKzb2 X-Gm-Gg: AfdE7cmXeljx7i00iDjZs9qHJ5ng5R0bInzCCYG5by/zvZ90BRJ4gF2GtvHkb9QY9md fJCD0lpcEZahBuDHA45vhs/kMct8JxvV1I59UIPxXgiCOjNShVfDXHS8SSmL4PezG0Zd7hNshYE dOhJYbA2wj2Ye08xj61lRUL1ph1lCqE45zJ8cH8F2cnDaEEcDG48wZqzb0ncbsL1NhJOBhUKU26 axLsQWuC7ANBpQXhjFDp9V/brRMluQ3O/UaWP9bQTsiUSuVstOsBw6JVmMPJMmbaneOvpqviRAA OESY3/OWWEqT2BPVzAWkIa57yy8Yqp7ZI1CHZ1FzbOvEGJ8etmkAbyj5yzzCUQ/L6k1Faur7BdS Ff8F7uZ94vREBcZXt/vw27swV8NyiOQ3Ca+04rLgAFwa19aaV1gnuyizuSDcHwN0PPZuIXfFdFk PkAajI9Heha/l0NzSA5+Ls3egfjbtaAuSWLHGUXSKaiWr4lP2aqalrKmQf X-Received: by 2002:a05:6a21:103:b0:3c0:9c1b:d0b6 with SMTP id adf61e73a8af0-3c0bd31298fmr8676661637.65.1783602043090; Thu, 09 Jul 2026 06:00:43 -0700 (PDT) From: phind.uet@gmail.com To: Peter Xu , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Cc: Nguyen Dinh Phi , qemu-devel@nongnu.org Subject: [PATCH 1/3] tests/migration: Factor out per-process launch and setup helpers Date: Thu, 9 Jul 2026 21:00:25 +0800 Message-ID: <20260709130032.58667-2-phind.uet@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260709130032.58667-1-phind.uet@gmail.com> References: <20260709130032.58667-1-phind.uet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::52d; envelope-from=phind.uet@gmail.com; helo=mail-pg1-x52d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1783602087895158500 Content-Type: text/plain; charset="utf-8" From: Nguyen Dinh Phi migrate_start() always spawned source and destination together, and migrate_start_set_capabilities() required both QTestState pointers at once. This coupling prevents launching a third QEMU instance or re-configuring an existing destination as a new source. Split the logic into three public helpers: migrate_launch_source() / migrate_launch_dest() Spawn a single QEMU process and record its serial file path on the returned QTestState. migrate_setup_instance() Register the event callback and apply migration capabilities to one already-running process. Can be called again to re-wire the same process for a different role. migrate_start() is kept for backward compatibility and now delegates to these helpers internally. Signed-off-by: Nguyen Dinh Phi --- tests/qtest/migration/framework.c | 253 +++++++++++++++++------------- tests/qtest/migration/framework.h | 18 ++- 2 files changed, 165 insertions(+), 106 deletions(-) diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/fram= ework.c index a830b96f41..305b8968ff 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -208,9 +208,11 @@ static QList *migrate_start_get_qmp_capabilities(const= MigrateStart *args) return capabilities; } =20 -static void migrate_start_set_capabilities(QTestState *from, QTestState *t= o, - MigrateStart *args) +void migrate_setup_instance(QTestState *who, QTestMigrationState *state, + MigrateStart *args) { + qtest_qmp_set_event_callback(who, migrate_watch_for_events, state); + *state =3D (QTestMigrationState) { .suspend_me =3D args->suspend_me }; /* * MigrationCapability_lookup and MIGRATION_CAPABILITY_ constants * are from qapi-types-migration.h. @@ -220,25 +222,13 @@ static void migrate_start_set_capabilities(QTestState= *from, QTestState *to, * Enable return path first, since other features depend on it. */ if (args->caps[MIGRATION_CAPABILITY_RETURN_PATH]) { - if (from) { - migrate_set_capability(from, "return-path", true); - } - if (to) { - migrate_set_capability(to, "return-path", true); - } + migrate_set_capability(who, "return-path", true); } =20 for (uint8_t i =3D 0; i < MIGRATION_CAPABILITY__MAX; i++) { - if (!args->caps[i]) { - continue; - } - if (from) { - migrate_set_capability(from, - MigrationCapability_lookup.array[i], true); - } - if (to) { - migrate_set_capability(to, - MigrationCapability_lookup.array[i], true); + if (args->caps[i]) { + migrate_set_capability(who, MigrationCapability_lookup.array[i= ], + true); } } =20 @@ -246,26 +236,17 @@ static void migrate_start_set_capabilities(QTestState= *from, QTestState *to, * Always enable migration events. Libvirt always uses it, let's try * to mimic as closer as that. */ - migrate_set_capability(from, "events", true); - if (!args->defer_target_connect && to) { - migrate_set_capability(to, "events", true); - } + migrate_set_capability(who, "events", true); =20 - /* + /* * Default number of channels should be fine for most * tests. Individual tests can override by calling * migrate_set_parameter() directly. */ if (args->caps[MIGRATION_CAPABILITY_MULTIFD]) { - migrate_set_parameter_int(from, "multifd-channels", + migrate_set_parameter_int(who, "multifd-channels", MULTIFD_TEST_CHANNELS); - if (to) { - migrate_set_parameter_int(to, "multifd-channels", - MULTIFD_TEST_CHANNELS); - } } - - return; } =20 static char *test_shmem_path(void) @@ -308,12 +289,28 @@ static char *migrate_mem_type_get_opts(MemType type, = const char *memory_size) return opts; } =20 -int migrate_args(char **from, char **to, MigrateStart *args) +/* + * Build a QEMU command line for one migration participant. + * + * @serial_name : serial output file basename under tmpfs + * @is_target : set to true if the new qemu process is destination side + * @extra_opts : extra arguments + * @defer_events : when true and is_target is set, use the command-line + * event flag instead of the QMP capability (for deferred + * monitor connections) + * @args : common process settings + * + * Returns 0 and sets *cmd_out on success. Returns -1 and calls + * g_test_skip() if the machine type is not available. + */ +static int migrate_build_cmd(const char *serial_name, + bool is_target, + const char *extra_opts, + bool defer_events, + MigrateStart *args, + char **cmd_out) { - /* options for source and target */ g_autofree gchar *arch_opts =3D NULL; - gchar *cmd_source =3D NULL; - gchar *cmd_target =3D NULL; const gchar *ignore_stderr; g_autofree char *mem_object =3D NULL; const char *kvm_opts =3D NULL; @@ -323,16 +320,10 @@ int migrate_args(char **from, char **to, MigrateStart= *args) g_autofree char *machine =3D NULL; const char *bootpath =3D bootfile_get(); g_autofree char *memory_backend =3D NULL; - const char *events; =20 if (strcmp(arch, "i386") =3D=3D 0 || strcmp(arch, "x86_64") =3D=3D 0) { memory_size =3D "150M"; - - if (g_str_equal(arch, "i386")) { - machine_alias =3D "pc"; - } else { - machine_alias =3D "q35"; - } + machine_alias =3D g_str_equal(arch, "i386") ? "pc" : "q35"; arch_opts =3D g_strdup_printf( "-drive if=3Dnone,id=3Dd0,file=3D%s,format=3Draw " "-device ide-hd,drive=3Dd0,secs=3D1,cyls=3D1,heads=3D1", bootp= ath); @@ -346,13 +337,13 @@ int migrate_args(char **from, char **to, MigrateStart= *args) end_address =3D S390_TEST_MEM_END; } else if (strcmp(arch, "ppc64") =3D=3D 0) { memory_size =3D "256M"; - start_address =3D PPC_TEST_MEM_START; - end_address =3D PPC_TEST_MEM_END; machine_alias =3D "pseries"; machine_opts =3D "vsmt=3D8"; arch_opts =3D g_strdup_printf( "-nodefaults -machine " PSERIES_DEFAULT_CAPABILITIES " " "-bios %s", bootpath); + start_address =3D PPC_TEST_MEM_START; + end_address =3D PPC_TEST_MEM_END; } else if (strcmp(arch, "aarch64") =3D=3D 0) { memory_size =3D "150M"; machine_alias =3D "virt"; @@ -394,53 +385,103 @@ int migrate_args(char **from, char **to, MigrateStar= t *args) } =20 if (!qtest_has_machine(machine_alias)) { - g_autofree char *msg =3D g_strdup_printf("machine %s not supported= ", machine_alias); + g_autofree char *msg =3D g_strdup_printf("machine %s not supported= ", + machine_alias); g_test_skip(msg); return -1; } =20 machine =3D resolve_machine_version(machine_alias, QEMU_ENV_SRC, QEMU_ENV_DST); - g_test_message("Using machine type: %s", machine); =20 - cmd_source =3D g_strdup_printf("-accel kvm%s -accel tcg " - "-machine %s,%s " - "-name source,debug-threads=3Don " - "%s " - "-serial file:%s/src_serial " - "%s %s %s", - kvm_opts ? kvm_opts : "", - machine, machine_opts, - memory_backend, tmpfs, - arch_opts ? arch_opts : "", - args->opts_source ? args->opts_source : "= ", - ignore_stderr); + if (is_target) { + /* + * If the monitor connection is deferred, enable events on the com= mand + * line so none are missed. This is for testing only, do not set + * migration options like this in general. + */ + const char *events =3D defer_events ? "-global migration.x-events= =3Don" + : ""; + *cmd_out =3D g_strdup_printf( + "-accel kvm%s -accel tcg " + "-machine %s,%s " + "-name target,debug-threads=3Don " + "%s " + "-serial file:%s/%s " + "-incoming defer " + "%s %s %s %s", + kvm_opts ? kvm_opts : "", + machine, machine_opts, + memory_backend, tmpfs, serial_name, + events, + arch_opts ? arch_opts : "", + extra_opts ? extra_opts : "", + ignore_stderr); + } else { + *cmd_out =3D g_strdup_printf( + "-accel kvm%s -accel tcg " + "-machine %s,%s " + "-name source,debug-threads=3Don " + "%s " + "-serial file:%s/%s " + "%s %s %s", + kvm_opts ? kvm_opts : "", + machine, machine_opts, + memory_backend, tmpfs, serial_name, + arch_opts ? arch_opts : "", + extra_opts ? extra_opts : "", + ignore_stderr); + } =20 - /* - * If the monitor connection is deferred, enable events on the command= line - * so none are missed. This is for testing only, do not set migration - * options like this in general. - */ - events =3D args->defer_target_connect ? "-global migration.x-events=3D= on" : ""; - - cmd_target =3D g_strdup_printf("-accel kvm%s -accel tcg " - "-machine %s,%s " - "-name target,debug-threads=3Don " - "%s " - "-serial file:%s/dest_serial " - "-incoming defer " - "%s %s %s %s", - kvm_opts ? kvm_opts : "", - machine, machine_opts, - memory_backend, tmpfs, - events, - arch_opts ? arch_opts : "", - args->opts_target ? args->opts_target : "= ", - ignore_stderr); - - *from =3D cmd_source; - *to =3D cmd_target; + return 0; +} + +/* + * Launch a QEMU process as a migration source. + * Returns the QTestState on success, or NULL otherwise + */ +QTestState *migrate_launch_source(const char *serial_name, MigrateStart *a= rgs) +{ + g_autofree char *cmd =3D NULL; + g_autoptr(QList) capabilities =3D migrate_start_get_qmp_capabilities(a= rgs); + + if (migrate_build_cmd(serial_name, false, args->opts_source, + false, args, &cmd)) { + return NULL; + } + return qtest_init_ext(QEMU_ENV_SRC, cmd, capabilities, true); +} + +/* + * Launch a QEMU process as a migration destination. + * Returns the QTestState on success, or NULL otherwise + */ +QTestState *migrate_launch_dest(const char *serial_name, MigrateStart *arg= s) +{ + g_autofree char *cmd =3D NULL; + g_autoptr(QList) capabilities =3D migrate_start_get_qmp_capabilities(a= rgs); + + if (migrate_build_cmd(serial_name, true, args->opts_target, + args->defer_target_connect, args, &cmd)) { + return NULL; + } + return qtest_init_ext(QEMU_ENV_DST, cmd, capabilities, + !args->defer_target_connect); +} + +int migrate_args(char **from, char **to, MigrateStart *args) +{ + if (migrate_build_cmd("src_serial", false, args->opts_source, + false, args, from)) { + return -1; + } + if (migrate_build_cmd("dest_serial", true, args->opts_target, + args->defer_target_connect, args, to)) { + g_free(*from); + *from =3D NULL; + return -1; + } return 0; } =20 @@ -482,43 +523,45 @@ static void migrate_mem_type_cleanup(MemType type) =20 int migrate_start(QTestState **from, QTestState **to, MigrateStart *args) { - g_autofree gchar *cmd_source =3D NULL; - g_autofree gchar *cmd_target =3D NULL; - g_autoptr(QList) capabilities =3D migrate_start_get_qmp_capabilities(a= rgs); - if (!migrate_mem_type_prepare(args->mem_type)) { return -1; } =20 - dst_state =3D (QTestMigrationState) { }; - src_state =3D (QTestMigrationState) { }; + src_state =3D (QTestMigrationState){}; + dst_state =3D (QTestMigrationState){}; bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me); - src_state.suspend_me =3D args->suspend_me; - - if (migrate_args(&cmd_source, &cmd_target, args)) { - return -1; - } =20 if (!args->only_target) { - *from =3D qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, t= rue); - qtest_qmp_set_event_callback(*from, - migrate_watch_for_events, - &src_state); + *from =3D migrate_launch_source("src_serial", args); + if (!*from) { + return -1; + } + migrate_setup_instance(*from, &src_state, args); } =20 if (!args->only_source) { - *to =3D qtest_init_ext(QEMU_ENV_DST, cmd_target, capabilities, - !args->defer_target_connect); - qtest_qmp_set_event_callback(*to, - migrate_watch_for_events, - &dst_state); + *to =3D migrate_launch_dest("dest_serial", args); + if (!*to) { + if (!args->only_target) { + qtest_quit(*from); + } + return -1; + } + if (!args->defer_target_connect) { + migrate_setup_instance(*to, &dst_state, args); + } else { + /* + * The monitor is not connected yet; only register the event + * callback so no events are missed. + * The caller must call migrate_setup_instance() after + * qtest_connect() if it wants to setup any capability + */ + qtest_qmp_set_event_callback(*to, migrate_watch_for_events, + &dst_state); + } } =20 migrate_mem_type_cleanup(args->mem_type); - migrate_start_set_capabilities(*from, - args->only_source ? NULL : *to, - args); - return 0; } =20 diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/fram= ework.h index 941cbd7102..f054ef8f4d 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -225,10 +225,27 @@ typedef struct { bool live; } MigrateCommon; =20 +typedef struct QTestMigrationState QTestMigrationState; + void wait_for_serial(const char *side); void migrate_prepare_for_dirty_mem(QTestState *from); void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to); =20 +/* + * Start a QEMU process which has serial set to @serial_name + */ +QTestState *migrate_launch_source(const char *serial_name, MigrateStart *a= rgs); +/* + * Start a QEMU process which has serial set to @serial_name + */ +QTestState *migrate_launch_dest(const char *serial_name, MigrateStart *arg= s); +/* + * Registers the event callback and sets migration capabilities on an + * already-running process + */ +void migrate_setup_instance(QTestState *who, QTestMigrationState *state, + MigrateStart *args); + int migrate_args(char **from, char **to, MigrateStart *args); int migrate_start(QTestState **from, QTestState **to, MigrateStart *args); void migrate_end(QTestState *from, QTestState *to, bool test_dest); @@ -240,7 +257,6 @@ int test_precopy_common(MigrateCommon *args); void test_precopy_unix_common(MigrateCommon *args); void test_file_common(MigrateCommon *args, bool stop_src); =20 -typedef struct QTestMigrationState QTestMigrationState; QTestMigrationState *get_src(void); QTestMigrationState *get_dst(void); =20 --=20 2.50.1 (Apple Git-155) From nobody Sun Jul 26 10:07:05 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1783602086; cv=none; d=zohomail.com; s=zohoarc; b=XDD/EUHSLG6rS6gjgim3jIkkqCHJKxZXP6WK3CZBQuHbUcjxR2XRnQWWK9yyNZQ+HG8we/KY4k3BJIb+qVcT6dZ+qWtkIVqISr2YNPUkWdlsAe3eXwmsMCl1MSr1lrDkI11340lDlgzTBttf8lUy0xHP0Ptuzfqm4ENZjuH4TCM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783602086; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=20jw1gKRRwIYR9j0Ca71dxRoZUJNv80X1O03w2o3ayc=; b=M+tzW9DkT1ppK3h+WJOH3r6J/wttAc8JdKzM53tuoNy+iy7GjPrEFAAKfXRuFqDAuU/j0IUuuvrlkMnb7fUxwoyOZNlL+TwuWcd6HrEMz8CB3j7uAFzEJ/VY4JBo0H4QSNXuGVnSrjyd9bQ98UMcdSNshkKSOgx2QSimt2BdEZw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1783602086054311.05561302101455; Thu, 9 Jul 2026 06:01:26 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1whoNB-0001g2-7i; Thu, 09 Jul 2026 09:01:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1whoN5-0001dP-JN for qemu-devel@nongnu.org; Thu, 09 Jul 2026 09:00:56 -0400 Received: from mail-pg1-x52e.google.com ([2607:f8b0:4864:20::52e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1whoN0-00005Z-BJ for qemu-devel@nongnu.org; Thu, 09 Jul 2026 09:00:55 -0400 Received: by mail-pg1-x52e.google.com with SMTP id 41be03b00d2f7-ca913a601fbso209317a12.3 for ; Thu, 09 Jul 2026 06:00:49 -0700 (PDT) Received: from C02G720XMD6P.sg.corp.seagroup.com ([111.223.92.222]) by smtp.googlemail.com with ESMTPSA id 5a478bee46e88-31174ac14f2sm32908611eec.27.2026.07.09.06.00.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Jul 2026 06:00:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783602048; x=1784206848; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=20jw1gKRRwIYR9j0Ca71dxRoZUJNv80X1O03w2o3ayc=; b=GB6UqlkJlvJ5SRua3N6dXO116O9MSzD+1VbAj6l9zgGw8MFcYTe6EwzEQxaJUGQ9U7 OJZ4tg+IsIzJ8OLeri61mIU2cpwnntUFKvAp5OO37BRxDXD5zq3YNR0zbIcD/zf0AngU fS2H8VZXHQELBVqJEhUfOsCD+q7o9w803HUeJFIgH7nPPw5EIgmDZuUBLpKDPo/qgFEm ihqP8cVqxurvGKwEfprRO+cvZNsk/hIB8bEY8ObqAc1R17SqoN3c3HOGDQGlAjaMWsDR mRDn7egArsorgaTUM/xmLFNf14oy9yb8/L7fsHKLhPzz9mS1ogmKFrFVJzRf/gublZoH GPXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783602048; x=1784206848; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=20jw1gKRRwIYR9j0Ca71dxRoZUJNv80X1O03w2o3ayc=; b=fsaEP7W3EErx9pGCzS9r4pgk4u1CPDc96cMeklx8nmuaYB2A6hESkVnkaCbKGQ5r0b VAoCqda9eWCpvtOZm6eN31zcclWxfNiDW3s9uawgH+KOZFN5xUG78F4Go2xni5sgceAJ ARY49UvU/vkPzi4inbMwGHU8aKyjZTU56icFk8yicZi46Uocdn8UyF9ASQ0Sv/Yp+fG/ 1XU6Bx5uhVMKTk7X7dOiOmF1tt8adtVmViX9xvj8WdM9gtmARgL/9H7kW1J6NyqemBF8 n3F52Den3Uy4T+MhQaP6Z6Yb0JlNKDUryJJPmyicIRDODgldot1gHPsGgSyi8O9wYKC0 KiRA== X-Forwarded-Encrypted: i=1; AHgh+RqICOYgUisKRQVDfapwRB7kt4rkmb5VScrFNIgiqgKHhX4wtr04LNKLMBJUu64dM8G5LFykHjNxNW4u@nongnu.org X-Gm-Message-State: AOJu0YzqVg6gh1+grhBpq6/GKWMNJ5SMGCfa1wqSDQepzhv2I5q+K4Mj HKlmsrj1R5ERwCGVDhaQoOTIdtz97Oi80vhFZLG3pguZeHZI2/t8KfMi X-Gm-Gg: AfdE7cnOcKt+Sh8fI/xN70LjABnTE6PebO42uD7KelmEB8yRVyVZSzyeDSwMCncBF/u PgZncLr7WvS6x8ciGvgoB16lbBt7UzDGawy0/mGMRHcVC3RJmtl4oqrZyfwJxL+ZIpkuO9VqrOx 6DF4YhNsN3eeUjeq4uCFCOc9yysnt/Y77QUggsW/9EgBf/wLNAfWJAgdQ46PIa5mGZ2L+IE65U7 SYV3CbAK1OSpXgzH1FQCDuIv/InJLQClII3Yrcem4nk+VItED383EFb1EKdNFm/irWW0vThgKbP 3+s3jGm/5aDWEJtVVaz+DVbucCGjYiM0hpdKVNGQJ8SuLXcv5K/R1HnmxUiAph0ofcPIM5JpQHM J9Tg8MZqsExi1Q0O98H2SKa742yvSGIKc8rswrl7c+laR0AWQBOG8Q3qEqK8Dl9R3d1ObkBPh/s LSOc9/F2G76etvklc37APF7fUtSTeaIJ4oMgP4yO2EIGTFZ4HTKAqG3RsN X-Received: by 2002:a05:6a21:a95:b0:3bf:6c08:fb9d with SMTP id adf61e73a8af0-3c0bcead1b1mr9350607637.49.1783602047307; Thu, 09 Jul 2026 06:00:47 -0700 (PDT) From: phind.uet@gmail.com To: Fabiano Rosas , Laurent Vivier , Paolo Bonzini , Lukas Straub , Peter Xu , "Maciej S. Szmigiero" , Mark Kanda , Ben Chaney Cc: Nguyen Dinh Phi , qemu-devel@nongnu.org Subject: [PATCH 2/3] tests/migration: Retrieve serial path from QTestState Date: Thu, 9 Jul 2026 21:00:26 +0800 Message-ID: <20260709130032.58667-3-phind.uet@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260709130032.58667-1-phind.uet@gmail.com> References: <20260709130032.58667-1-phind.uet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::52e; envelope-from=phind.uet@gmail.com; helo=mail-pg1-x52e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1783602087961158500 Content-Type: text/plain; charset="utf-8" From: Nguyen Dinh Phi Replace hard-coded side names ("src_serial", "dest_serial") passed to wait_for_serial() with qtest_get_serial_path(). The path is stored on the QTestState at launch time by migrate_launch_source/dest(). Hard-coded names break when a process changes role, for example when a completed destination is re-used as a new source in a chain migration. Signed-off-by: Nguyen Dinh Phi --- tests/qtest/libqtest.c | 16 ++++++++++++ tests/qtest/libqtest.h | 8 ++++++ tests/qtest/migration/colo-tests.c | 14 +++++----- tests/qtest/migration/cpr-tests.c | 8 +++--- tests/qtest/migration/framework.c | 37 ++++++++++++++++----------- tests/qtest/migration/framework.h | 2 +- tests/qtest/migration/misc-tests.c | 4 +-- tests/qtest/migration/precopy-tests.c | 28 +++++++++++--------- 8 files changed, 76 insertions(+), 41 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index c33c799c92..3fccd089dd 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -93,6 +93,7 @@ struct QTestState GList *pending_events; QTestQMPEventCallback eventCB; void *eventData; + char *serial_path; }; =20 static GHookList abrt_hooks; @@ -688,10 +689,25 @@ void qtest_quit(QTestState *s) } =20 g_list_free(s->pending_events); + if (s->serial_path) { + unlink(s->serial_path); + g_free(s->serial_path); + } =20 g_free(s); } =20 +void qtest_set_serial_path(QTestState *s, const char *path) +{ + g_free(s->serial_path); + s->serial_path =3D g_strdup(path); +} + +const char *qtest_get_serial_path(QTestState *s) +{ + return s->serial_path; +} + static void socket_send(int fd, const char *buf, size_t size) { ssize_t res =3D qemu_send_full(fd, buf, size); diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index 45217fb8dc..0958cf1662 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -98,6 +98,14 @@ QTestState *qtest_init(const char *extra_args); QTestState *qtest_init_ext(const char *var, const char *extra_args, QList *capabilities, bool do_connect); =20 +/** + * qtest_set_serial_path: + * @s: #QTestState instance + * @path: full path to the serial output file to unlink on qtest_quit() + */ +void qtest_set_serial_path(QTestState *s, const char *path); +const char *qtest_get_serial_path(QTestState *s); + /** * qtest_init_without_qmp_handshake: * @extra_args: other arguments to pass to QEMU. CAUTION: these diff --git a/tests/qtest/migration/colo-tests.c b/tests/qtest/migration/col= o-tests.c index f7f9ba491b..c6b6faa578 100644 --- a/tests/qtest/migration/colo-tests.c +++ b/tests/qtest/migration/colo-tests.c @@ -58,21 +58,21 @@ static int test_colo_common(MigrateCommon *args, migrate_incoming_qmp(to, args->uri, NULL, "{}"); =20 migrate_ensure_converge(from); - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); =20 migrate_qmp(from, to, NULL, NULL, "{}"); =20 wait_for_migration_status(from, "colo", NULL); wait_for_resume(to, get_dst()); =20 - wait_for_serial("src_serial"); - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(from)); + wait_for_serial(qtest_get_serial_path(to)); =20 /* wait for 3 checkpoints */ for (int i =3D 0; i < 3; i++) { qtest_qmp_eventwait(to, "RESUME"); - wait_for_serial("src_serial"); - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(from)); + wait_for_serial(qtest_get_serial_path(to)); } =20 if (failover_during_checkpoint) { @@ -83,13 +83,13 @@ static int test_colo_common(MigrateCommon *args, "'arguments': {'instances':" "[{'type': 'migration'}]}}= "); qtest_qmp_assert_success(from, "{'execute': 'x-colo-lost-heartbeat= '}"); - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); } else { qtest_qmp_assert_success(to, "{'exec-oob': 'yank', 'id': 'yank-cmd= ', " "'arguments': {'instances':" "[{'type': 'migration'}]}}"); qtest_qmp_assert_success(to, "{'execute': 'x-colo-lost-heartbeat'}= "); - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(to)); } =20 if (args->end_hook) { diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-= tests.c index 0bec753b4a..f56bbe48fe 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -66,7 +66,7 @@ static int test_transfer(MigrateCommon *args, const char = *cpr_channel, =20 migrate_set_parameter_str(from, "mode", "cpr-transfer"); =20 - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); =20 qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); wait_for_stop(from, get_src()); @@ -89,7 +89,7 @@ static int test_transfer(MigrateCommon *args, const char = *cpr_channel, qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}"); =20 wait_for_resume(to, get_dst()); - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(to)); =20 migrate_end(from, to, true); =20 @@ -241,7 +241,7 @@ static void test_cpr_exec(MigrateCommon *args) data_hook =3D args->start_hook(from, NULL); } =20 - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); set_cpr_exec_args(from, args); migrate_set_capability(from, "events", true); migrate_qmp(from, NULL, connect_uri, NULL, "{}"); @@ -260,7 +260,7 @@ static void test_cpr_exec(MigrateCommon *args) =20 wait_for_resume(to, get_dst()); /* Device on target is still named src_serial because args do not chan= ge */ - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); =20 if (args->end_hook) { args->end_hook(from, to, data_hook); diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/fram= ework.c index 305b8968ff..a7dffeb82c 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -58,10 +58,9 @@ static char *tmpfs; * we get an 'A' followed by an endless string of 'B's * but on the destination we won't have the A (unless we enabled suspend/r= esume) */ -void wait_for_serial(const char *side) +void wait_for_serial(const char *path) { - g_autofree char *serialpath =3D g_strdup_printf("%s/%s", tmpfs, side); - FILE *serialfile =3D fopen(serialpath, "r"); + FILE *serialfile =3D fopen(path, "r"); =20 do { int readvalue =3D fgetc(serialfile); @@ -82,7 +81,7 @@ void wait_for_serial(const char *side) break; =20 default: - fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, sid= e); + fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, pat= h); g_assert_not_reached(); } } while (true); @@ -450,7 +449,12 @@ QTestState *migrate_launch_source(const char *serial_n= ame, MigrateStart *args) false, args, &cmd)) { return NULL; } - return qtest_init_ext(QEMU_ENV_SRC, cmd, capabilities, true); + QTestState *s =3D qtest_init_ext(QEMU_ENV_SRC, cmd, capabilities, true= ); + if (s) { + g_autofree char *path =3D g_strdup_printf("%s/%s", tmpfs, serial_n= ame); + qtest_set_serial_path(s, path); + } + return s; } =20 /* @@ -466,8 +470,13 @@ QTestState *migrate_launch_dest(const char *serial_nam= e, MigrateStart *args) args->defer_target_connect, args, &cmd)) { return NULL; } - return qtest_init_ext(QEMU_ENV_DST, cmd, capabilities, - !args->defer_target_connect); + QTestState *s =3D qtest_init_ext(QEMU_ENV_DST, cmd, capabilities, + !args->defer_target_connect); + if (s) { + g_autofree char *path =3D g_strdup_printf("%s/%s", tmpfs, serial_n= ame); + qtest_set_serial_path(s, path); + } + return s; } =20 int migrate_args(char **from, char **to, MigrateStart *args) @@ -595,8 +604,6 @@ void migrate_end(QTestState *from, QTestState *to, bool= test_dest) =20 cleanup("migsocket"); cleanup("cpr.sock"); - cleanup("src_serial"); - cleanup("dest_serial"); cleanup(FILE_TEST_FILENAME); } =20 @@ -631,7 +638,7 @@ static int migrate_postcopy_prepare(QTestState **from_p= tr, " 'port': '0' } } ] } }"); =20 /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); wait_for_suspend(from, &src_state); =20 migrate_qmp(from, to, NULL, NULL, "{}"); @@ -657,7 +664,7 @@ static void migrate_postcopy_complete(QTestState *from,= QTestState *to, } =20 /* Make sure we get at least one "B" on destination */ - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(to)); =20 if (env->uffd_feature_thread_id) { read_blocktime(to); @@ -895,7 +902,7 @@ int test_precopy_common(MigrateCommon *args) =20 /* Wait for the first serial output from the source */ if (args->result =3D=3D MIG_TEST_SUCCEED) { - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); wait_for_suspend(from, &src_state); } =20 @@ -972,7 +979,7 @@ int test_precopy_common(MigrateCommon *args) qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}"); } =20 - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(to)); } =20 finish: @@ -1063,7 +1070,7 @@ void test_file_common(MigrateCommon *args, bool stop_= src) } =20 migrate_ensure_converge(from); - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); =20 if (stop_src) { qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); @@ -1090,7 +1097,7 @@ void test_file_common(MigrateCommon *args, bool stop_= src) } wait_for_resume(to, &dst_state); =20 - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(to)); =20 if (check_offset) { file_check_offset_region(); diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/fram= ework.h index f054ef8f4d..f6936eb8c6 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -227,7 +227,7 @@ typedef struct { =20 typedef struct QTestMigrationState QTestMigrationState; =20 -void wait_for_serial(const char *side); +void wait_for_serial(const char *path); void migrate_prepare_for_dirty_mem(QTestState *from); void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to); =20 diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/mis= c-tests.c index ec6d438cdc..73750335f1 100644 --- a/tests/qtest/migration/misc-tests.c +++ b/tests/qtest/migration/misc-tests.c @@ -128,7 +128,7 @@ static void do_test_validate_uuid(MigrateStart *args, b= ool should_fail) migrate_set_capability(from, "validate-uuid", true); =20 /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); =20 migrate_incoming_qmp(to, uri, NULL, "{}"); migrate_qmp(from, to, uri, NULL, "{}"); @@ -185,7 +185,7 @@ static void do_test_validate_uri_channel(MigrateCommon = *args) } =20 /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); =20 migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); =20 diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/= precopy-tests.c index a23d51126b..194462c841 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -282,7 +282,8 @@ static void test_auto_converge(char *name, MigrateCommo= n *args) /* To check remaining size after precopy */ migrate_set_capability(from, "pause-before-switchover", true); =20 - wait_for_serial("src_serial"); + /* Wait for the first serial output from the source */ + wait_for_serial(qtest_get_serial_path(from)); =20 migrate_incoming_qmp(to, uri, NULL, "{}"); migrate_qmp(from, to, uri, NULL, "{}"); @@ -317,7 +318,7 @@ static void test_auto_converge(char *name, MigrateCommo= n *args) =20 qtest_qmp_eventwait(to, "RESUME"); =20 - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(to)); wait_for_migration_complete(from); =20 migrate_end(from, to, true); @@ -436,7 +437,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args= , bool postcopy_ram) migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); =20 /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); =20 migrate_qmp(from, to, NULL, NULL, "{}"); =20 @@ -486,7 +487,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args= , bool postcopy_ram) wait_for_stop(from, get_src()); qtest_qmp_eventwait(to2, "RESUME"); =20 - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(to2)); wait_for_migration_complete(from); migrate_end(from, to2, true); } @@ -510,7 +511,7 @@ static void test_cancel_src_after_failed(QTestState *fr= om, QTestState *to, * failed state during migrate_qmp(). */ =20 - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); migrate_ensure_converge(from); =20 migrate_qmp(from, to, uri, NULL, "{}"); @@ -535,7 +536,7 @@ static void test_cancel_src_after_cancelled(QTestState = *from, QTestState *to, { migrate_incoming_qmp(to, uri, NULL, "{}"); =20 - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); migrate_ensure_converge(from); =20 migrate_qmp(from, to, uri, NULL, "{}"); @@ -560,7 +561,7 @@ static void test_cancel_src_after_complete(QTestState *= from, QTestState *to, { migrate_incoming_qmp(to, uri, NULL, "{}"); =20 - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); migrate_ensure_converge(from); =20 migrate_qmp(from, to, uri, NULL, "{}"); @@ -586,7 +587,7 @@ static void test_cancel_src_after_none(QTestState *from= , QTestState *to, */ migrate_cancel(to); =20 - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); migrate_cancel(from); =20 migrate_incoming_qmp(to, uri, NULL, "{}"); @@ -610,7 +611,7 @@ static void test_cancel_src_pre_switchover(QTestState *= from, QTestState *to, =20 migrate_incoming_qmp(to, uri, NULL, "{}"); =20 - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); migrate_ensure_converge(from); =20 migrate_qmp(from, to, uri, NULL, "{}"); @@ -831,7 +832,10 @@ static void test_vcpu_dirty_limit(char *name, MigrateC= ommon *args) vm =3D dirtylimit_start_vm(); =20 /* Wait for the first serial output from the vm*/ - wait_for_serial("vm_serial"); + { + g_autofree char *vm_serial =3D g_strdup_printf("%s/vm_serial", tmp= fs); + wait_for_serial(vm_serial); + } =20 /* Do dirtyrate measurement with calc time equals 1s */ calc_dirty_rate(vm, 1); @@ -924,7 +928,7 @@ static void migrate_dirty_limit_wait_showup(QTestState = *from, migrate_set_capability(from, "pause-before-switchover", true); =20 /* Wait for the serial output from the source */ - wait_for_serial("src_serial"); + wait_for_serial(qtest_get_serial_path(from)); } =20 /* @@ -1062,7 +1066,7 @@ static void test_dirty_limit(char *name, MigrateCommo= n *args) =20 qtest_qmp_eventwait(to, "RESUME"); =20 - wait_for_serial("dest_serial"); + wait_for_serial(qtest_get_serial_path(to)); wait_for_migration_complete(from); =20 migrate_end(from, to, true); --=20 2.50.1 (Apple Git-155) From nobody Sun Jul 26 10:07:05 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1783602086; cv=none; d=zohomail.com; s=zohoarc; b=XLUK81zNthUFBoLrDm06lka42EoxCrQ49xFlYtP9OV178Gligc5/j1k/IcWpXerP/KyL5uNq23oW4GWMb7x02XYKbXXxgIXxEvUcpSPRo+ivAcBC2SGuCpiCRXUjoEMHEwe/ry4gfwp22m3WjHdAenoVHkFGdMeb2b3lAWdjVDc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783602086; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ZaEIfqybV7I+19pe9ex1wILGmf1tN0Ou6N7PZUVaFys=; b=UoCMh1lQZJfpQ+DkAlJIvIaShhYa/4lvrlWO0m3BKzTyGxdZi7BwjeGMYlGuqhWuBXbiVwyLqPDNWmhP8NHQxXttuveLRII43wh5a/9w7++D+4qYsuR59tCPLhSP/SCTdk+4QMdhbD0qFQGnP3fiaUL9gFprKH2weMWLuuurBBo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1783602086048104.03140570054677; Thu, 9 Jul 2026 06:01:26 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1whoNB-0001gK-Mj; Thu, 09 Jul 2026 09:01:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1whoN5-0001dI-6C for qemu-devel@nongnu.org; Thu, 09 Jul 2026 09:00:56 -0400 Received: from mail-pg1-x52e.google.com ([2607:f8b0:4864:20::52e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1whoN2-00006u-K5 for qemu-devel@nongnu.org; Thu, 09 Jul 2026 09:00:54 -0400 Received: by mail-pg1-x52e.google.com with SMTP id 41be03b00d2f7-ca80d708489so548942a12.1 for ; Thu, 09 Jul 2026 06:00:52 -0700 (PDT) Received: from C02G720XMD6P.sg.corp.seagroup.com ([111.223.92.222]) by smtp.googlemail.com with ESMTPSA id 5a478bee46e88-31174ac14f2sm32908611eec.27.2026.07.09.06.00.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Jul 2026 06:00:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783602051; x=1784206851; darn=nongnu.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=ZaEIfqybV7I+19pe9ex1wILGmf1tN0Ou6N7PZUVaFys=; b=X0fNRs+lQwO1DVp2lDS3xUkBEgrzl09J+el6aFUcWWakbpsbxyYtKW6ovFx9WiK0/7 pYt+7fFLj1Hsi1ho/66utcJwxU4WziRSAz1aKemNJ7HGsoMiPK5WvR0HhAlOG5uiqg5A syOm6wTy8Bw6GWCTKybYXnt9fm83o6WNfdWWzm5duPT54vH1nrNHHlwiYwMiRJTCA5O1 YvthAOZiNIn7BSZS5TRqLXYam4cBEfknYEgVmBWCry3oTPHHpOZZotmRkafAyM5FFWBz xx4n9Fdmjl2uHChRcliBDbEKtdHvDKDLcHNZ0Htit9lYkGI9H/K2tdyBKSvFJdaL1sOr jzVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783602051; x=1784206851; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ZaEIfqybV7I+19pe9ex1wILGmf1tN0Ou6N7PZUVaFys=; b=Un/LFN31TZMWBbcnT7/UKGhWEMai+obxH583iMw1rqyji23t9tLio5o5j0Y2+EIP21 DZFnviIIj+4SuB0UNX5up+z3N2n5sLNJREmKP6f/FQBveYopcys6uvRABQPdTFeSZ7qF hF5zG71kk5f6ytWdKE2fpBDbcG4xehhcxNabbkqmnZVbakz5a/n2AnD9NAH1Xg/ImXf9 5zLZVbQgWz9NBivVmqLazcxFx89PQX+znslGUvbu92MCUCRxW2ErEJpBj7HOt/L7eHsJ IKdRKxmevabl0Mla4i93PnCiAd3pjV3s0D4L9qV4Xjstn6ZpZZDVKP8ewkm/K5SEzkn3 Bicw== X-Forwarded-Encrypted: i=1; AHgh+RrIQmH/6Bu00HVW9iRLirq6UVYlZbY3o5tjKfwLoFLOQuos7ihxJSpIJPR9OxrLX9fjlq3ShsYwrkPS@nongnu.org X-Gm-Message-State: AOJu0YzC6zoidff9NwnHeiZ2BzQKGeHYguJc1u9aaYf0tmmOlicrpsgr 3xgHNnVOgL63VRjQNZMMsdhaYe/4eXa+b0jBhsfMXtu4mQA5VCE9wklZ X-Gm-Gg: AfdE7cmjcxhW3rhyJor8HlCz5AmtB0hQiIpk2dNC3cWWpRTHHNDQfWdROCaxoCePLjS zu37EByaSga7/fo+kKJo9hCmUCK2yhTtTYLMt/55vVY6vqP2dU4LZxGtI72stzRtKWEnTgrkX/i HyTrK1voGAoot3pg+RslOaC/fU4pwegp9DMXpORow4cMgp7IbPfKa5IXK0SNDYDCNjHlgcXc9NM 8NyEySRJI1BH1BuDEpblt0vFjWQR3rvZk+HRADFnd0oZHe1sbfmEkJNLX/UpCuF+miYy6pGSAwO ctXwgIDLyYWWIzr8GFALE9hzC9beln+xkVpLXKS20Ylo38tqOUorHCr5Kk393f5hGvLTUOJm4Of EICvjyW2rDq66nYJR91dUfe8EURUp07YSN6TELK0K3MMbyQxXyoj1YxHnXx4+e5zAZPdJAzbwbt YOKtWaFxv8TA6hRldusLEg4aL1W5Oab5CBTShmobCwbULUhwqndXGhPoFT X-Received: by 2002:a05:6a20:d81a:b0:3bf:a8fa:a7b1 with SMTP id adf61e73a8af0-3c0d6c6f129mr3623269637.37.1783602050476; Thu, 09 Jul 2026 06:00:50 -0700 (PDT) From: phind.uet@gmail.com To: Peter Xu , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Cc: Nguyen Dinh Phi , qemu-devel@nongnu.org Subject: [PATCH 3/3] tests/migration: Add chain (A to B to C) precopy migration tests Date: Thu, 9 Jul 2026 21:00:27 +0800 Message-ID: <20260709130032.58667-4-phind.uet@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260709130032.58667-1-phind.uet@gmail.com> References: <20260709130032.58667-1-phind.uet@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::52e; envelope-from=phind.uet@gmail.com; helo=mail-pg1-x52e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1783602087913158500 From: Nguyen Dinh Phi Extract migrate_precopy_hop() from the SUCCESS path of test_precopy_common() to wrap the per-hop migration sequence of a succesfull migration. test_precopy_common() delegates its success path to this helper; failure paths are handled directly. Introduce test_precopy_chain(), a helper that drives two consecutive migration hops on already-running processes: first A=E2=86=92B, then B=E2= =86=92C, both hops are expected to be success. Add two test cases exercising the new helper: - /migration/precopy/tcp/plain/chain - /migration/multifd/tcp/channels/plain/chain Signed-off-by: Nguyen Dinh Phi --- tests/qtest/migration/framework.c | 195 +++++++++++++++++--------- tests/qtest/migration/framework.h | 1 + tests/qtest/migration/precopy-tests.c | 23 +++ 3 files changed, 153 insertions(+), 66 deletions(-) diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/fram= ework.c index a7dffeb82c..b4218b2f23 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -883,28 +883,25 @@ void test_postcopy_recovery_common(MigrateCommon *arg= s, migrate_postcopy_complete(from, to, hook_data, args); } =20 -int test_precopy_common(MigrateCommon *args) +/* + * Perform one precopy migration hop on an already-running (from, to) pair. + * Both processes must have migrate_setup_instance() called before this + * function. + * Always expects the hop to succeed. + * + */ +static void migrate_precopy_hop(QTestState *from, QTestState *to, + const char *listen_uri, + const char *connect_uri, + MigrateCommon *args) { - QTestState *from, *to; - void *data_hook =3D NULL; QObject *channels =3D NULL; - const char *listen_uri =3D args->uri ?: "tcp:127.0.0.1:0"; - - if (migrate_start(&from, &to, &args->start)) { - return -1; - } - - if (args->start_hook) { - data_hook =3D args->start_hook(from, to); - } + int iters; =20 migrate_incoming_qmp(to, listen_uri, NULL, "{}"); =20 - /* Wait for the first serial output from the source */ - if (args->result =3D=3D MIG_TEST_SUCCEED) { - wait_for_serial(qtest_get_serial_path(from)); - wait_for_suspend(from, &src_state); - } + wait_for_serial(qtest_get_serial_path(from)); + wait_for_suspend(from, &src_state); =20 if (args->live) { migrate_ensure_non_converge(from); @@ -913,76 +910,104 @@ int test_precopy_common(MigrateCommon *args) /* * Testing non-live migration, we allow it to run at * full speed to ensure short test case duration. - * For tests expected to fail, we don't need to - * change anything. */ - if (args->result =3D=3D MIG_TEST_SUCCEED) { - qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); - wait_for_stop(from, &src_state); - migrate_ensure_converge(from); - } + qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); + wait_for_stop(from, &src_state); + migrate_ensure_converge(from); } =20 if (args->connect_channels) { channels =3D qobject_from_json(args->connect_channels, &error_abor= t); } =20 - if (args->result =3D=3D MIG_TEST_QMP_ERROR) { - migrate_qmp_fail(from, args->uri, channels, "{}"); - goto finish; - } + migrate_qmp(from, to, connect_uri, channels, "{}"); =20 - migrate_qmp(from, to, args->uri, channels, "{}"); + if (args->live) { + /* + * For initial iteration(s) we must do a full pass, + * but for the final iteration, we need only wait + * for some dirty mem before switching to converge. + */ + /* + * Avoid changing the args->iterations by using a local copy + */ + iters =3D args->iterations; + while (iters > 1) { + wait_for_migration_pass(from, &src_state); + iters--; + } + migrate_wait_for_dirty_mem(from, to); + + migrate_ensure_converge(from); + + /* + * We do this first, as it has a timeout to stop us + * hanging forever if migration didn't converge + */ + wait_for_migration_complete(from); + + wait_for_stop(from, &src_state); =20 - if (args->result !=3D MIG_TEST_SUCCEED) { - bool allow_active =3D args->result =3D=3D MIG_TEST_FAIL; - wait_for_migration_fail(from, allow_active); } else { - if (args->live) { - /* - * For initial iteration(s) we must do a full pass, - * but for the final iteration, we need only wait - * for some dirty mem before switching to converge - */ - while (args->iterations > 1) { - wait_for_migration_pass(from, &src_state); - args->iterations--; - } - migrate_wait_for_dirty_mem(from, to); + wait_for_migration_complete(from); + /* + * Must wait for dst to finish reading all incoming + * data on the socket before issuing 'cont' otherwise + * it'll be ignored + */ + wait_for_migration_complete(to); =20 - migrate_ensure_converge(from); + qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}"); + } =20 - /* - * We do this first, as it has a timeout to stop us - * hanging forever if migration didn't converge - */ - wait_for_migration_complete(from); + wait_for_resume(to, &dst_state); + + if (args->start.suspend_me) { + /* wakeup succeeds only if guest is suspended */ + qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}"); + } =20 - wait_for_stop(from, &src_state); + wait_for_serial(qtest_get_serial_path(to)); +} =20 - } else { - wait_for_migration_complete(from); - /* - * Must wait for dst to finish reading all incoming - * data on the socket before issuing 'cont' otherwise - * it'll be ignored - */ - wait_for_migration_complete(to); +int test_precopy_common(MigrateCommon *args) +{ + QTestState *from, *to; + void *data_hook =3D NULL; + const char *listen_uri =3D args->uri ?: "tcp:127.0.0.1:0"; =20 - qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}"); - } + if (migrate_start(&from, &to, &args->start)) { + return -1; + } + + if (args->start_hook) { + data_hook =3D args->start_hook(from, to); + } =20 - wait_for_resume(to, &dst_state); + if (args->result =3D=3D MIG_TEST_SUCCEED) { + migrate_precopy_hop(from, to, listen_uri, args->uri, args); + } else { + QObject *channels =3D NULL; + + migrate_incoming_qmp(to, listen_uri, NULL, "{}"); + + if (args->live) { + migrate_ensure_non_converge(from); + migrate_prepare_for_dirty_mem(from); + } =20 - if (args->start.suspend_me) { - /* wakeup succeeds only if guest is suspended */ - qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}"); + if (args->connect_channels) { + channels =3D qobject_from_json(args->connect_channels, &error_= abort); } =20 - wait_for_serial(qtest_get_serial_path(to)); + if (args->result =3D=3D MIG_TEST_QMP_ERROR) { + migrate_qmp_fail(from, args->uri, channels, "{}"); + } else { + migrate_qmp(from, to, args->uri, channels, "{}"); + wait_for_migration_fail(from, args->result =3D=3D MIG_TEST_FAI= L); + } } =20 -finish: if (args->end_hook) { args->end_hook(from, to, data_hook); } @@ -1000,6 +1025,44 @@ void test_precopy_unix_common(MigrateCommon *args) test_precopy_common(args); } =20 +int test_precopy_chain(MigrateCommon *args) +{ + QTestState *from, *to, *to2; + const char *listen_uri =3D args->uri ?: "tcp:127.0.0.1:0"; + + /* + * Hook callbacks operate on a fixed (from, to) pair; they do not + * compose across multiple migration legs. + */ + g_assert(!args->start_hook && !args->end_hook); + + if (migrate_start(&from, &to, &args->start)) { + return -1; + } + + /* First leg: A -> B */ + migrate_precopy_hop(from, to, listen_uri, args->uri, args); + + /* + * Second leg: B -> C. + */ + qtest_quit(from); + migrate_setup_instance(to, &src_state, &args->start); + + to2 =3D migrate_launch_dest("dest_serial2", &args->start); + if (!to2) { + qtest_quit(to); + return -1; + } + migrate_setup_instance(to2, &dst_state, &args->start); + + migrate_precopy_hop(to, to2, listen_uri, NULL, args); + + migrate_end(to, to2, true); + + return 0; +} + static void file_dirty_offset_region(void) { g_autofree char *path =3D g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FI= LENAME); diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/fram= ework.h index f6936eb8c6..ca5289329a 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -254,6 +254,7 @@ void test_postcopy_common(MigrateCommon *args); void test_postcopy_recovery_common(MigrateCommon *args, PostcopyRecoveryFailStage fail_stage); int test_precopy_common(MigrateCommon *args); +int test_precopy_chain(MigrateCommon *args); void test_precopy_unix_common(MigrateCommon *args); void test_file_common(MigrateCommon *args, bool stop_src); =20 diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/= precopy-tests.c index 194462c841..fccff76ef6 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -182,6 +182,11 @@ static void test_precopy_tcp_plain(char *name, Migrate= Common *args) test_precopy_common(args); } =20 +static void test_precopy_tcp_plain_chain(char *name, MigrateCommon *args) +{ + test_precopy_chain(args); +} + static void test_precopy_tcp_switchover_ack(char *name, MigrateCommon *arg= s) { /* @@ -398,6 +403,20 @@ static void test_multifd_tcp_channels_none(char *name,= MigrateCommon *args) test_precopy_common(args); } =20 +static void test_multifd_tcp_channels_chain(char *name, MigrateCommon *arg= s) +{ + args->live =3D true; + args->connect_channels =3D ("[ { 'channel-type': 'main'," + " 'addr': { 'transport': 'socket'," + " 'type': 'inet'," + " 'host': '127.0.0.1'," + " 'port': '0' } } ]"); + + args->start.caps[MIGRATION_CAPABILITY_MULTIFD] =3D true; + + test_precopy_chain(args); +} + /* * This test does: * source target @@ -1112,6 +1131,8 @@ void migration_test_add_precopy(MigrationTestEnv *env) return; } =20 + migration_test_add("/migration/precopy/tcp/plain/chain", + test_precopy_tcp_plain_chain); migration_test_add("/migration/precopy/tcp/plain/switchover-ack", test_precopy_tcp_switchover_ack); =20 @@ -1133,6 +1154,8 @@ void migration_test_add_precopy(MigrationTestEnv *env) } migration_test_add("/migration/multifd/tcp/channels/plain/none", test_multifd_tcp_channels_none); + migration_test_add("/migration/multifd/tcp/channels/plain/chain", + test_multifd_tcp_channels_chain); migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy", test_multifd_tcp_zero_page_legacy); migration_test_add("/migration/multifd/tcp/plain/zero-page/none", --=20 2.50.1 (Apple Git-155)