1 /* 2 * QTest testcases for migration to file 3 * 4 * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates 5 * based on the vhost-user-test.c that is: 6 * Copyright (c) 2014 Virtual Open Systems Sarl. 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 * See the COPYING file in the top-level directory. 10 * 11 */ 12 13 #include "qemu/osdep.h" 14 #include "libqtest.h" 15 #include "migration/framework.h" 16 #include "migration/migration-qmp.h" 17 #include "migration/migration-util.h" 18 #include "qobject/qlist.h" 19 20 21 static char *tmpfs; 22 23 static void test_precopy_file(void) 24 { 25 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 26 FILE_TEST_FILENAME); 27 MigrateCommon args = { 28 .connect_uri = uri, 29 .listen_uri = "defer", 30 }; 31 32 test_file_common(&args, true); 33 } 34 35 #ifndef _WIN32 36 static void fdset_add_fds(QTestState *qts, const char *file, int flags, 37 int num_fds, bool direct_io) 38 { 39 for (int i = 0; i < num_fds; i++) { 40 int fd; 41 42 #ifdef O_DIRECT 43 /* only secondary channels can use direct-io */ 44 if (direct_io && i != 0) { 45 flags |= O_DIRECT; 46 } 47 #endif 48 49 fd = open(file, flags, 0660); 50 assert(fd != -1); 51 52 qtest_qmp_fds_assert_success(qts, &fd, 1, "{'execute': 'add-fd', " 53 "'arguments': {'fdset-id': 1}}"); 54 close(fd); 55 } 56 } 57 58 static void *migrate_hook_start_file_offset_fdset(QTestState *from, 59 QTestState *to) 60 { 61 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); 62 63 fdset_add_fds(from, file, O_WRONLY, 1, false); 64 fdset_add_fds(to, file, O_RDONLY, 1, false); 65 66 return NULL; 67 } 68 69 static void test_precopy_file_offset_fdset(void) 70 { 71 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", 72 FILE_TEST_OFFSET); 73 MigrateCommon args = { 74 .connect_uri = uri, 75 .listen_uri = "defer", 76 .start_hook = migrate_hook_start_file_offset_fdset, 77 }; 78 79 test_file_common(&args, false); 80 } 81 #endif 82 83 static void test_precopy_file_offset(void) 84 { 85 g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs, 86 FILE_TEST_FILENAME, 87 FILE_TEST_OFFSET); 88 MigrateCommon args = { 89 .connect_uri = uri, 90 .listen_uri = "defer", 91 }; 92 93 test_file_common(&args, false); 94 } 95 96 static void test_precopy_file_offset_bad(void) 97 { 98 /* using a value not supported by qemu_strtosz() */ 99 g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M", 100 tmpfs, FILE_TEST_FILENAME); 101 MigrateCommon args = { 102 .connect_uri = uri, 103 .listen_uri = "defer", 104 .result = MIG_TEST_QMP_ERROR, 105 }; 106 107 test_file_common(&args, false); 108 } 109 110 static void test_precopy_file_mapped_ram_live(void) 111 { 112 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 113 FILE_TEST_FILENAME); 114 MigrateCommon args = { 115 .connect_uri = uri, 116 .listen_uri = "defer", 117 .start = { 118 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, 119 }, 120 }; 121 122 test_file_common(&args, false); 123 } 124 125 static void test_precopy_file_mapped_ram(void) 126 { 127 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 128 FILE_TEST_FILENAME); 129 MigrateCommon args = { 130 .connect_uri = uri, 131 .listen_uri = "defer", 132 .start = { 133 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, 134 }, 135 }; 136 137 test_file_common(&args, true); 138 } 139 140 static void test_multifd_file_mapped_ram_live(void) 141 { 142 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 143 FILE_TEST_FILENAME); 144 MigrateCommon args = { 145 .connect_uri = uri, 146 .listen_uri = "defer", 147 .start = { 148 .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 149 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, 150 }, 151 }; 152 153 test_file_common(&args, false); 154 } 155 156 static void test_multifd_file_mapped_ram(void) 157 { 158 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 159 FILE_TEST_FILENAME); 160 MigrateCommon args = { 161 .connect_uri = uri, 162 .listen_uri = "defer", 163 .start = { 164 .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 165 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, 166 }, 167 }; 168 169 test_file_common(&args, true); 170 } 171 172 static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from, 173 QTestState *to) 174 { 175 migrate_set_parameter_bool(from, "direct-io", true); 176 migrate_set_parameter_bool(to, "direct-io", true); 177 178 return NULL; 179 } 180 181 static void test_multifd_file_mapped_ram_dio(void) 182 { 183 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 184 FILE_TEST_FILENAME); 185 MigrateCommon args = { 186 .connect_uri = uri, 187 .listen_uri = "defer", 188 .start_hook = migrate_hook_start_multifd_mapped_ram_dio, 189 .start = { 190 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, 191 .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 192 }, 193 }; 194 195 if (!probe_o_direct_support(tmpfs)) { 196 g_test_skip("Filesystem does not support O_DIRECT"); 197 return; 198 } 199 200 test_file_common(&args, true); 201 } 202 203 #ifndef _WIN32 204 static void migrate_hook_end_multifd_mapped_ram_fdset(QTestState *from, 205 QTestState *to, 206 void *opaque) 207 { 208 QDict *resp; 209 QList *fdsets; 210 211 /* 212 * Remove the fdsets after migration, otherwise a second migration 213 * would fail due fdset reuse. 214 */ 215 qtest_qmp_assert_success(from, "{'execute': 'remove-fd', " 216 "'arguments': { 'fdset-id': 1}}"); 217 218 /* 219 * Make sure no fdsets are left after migration, otherwise a 220 * second migration would fail due fdset reuse. 221 */ 222 resp = qtest_qmp(from, "{'execute': 'query-fdsets', " 223 "'arguments': {}}"); 224 g_assert(qdict_haskey(resp, "return")); 225 fdsets = qdict_get_qlist(resp, "return"); 226 g_assert(fdsets && qlist_empty(fdsets)); 227 qobject_unref(resp); 228 } 229 230 static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from, 231 QTestState *to) 232 { 233 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); 234 235 fdset_add_fds(from, file, O_WRONLY, 2, true); 236 fdset_add_fds(to, file, O_RDONLY, 2, true); 237 238 migrate_set_parameter_bool(from, "direct-io", true); 239 migrate_set_parameter_bool(to, "direct-io", true); 240 241 return NULL; 242 } 243 244 static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from, 245 QTestState *to) 246 { 247 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); 248 249 fdset_add_fds(from, file, O_WRONLY, 2, false); 250 fdset_add_fds(to, file, O_RDONLY, 2, false); 251 252 return NULL; 253 } 254 255 static void test_multifd_file_mapped_ram_fdset(void) 256 { 257 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", 258 FILE_TEST_OFFSET); 259 MigrateCommon args = { 260 .connect_uri = uri, 261 .listen_uri = "defer", 262 .start_hook = migrate_hook_start_multifd_mapped_ram_fdset, 263 .end_hook = migrate_hook_end_multifd_mapped_ram_fdset, 264 .start = { 265 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, 266 .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 267 }, 268 }; 269 270 test_file_common(&args, true); 271 } 272 273 static void test_multifd_file_mapped_ram_fdset_dio(void) 274 { 275 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", 276 FILE_TEST_OFFSET); 277 MigrateCommon args = { 278 .connect_uri = uri, 279 .listen_uri = "defer", 280 .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio, 281 .end_hook = migrate_hook_end_multifd_mapped_ram_fdset, 282 .start = { 283 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, 284 .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 285 }, 286 }; 287 288 if (!probe_o_direct_support(tmpfs)) { 289 g_test_skip("Filesystem does not support O_DIRECT"); 290 return; 291 } 292 293 test_file_common(&args, true); 294 } 295 #endif /* !_WIN32 */ 296 297 static void migration_test_add_file_smoke(MigrationTestEnv *env) 298 { 299 migration_test_add("/migration/precopy/file", 300 test_precopy_file); 301 302 migration_test_add("/migration/multifd/file/mapped-ram/dio", 303 test_multifd_file_mapped_ram_dio); 304 } 305 306 void migration_test_add_file(MigrationTestEnv *env) 307 { 308 tmpfs = env->tmpfs; 309 310 migration_test_add_file_smoke(env); 311 312 if (!env->full_set) { 313 return; 314 } 315 316 migration_test_add("/migration/precopy/file/offset", 317 test_precopy_file_offset); 318 #ifndef _WIN32 319 migration_test_add("/migration/precopy/file/offset/fdset", 320 test_precopy_file_offset_fdset); 321 #endif 322 migration_test_add("/migration/precopy/file/offset/bad", 323 test_precopy_file_offset_bad); 324 325 migration_test_add("/migration/precopy/file/mapped-ram", 326 test_precopy_file_mapped_ram); 327 migration_test_add("/migration/precopy/file/mapped-ram/live", 328 test_precopy_file_mapped_ram_live); 329 330 migration_test_add("/migration/multifd/file/mapped-ram", 331 test_multifd_file_mapped_ram); 332 migration_test_add("/migration/multifd/file/mapped-ram/live", 333 test_multifd_file_mapped_ram_live); 334 335 #ifndef _WIN32 336 migration_test_add("/migration/multifd/file/mapped-ram/fdset", 337 test_multifd_file_mapped_ram_fdset); 338 migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio", 339 test_multifd_file_mapped_ram_fdset_dio); 340 #endif 341 } 342