From patchwork Mon Oct 16 10:06:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juan Quintela X-Patchwork-Id: 13422878 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2F5F3CDB482 for ; Mon, 16 Oct 2023 10:09:12 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qsKWT-0002P0-1T; Mon, 16 Oct 2023 06:08:29 -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 1qsKW7-0001uU-Rf for qemu-devel@nongnu.org; Mon, 16 Oct 2023 06:08:07 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qsKW0-0007WE-Im for qemu-devel@nongnu.org; Mon, 16 Oct 2023 06:08:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1697450878; h=from:from:reply-to:subject:subject: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=OFlgGpLEpvch6kF0rrWWynWCL0mt1MQwnQtfZn7XwU4=; b=aj3cA7fnoBXKsnefCPyKC3BtiZl4YAhBDHzcLQprevZi6ovNS/H5SEt40mgXApkFO97bb3 A3zqQutpAstf/9cLgEvXf7UCAeAYI1E7M39Q+/0Qe5lRkrdJ6doyHaE+b7kgBKjRXMDr9x +7L82xFuZPHA5ZYYmTx6HOTQGpwK36w= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-455-20410SwqMQ6W7tvhWSp9Tw-1; Mon, 16 Oct 2023 06:07:44 -0400 X-MC-Unique: 20410SwqMQ6W7tvhWSp9Tw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6FD513826D42; Mon, 16 Oct 2023 10:07:44 +0000 (UTC) Received: from secure.mitica (unknown [10.39.194.127]) by smtp.corp.redhat.com (Postfix) with ESMTP id DFA6F63F21; Mon, 16 Oct 2023 10:07:41 +0000 (UTC) From: Juan Quintela To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, Paolo Bonzini , Vladimir Sementsov-Ogievskiy , Fam Zheng , Cleber Rosa , Eric Blake , Li Zhijian , Peter Xu , Markus Armbruster , John Snow , Stefan Hajnoczi , Juan Quintela , Leonardo Bras , Laurent Vivier , Fabiano Rosas , Thomas Huth Subject: [PULL 11/38] tests/qtest: migration-test: Add tests for file-based migration Date: Mon, 16 Oct 2023 12:06:39 +0200 Message-ID: <20231016100706.2551-12-quintela@redhat.com> In-Reply-To: <20231016100706.2551-1-quintela@redhat.com> References: <20231016100706.2551-1-quintela@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 Received-SPF: pass client-ip=170.10.129.124; envelope-from=quintela@redhat.com; helo=us-smtp-delivery-124.mimecast.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, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Fabiano Rosas Add basic tests for file-based migration. Note that we cannot use test_precopy_common because that routine expects it to be possible to run the migration live. With the file transport there is no live migration because we must wait for the source to finish writing the migration data to the file before the destination can start reading. Add a new migration function specifically to handle the file migration. Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Fabiano Rosas Signed-off-by: Juan Quintela Message-ID: <20230712190742.22294-7-farosas@suse.de> --- tests/qtest/migration-test.c | 147 +++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index cef5081f8c..da02b6d692 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -68,6 +68,10 @@ static bool got_dst_resume; #define ANALYZE_SCRIPT "scripts/analyze-migration.py" +#define QEMU_VM_FILE_MAGIC 0x5145564d +#define FILE_TEST_FILENAME "migfile" +#define FILE_TEST_OFFSET 0x1000 + #if defined(__linux__) #include #include @@ -884,6 +888,7 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest) cleanup("migsocket"); cleanup("src_serial"); cleanup("dest_serial"); + cleanup(FILE_TEST_FILENAME); } #ifdef CONFIG_GNUTLS @@ -1667,6 +1672,70 @@ finish: test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED); } +static void test_file_common(MigrateCommon *args, bool stop_src) +{ + QTestState *from, *to; + void *data_hook = NULL; + g_autofree char *connect_uri = g_strdup(args->connect_uri); + + if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) { + return; + } + + /* + * File migration is never live. We can keep the source VM running + * during migration, but the destination will not be running + * concurrently. + */ + g_assert_false(args->live); + + if (args->start_hook) { + data_hook = args->start_hook(from, to); + } + + migrate_ensure_converge(from); + wait_for_serial("src_serial"); + + if (stop_src) { + qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); + if (!got_src_stop) { + qtest_qmp_eventwait(from, "STOP"); + } + } + + if (args->result == MIG_TEST_QMP_ERROR) { + migrate_qmp_fail(from, connect_uri, "{}"); + goto finish; + } + + migrate_qmp(from, connect_uri, "{}"); + wait_for_migration_complete(from); + + /* + * We need to wait for the source to finish before starting the + * destination. + */ + migrate_incoming_qmp(to, connect_uri, "{}"); + wait_for_migration_complete(to); + + if (stop_src) { + qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}"); + } + + if (!got_dst_resume) { + qtest_qmp_eventwait(to, "RESUME"); + } + + wait_for_serial("dest_serial"); + +finish: + if (args->finish_hook) { + args->finish_hook(from, to, data_hook); + } + + test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED); +} + static void test_precopy_unix_plain(void) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); @@ -1862,6 +1931,76 @@ static void test_precopy_unix_compress_nowait(void) test_precopy_common(&args); } +static void test_precopy_file(void) +{ + g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, + FILE_TEST_FILENAME); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = "defer", + }; + + test_file_common(&args, true); +} + +static void file_offset_finish_hook(QTestState *from, QTestState *to, + void *opaque) +{ +#if defined(__linux__) + g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); + size_t size = FILE_TEST_OFFSET + sizeof(QEMU_VM_FILE_MAGIC); + uintptr_t *addr, *p; + int fd; + + fd = open(path, O_RDONLY); + g_assert(fd != -1); + addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + g_assert(addr != MAP_FAILED); + + /* + * Ensure the skipped offset contains zeros and the migration + * stream starts at the right place. + */ + p = addr; + while (p < addr + FILE_TEST_OFFSET / sizeof(uintptr_t)) { + g_assert(*p == 0); + p++; + } + g_assert_cmpint(cpu_to_be32(*p), ==, QEMU_VM_FILE_MAGIC); + + munmap(addr, size); + close(fd); +#endif +} + +static void test_precopy_file_offset(void) +{ + g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs, + FILE_TEST_FILENAME, + FILE_TEST_OFFSET); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = "defer", + .finish_hook = file_offset_finish_hook, + }; + + test_file_common(&args, false); +} + +static void test_precopy_file_offset_bad(void) +{ + /* using a value not supported by qemu_strtosz() */ + g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M", + tmpfs, FILE_TEST_FILENAME); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = "defer", + .result = MIG_TEST_QMP_ERROR, + }; + + test_file_common(&args, false); +} + static void test_precopy_tcp_plain(void) { MigrateCommon args = { @@ -2909,6 +3048,14 @@ int main(int argc, char **argv) qtest_add_func("/migration/precopy/unix/compress/nowait", test_precopy_unix_compress_nowait); } + + qtest_add_func("/migration/precopy/file", + test_precopy_file); + qtest_add_func("/migration/precopy/file/offset", + test_precopy_file_offset); + qtest_add_func("/migration/precopy/file/offset/bad", + test_precopy_file_offset_bad); + #ifdef CONFIG_GNUTLS qtest_add_func("/migration/precopy/unix/tls/psk", test_precopy_unix_tls_psk);