/* * QTest testcases for migration to file * * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates * based on the vhost-user-test.c that is: * Copyright (c) 2014 Virtual Open Systems Sarl. * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. * */ #include "qemu/osdep.h" #include "libqtest.h" #include "migration/framework.h" #include "migration/migration-qmp.h" #include "migration/migration-util.h" #include "qobject/qlist.h" static char *tmpfs; 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); } #ifndef _WIN32 static void fdset_add_fds(QTestState *qts, const char *file, int flags, int num_fds, bool direct_io) { for (int i = 0; i < num_fds; i++) { int fd; #ifdef O_DIRECT /* only secondary channels can use direct-io */ if (direct_io && i != 0) { flags |= O_DIRECT; } #endif fd = open(file, flags, 0660); assert(fd != -1); qtest_qmp_fds_assert_success(qts, &fd, 1, "{'execute': 'add-fd', " "'arguments': {'fdset-id': 1}}"); close(fd); } } static void *migrate_hook_start_file_offset_fdset(QTestState *from, QTestState *to) { g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); fdset_add_fds(from, file, O_WRONLY, 1, false); fdset_add_fds(to, file, O_RDONLY, 1, false); return NULL; } static void test_precopy_file_offset_fdset(void) { g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", FILE_TEST_OFFSET); MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", .start_hook = migrate_hook_start_file_offset_fdset, }; test_file_common(&args, false); } #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", }; 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_file_mapped_ram_live(void) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", .start = { .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, }, }; test_file_common(&args, false); } static void test_precopy_file_mapped_ram(void) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", .start = { .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, }, }; test_file_common(&args, true); } static void test_multifd_file_mapped_ram_live(void) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", .start = { .caps[MIGRATION_CAPABILITY_MULTIFD] = true, .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, }, }; test_file_common(&args, false); } static void test_multifd_file_mapped_ram(void) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", .start = { .caps[MIGRATION_CAPABILITY_MULTIFD] = true, .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, }, }; test_file_common(&args, true); } static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from, QTestState *to) { migrate_set_parameter_bool(from, "direct-io", true); migrate_set_parameter_bool(to, "direct-io", true); return NULL; } static void test_multifd_file_mapped_ram_dio(void) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_mapped_ram_dio, .start = { .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, .caps[MIGRATION_CAPABILITY_MULTIFD] = true, }, }; if (!probe_o_direct_support(tmpfs)) { g_test_skip("Filesystem does not support O_DIRECT"); return; } test_file_common(&args, true); } #ifndef _WIN32 static void migrate_hook_end_multifd_mapped_ram_fdset(QTestState *from, QTestState *to, void *opaque) { QDict *resp; QList *fdsets; /* * Remove the fdsets after migration, otherwise a second migration * would fail due fdset reuse. */ qtest_qmp_assert_success(from, "{'execute': 'remove-fd', " "'arguments': { 'fdset-id': 1}}"); /* * Make sure no fdsets are left after migration, otherwise a * second migration would fail due fdset reuse. */ resp = qtest_qmp(from, "{'execute': 'query-fdsets', " "'arguments': {}}"); g_assert(qdict_haskey(resp, "return")); fdsets = qdict_get_qlist(resp, "return"); g_assert(fdsets && qlist_empty(fdsets)); qobject_unref(resp); } static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from, QTestState *to) { g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); fdset_add_fds(from, file, O_WRONLY, 2, true); fdset_add_fds(to, file, O_RDONLY, 2, true); migrate_set_parameter_bool(from, "direct-io", true); migrate_set_parameter_bool(to, "direct-io", true); return NULL; } static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from, QTestState *to) { g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); fdset_add_fds(from, file, O_WRONLY, 2, false); fdset_add_fds(to, file, O_RDONLY, 2, false); return NULL; } static void test_multifd_file_mapped_ram_fdset(void) { g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", FILE_TEST_OFFSET); MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_mapped_ram_fdset, .end_hook = migrate_hook_end_multifd_mapped_ram_fdset, .start = { .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, .caps[MIGRATION_CAPABILITY_MULTIFD] = true, }, }; test_file_common(&args, true); } static void test_multifd_file_mapped_ram_fdset_dio(void) { g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", FILE_TEST_OFFSET); MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio, .end_hook = migrate_hook_end_multifd_mapped_ram_fdset, .start = { .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, .caps[MIGRATION_CAPABILITY_MULTIFD] = true, }, }; if (!probe_o_direct_support(tmpfs)) { g_test_skip("Filesystem does not support O_DIRECT"); return; } test_file_common(&args, true); } #endif /* !_WIN32 */ static void migration_test_add_file_smoke(MigrationTestEnv *env) { migration_test_add("/migration/precopy/file", test_precopy_file); migration_test_add("/migration/multifd/file/mapped-ram/dio", test_multifd_file_mapped_ram_dio); } void migration_test_add_file(MigrationTestEnv *env) { tmpfs = env->tmpfs; migration_test_add_file_smoke(env); if (!env->full_set) { return; } migration_test_add("/migration/precopy/file/offset", test_precopy_file_offset); #ifndef _WIN32 migration_test_add("/migration/precopy/file/offset/fdset", test_precopy_file_offset_fdset); #endif migration_test_add("/migration/precopy/file/offset/bad", test_precopy_file_offset_bad); migration_test_add("/migration/precopy/file/mapped-ram", test_precopy_file_mapped_ram); migration_test_add("/migration/precopy/file/mapped-ram/live", test_precopy_file_mapped_ram_live); migration_test_add("/migration/multifd/file/mapped-ram", test_multifd_file_mapped_ram); migration_test_add("/migration/multifd/file/mapped-ram/live", test_multifd_file_mapped_ram_live); #ifndef _WIN32 migration_test_add("/migration/multifd/file/mapped-ram/fdset", test_multifd_file_mapped_ram_fdset); migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio", test_multifd_file_mapped_ram_fdset_dio); #endif }