From nobody Sun May 19 07:31:39 2024 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=suse.de ARC-Seal: i=1; a=rsa-sha256; t=1696342890; cv=none; d=zohomail.com; s=zohoarc; b=jWJ7Iw4Zg5Z6RUnQCd+6nAPZAJAmx7zYkrZBJ5Xyt+T0I0+ABT/2Hs5GbQzGFP27ZxskaikCowus+XDTdH6/y0uXqQl2WdnEfaqWVugXmKIZmcEl00Ezq/CinD/VvgRIWCyo1cOhIGmWAR7z4Jz5aV429TSA7C+5Y2rn+k5Y4FE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1696342890; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=JBPSiPSrOpI2yCVGuVGu4ZJOaoUnS+0et1HCCtrJUNI=; b=OqX4v1P7fvam+hnO6TZCkriezX94/wC6zzwBLiF8EAx+dzceD9VdYsllj4CjMaWL1cLYIlOsPhfSt10gcBf0FoTmHubyUsKERevuN97BNk4Abe3Q64Gy5QBUaDi3O9HNZo9JA82kZHLHaEjpghD79DzgFJfTIiEJfR2fHmIwWbk= 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 lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1696342890423321.0805309461209; Tue, 3 Oct 2023 07:21:30 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qngG7-00087S-Re; Tue, 03 Oct 2023 10:20:24 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qngG2-000853-Fh for qemu-devel@nongnu.org; Tue, 03 Oct 2023 10:20:19 -0400 Received: from smtp-out2.suse.de ([2001:67c:2178:6::1d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qngFz-0005MZ-D3 for qemu-devel@nongnu.org; Tue, 03 Oct 2023 10:20:17 -0400 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 5C6B31F894; Tue, 3 Oct 2023 14:20:12 +0000 (UTC) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 38E19139F9; Tue, 3 Oct 2023 14:20:10 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id SAuIARojHGWuUAAAMHmgww (envelope-from ); Tue, 03 Oct 2023 14:20:10 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1696342812; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JBPSiPSrOpI2yCVGuVGu4ZJOaoUnS+0et1HCCtrJUNI=; b=M3ScFDNvcKZlGviB9W5+G7nZA4V6C1t2KyDfH+TsVJLwr6B1hs6VexzpcuHdDIkgIxR0rG ITOv/t4QNqfgsmHE55JPsi9ssoiJhS6t1EIPp2HcMe07j4eY9dXt+r1cyJUpfLlyE5/cFN T3OFKH8hepL468VhR5aooOoI2kSwsQ4= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1696342812; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JBPSiPSrOpI2yCVGuVGu4ZJOaoUnS+0et1HCCtrJUNI=; b=fbaLNuSzk/Ptz8w4LW2bzyUEkY+OARHfZpk0FmXuRwDA2QdsHmxTtfhwW0VOR5rAfalddE /aQoDU+2voH3QZAg== From: Fabiano Rosas To: qemu-devel@nongnu.org Cc: Juan Quintela , Peter Xu , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , Laurent Vivier , Paolo Bonzini , Leonardo Bras Subject: [RFC PATCH 1/1] qtest/migration: Support more than one QEMU binary Date: Tue, 3 Oct 2023 11:19:32 -0300 Message-Id: <20231003141932.2367-2-farosas@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20231003141932.2367-1-farosas@suse.de> References: <20231003141932.2367-1-farosas@suse.de> 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=lists.gnu.org; Received-SPF: pass client-ip=2001:67c:2178:6::1d; envelope-from=farosas@suse.de; helo=smtp-out2.suse.de X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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, RCVD_IN_DNSWL_MED=-2.3, 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: 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 @suse.de) X-ZM-MESSAGEID: 1696342891082100005 Content-Type: text/plain; charset="utf-8" We have strict rules around migration compatibility between different QEMU versions but not a single test that validates the migration state between different binaries. Add some infrastructure to allow running the migration tests with two different QEMU binaries as migration source and destination. The code now recognizes two new environment variables QTEST_QEMU_SRC and QTEST_QEMU_DST. Only one of the two is expected to be used along with the existing QTEST_QEMU_BINARY, which will automatically be used for the other side of migration. Usage: QTEST_QEMU_DST=3D./build-8.2.0/qemu-system-x86_64 \ QTEST_QEMU_BINARY=3D../build-8.1.0/qemu-system-x86_64 \ ./tests/qtest/migration-test This code also works for when debugging with GDB to pass the same binary, but different GDB options for src and dst. Signed-off-by: Fabiano Rosas --- tests/qtest/migration-helpers.c | 168 ++++++++++++++++++++++++++++++++ tests/qtest/migration-helpers.h | 3 + tests/qtest/migration-test.c | 52 ++++++++-- 3 files changed, 216 insertions(+), 7 deletions(-) diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helper= s.c index be00c52d00..e84360c3b3 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -12,6 +12,8 @@ =20 #include "qemu/osdep.h" #include "qapi/qmp/qjson.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qstring.h" =20 #include "migration-helpers.h" =20 @@ -180,3 +182,169 @@ void wait_for_migration_fail(QTestState *from, bool a= llow_active) g_assert(qdict_get_bool(rsp_return, "running")); qobject_unref(rsp_return); } + +static char *query_pkg_version(QTestState *who) +{ + QDict *rsp; + char *pkg; + + rsp =3D qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-version= ' }"); + g_assert(rsp); + + pkg =3D g_strdup(qdict_get_str(rsp, "package")); + qobject_unref(rsp); + + return pkg; +} + +static QList *query_machines(void) +{ + QDict *response; + QList *list; + QTestState *qts; + + qts =3D qtest_init("-machine none"); + response =3D qtest_qmp(qts, "{ 'execute': 'query-machines' }"); + g_assert(response); + list =3D qdict_get_qlist(response, "return"); + g_assert(list); + + qtest_quit(qts); + return list; +} + +static char *get_default_machine(QList *list) +{ + QDict *info; + QListEntry *entry; + QString *qstr; + char *name =3D NULL; + + QLIST_FOREACH_ENTRY(list, entry) { + info =3D qobject_to(QDict, qlist_entry_obj(entry)); + g_assert(info); + + if (qdict_get(info, "is-default")) { + qstr =3D qobject_to(QString, qdict_get(info, "name")); + g_assert(qstr); + name =3D g_strdup(qstring_get_str(qstr)); + break; + } + } + + g_assert(name); + return name; +} + +static bool search_default_machine(QList *list, const char *theirs) +{ + QDict *info; + QListEntry *entry; + QString *qstr; + + if (!theirs) { + return false; + } + + QLIST_FOREACH_ENTRY(list, entry) { + info =3D qobject_to(QDict, qlist_entry_obj(entry)); + g_assert(info); + + qstr =3D qobject_to(QString, qdict_get(info, "name")); + g_assert(qstr); + + if (g_str_equal(qstring_get_str(qstr), theirs)) { + return true; + } + } + return false; +} + +/* + * We need to ensure that both QEMU instances set via the QTEST_QEMU_* + * vars will use the same machine type. Use a custom query_machines + * function because the generic one in libqtest has a cache that would + * return the same machines for both binaries. + */ +char *find_common_machine_type(const char *bin) +{ + QList *m1, *m2; + g_autofree char *def1 =3D NULL; + g_autofree char *def2 =3D NULL; + const char *qemu_bin =3D getenv("QTEST_QEMU_BINARY"); + + m1 =3D query_machines(); + + g_setenv("QTEST_QEMU_BINARY", bin, true); + m2 =3D query_machines(); + g_setenv("QTEST_QEMU_BINARY", qemu_bin, true); + + def1 =3D get_default_machine(m1); + def2 =3D get_default_machine(m2); + + if (g_str_equal(def1, def2)) { + /* either can be used */ + return g_strdup(def1); + } + + if (search_default_machine(m1, def2)) { + return g_strdup(def2); + } + + if (search_default_machine(m2, def1)) { + return g_strdup(def1); + } + + g_assert_not_reached(); +} + +/* + * Init a guest for migration tests using an alternate QEMU binary for + * either the source or destination, depending on @var. The other + * binary should be set as usual via QTEST_QEMU_BINARY. + * + * Expected values: + * QTEST_QEMU_SRC + * QTEST_QEMU_DST + * + * Warning: The generic parts of qtest could be using + * QTEST_QEMU_BINARY to query for properties before we reach the + * migration code. If the alternate binary is too dissimilar that + * could cause issues. + */ +static QTestState *init_vm(const char *extra_args, const char *var) +{ + const char *alt_bin =3D getenv(var); + const char *qemu_bin =3D getenv("QTEST_QEMU_BINARY"); + g_autofree char *pkg =3D NULL; + bool src =3D !!strstr(var, "SRC"); + QTestState *qts; + + if (alt_bin) { + g_setenv("QTEST_QEMU_BINARY", alt_bin, true); + } + + qts =3D qtest_init(extra_args); + pkg =3D query_pkg_version(qts); + + g_test_message("Using %s (%s) as migration %s", + alt_bin ? alt_bin : qemu_bin, + pkg, + src ? "source" : "destination"); + + if (alt_bin) { + /* restore the original */ + g_setenv("QTEST_QEMU_BINARY", qemu_bin, true); + } + return qts; +} + +QTestState *mig_init_src(const char *extra_args) +{ + return init_vm(extra_args, "QTEST_QEMU_SRC"); +} + +QTestState *mig_init_dst(const char *extra_args) +{ + return init_vm(extra_args, "QTEST_QEMU_DST"); +} diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helper= s.h index 009e250e90..aabdbc7507 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -33,4 +33,7 @@ void wait_for_migration_complete(QTestState *who); =20 void wait_for_migration_fail(QTestState *from, bool allow_active); =20 +QTestState *mig_init_src(const char *extra_args); +QTestState *mig_init_dst(const char *extra_args); +char *find_common_machine_type(const char *bin); #endif /* MIGRATION_HELPERS_H */ diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 1b43df5ca7..60f0b15417 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -45,6 +45,7 @@ unsigned end_address; static bool uffd_feature_thread_id; static bool got_src_stop; static bool got_dst_resume; +static char *common_machine_type; =20 /* * An initial 3 MB offset is used as that corresponds @@ -712,6 +713,7 @@ static int test_migrate_start(QTestState **from, QTestS= tate **to, g_autofree char *shmem_path =3D NULL; const char *arch =3D qtest_get_arch(); const char *memory_size; + g_autofree char *machine =3D NULL; =20 if (args->use_shmem) { if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) { @@ -723,18 +725,30 @@ static int test_migrate_start(QTestState **from, QTes= tState **to, got_src_stop =3D false; got_dst_resume =3D false; bootpath =3D g_strdup_printf("%s/bootsect", tmpfs); + if (strcmp(arch, "i386") =3D=3D 0 || strcmp(arch, "x86_64") =3D=3D 0) { /* the assembled x86 boot sector should be exactly one sector larg= e */ assert(sizeof(x86_bootsect) =3D=3D 512); init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect)); memory_size =3D "150M"; - arch_opts =3D g_strdup_printf("-drive file=3D%s,format=3Draw", boo= tpath); + + if (common_machine_type) { + machine =3D g_strdup_printf("-machine %s", common_machine_type= ); + } + + arch_opts =3D g_strdup_printf("%s -drive file=3D%s,format=3Draw", + machine, bootpath); start_address =3D X86_TEST_MEM_START; end_address =3D X86_TEST_MEM_END; } else if (g_str_equal(arch, "s390x")) { init_bootfile(bootpath, s390x_elf, sizeof(s390x_elf)); memory_size =3D "128M"; - arch_opts =3D g_strdup_printf("-bios %s", bootpath); + + if (common_machine_type) { + machine =3D g_strdup_printf("-machine %s", common_machine_type= ); + } + + arch_opts =3D g_strdup_printf("%s -bios %s", machine, bootpath); start_address =3D S390_TEST_MEM_START; end_address =3D S390_TEST_MEM_END; } else if (strcmp(arch, "ppc64") =3D=3D 0) { @@ -745,12 +759,24 @@ static int test_migrate_start(QTestState **from, QTes= tState **to, "'nvramrc=3Dhex .\" _\" begin %x %x " "do i c@ 1 + i c! 1000 +loop .\" B\"= 0 " "until'", end_address, start_address= ); - arch_opts =3D g_strdup("-nodefaults -machine vsmt=3D8"); + + if (common_machine_type) { + machine =3D g_strdup_printf("%s,", common_machine_type); + } + + arch_opts =3D g_strdup_printf("-nodefaults -machine %svsmt=3D8", m= achine); } else if (strcmp(arch, "aarch64") =3D=3D 0) { init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel)); memory_size =3D "150M"; - arch_opts =3D g_strdup_printf("-machine virt,gic-version=3Dmax -cp= u max " - "-kernel %s", bootpath); + + if (common_machine_type) { + machine =3D g_strdup_printf("%s", common_machine_type); + } else { + machine =3D g_strdup("virt"); + } + + arch_opts =3D g_strdup_printf("-machine %s,gic-version=3Dmax -cpu = max " + "-kernel %s", machine, bootpath); start_address =3D ARM_TEST_MEM_START; end_address =3D ARM_TEST_MEM_END; =20 @@ -799,7 +825,7 @@ static int test_migrate_start(QTestState **from, QTestS= tate **to, args->opts_source ? args->opts_source : "= ", ignore_stderr); if (!args->only_target) { - *from =3D qtest_init(cmd_source); + *from =3D mig_init_src(cmd_source); qtest_qmp_set_event_callback(*from, migrate_watch_for_stop, &got_src_stop); @@ -819,7 +845,7 @@ static int test_migrate_start(QTestState **from, QTestS= tate **to, shmem_opts, args->opts_target ? args->opts_target : "= ", ignore_stderr); - *to =3D qtest_init(cmd_target); + *to =3D mig_init_dst(cmd_target); qtest_qmp_set_event_callback(*to, migrate_watch_for_resume, &got_dst_resume); @@ -2769,6 +2795,8 @@ int main(int argc, char **argv) const char *arch; g_autoptr(GError) err =3D NULL; int ret; + const char *qemu_src =3D getenv("QTEST_QEMU_SRC"); + const char *qemu_dst =3D getenv("QTEST_QEMU_DST"); =20 g_test_init(&argc, &argv, NULL); =20 @@ -2780,6 +2808,16 @@ int main(int argc, char **argv) return 0; } =20 + if (qemu_src || qemu_dst) { + if (qemu_src && qemu_dst) { + g_test_message("Only one of QTEST_QEMU_SRC, QTEST_QEMU_DST is = allowed."); + exit(1); + } + common_machine_type =3D find_common_machine_type(qemu_src ? qemu_s= rc : qemu_dst); + g_test_message("Using two different QEMU binaries. Common machine = type: %s", + common_machine_type); + } + has_uffd =3D ufd_version_check(); arch =3D qtest_get_arch(); =20 --=20 2.35.3