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 *migrate_hook_start_mapped_ram(QTestState *from, 111 QTestState *to) 112 { 113 migrate_set_capability(from, "mapped-ram", true); 114 migrate_set_capability(to, "mapped-ram", true); 115 116 return NULL; 117 } 118 119 static void test_precopy_file_mapped_ram_live(void) 120 { 121 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 122 FILE_TEST_FILENAME); 123 MigrateCommon args = { 124 .connect_uri = uri, 125 .listen_uri = "defer", 126 .start_hook = migrate_hook_start_mapped_ram, 127 }; 128 129 test_file_common(&args, false); 130 } 131 132 static void test_precopy_file_mapped_ram(void) 133 { 134 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 135 FILE_TEST_FILENAME); 136 MigrateCommon args = { 137 .connect_uri = uri, 138 .listen_uri = "defer", 139 .start_hook = migrate_hook_start_mapped_ram, 140 }; 141 142 test_file_common(&args, true); 143 } 144 145 static void *migrate_hook_start_multifd_mapped_ram(QTestState *from, 146 QTestState *to) 147 { 148 migrate_hook_start_mapped_ram(from, to); 149 150 migrate_set_parameter_int(from, "multifd-channels", 4); 151 migrate_set_parameter_int(to, "multifd-channels", 4); 152 153 migrate_set_capability(from, "multifd", true); 154 migrate_set_capability(to, "multifd", true); 155 156 return NULL; 157 } 158 159 static void test_multifd_file_mapped_ram_live(void) 160 { 161 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 162 FILE_TEST_FILENAME); 163 MigrateCommon args = { 164 .connect_uri = uri, 165 .listen_uri = "defer", 166 .start_hook = migrate_hook_start_multifd_mapped_ram, 167 }; 168 169 test_file_common(&args, false); 170 } 171 172 static void test_multifd_file_mapped_ram(void) 173 { 174 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 175 FILE_TEST_FILENAME); 176 MigrateCommon args = { 177 .connect_uri = uri, 178 .listen_uri = "defer", 179 .start_hook = migrate_hook_start_multifd_mapped_ram, 180 }; 181 182 test_file_common(&args, true); 183 } 184 185 static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from, 186 QTestState *to) 187 { 188 migrate_hook_start_multifd_mapped_ram(from, to); 189 190 migrate_set_parameter_bool(from, "direct-io", true); 191 migrate_set_parameter_bool(to, "direct-io", true); 192 193 return NULL; 194 } 195 196 static void test_multifd_file_mapped_ram_dio(void) 197 { 198 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, 199 FILE_TEST_FILENAME); 200 MigrateCommon args = { 201 .connect_uri = uri, 202 .listen_uri = "defer", 203 .start_hook = migrate_hook_start_multifd_mapped_ram_dio, 204 }; 205 206 if (!probe_o_direct_support(tmpfs)) { 207 g_test_skip("Filesystem does not support O_DIRECT"); 208 return; 209 } 210 211 test_file_common(&args, true); 212 } 213 214 #ifndef _WIN32 215 static void migrate_hook_end_multifd_mapped_ram_fdset(QTestState *from, 216 QTestState *to, 217 void *opaque) 218 { 219 QDict *resp; 220 QList *fdsets; 221 222 /* 223 * Remove the fdsets after migration, otherwise a second migration 224 * would fail due fdset reuse. 225 */ 226 qtest_qmp_assert_success(from, "{'execute': 'remove-fd', " 227 "'arguments': { 'fdset-id': 1}}"); 228 229 /* 230 * Make sure no fdsets are left after migration, otherwise a 231 * second migration would fail due fdset reuse. 232 */ 233 resp = qtest_qmp(from, "{'execute': 'query-fdsets', " 234 "'arguments': {}}"); 235 g_assert(qdict_haskey(resp, "return")); 236 fdsets = qdict_get_qlist(resp, "return"); 237 g_assert(fdsets && qlist_empty(fdsets)); 238 qobject_unref(resp); 239 } 240 241 static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from, 242 QTestState *to) 243 { 244 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); 245 246 fdset_add_fds(from, file, O_WRONLY, 2, true); 247 fdset_add_fds(to, file, O_RDONLY, 2, true); 248 249 migrate_hook_start_multifd_mapped_ram(from, to); 250 migrate_set_parameter_bool(from, "direct-io", true); 251 migrate_set_parameter_bool(to, "direct-io", true); 252 253 return NULL; 254 } 255 256 static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from, 257 QTestState *to) 258 { 259 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); 260 261 fdset_add_fds(from, file, O_WRONLY, 2, false); 262 fdset_add_fds(to, file, O_RDONLY, 2, false); 263 264 migrate_hook_start_multifd_mapped_ram(from, to); 265 266 return NULL; 267 } 268 269 static void test_multifd_file_mapped_ram_fdset(void) 270 { 271 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", 272 FILE_TEST_OFFSET); 273 MigrateCommon args = { 274 .connect_uri = uri, 275 .listen_uri = "defer", 276 .start_hook = migrate_hook_start_multifd_mapped_ram_fdset, 277 .end_hook = migrate_hook_end_multifd_mapped_ram_fdset, 278 }; 279 280 test_file_common(&args, true); 281 } 282 283 static void test_multifd_file_mapped_ram_fdset_dio(void) 284 { 285 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", 286 FILE_TEST_OFFSET); 287 MigrateCommon args = { 288 .connect_uri = uri, 289 .listen_uri = "defer", 290 .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio, 291 .end_hook = migrate_hook_end_multifd_mapped_ram_fdset, 292 }; 293 294 if (!probe_o_direct_support(tmpfs)) { 295 g_test_skip("Filesystem does not support O_DIRECT"); 296 return; 297 } 298 299 test_file_common(&args, true); 300 } 301 #endif /* !_WIN32 */ 302 303 static void migration_test_add_file_smoke(MigrationTestEnv *env) 304 { 305 migration_test_add("/migration/precopy/file", 306 test_precopy_file); 307 308 migration_test_add("/migration/multifd/file/mapped-ram/dio", 309 test_multifd_file_mapped_ram_dio); 310 } 311 312 void migration_test_add_file(MigrationTestEnv *env) 313 { 314 tmpfs = env->tmpfs; 315 316 migration_test_add_file_smoke(env); 317 318 if (!env->full_set) { 319 return; 320 } 321 322 migration_test_add("/migration/precopy/file/offset", 323 test_precopy_file_offset); 324 #ifndef _WIN32 325 migration_test_add("/migration/precopy/file/offset/fdset", 326 test_precopy_file_offset_fdset); 327 #endif 328 migration_test_add("/migration/precopy/file/offset/bad", 329 test_precopy_file_offset_bad); 330 331 migration_test_add("/migration/precopy/file/mapped-ram", 332 test_precopy_file_mapped_ram); 333 migration_test_add("/migration/precopy/file/mapped-ram/live", 334 test_precopy_file_mapped_ram_live); 335 336 migration_test_add("/migration/multifd/file/mapped-ram", 337 test_multifd_file_mapped_ram); 338 migration_test_add("/migration/multifd/file/mapped-ram/live", 339 test_multifd_file_mapped_ram_live); 340 341 #ifndef _WIN32 342 migration_test_add("/migration/multifd/file/mapped-ram/fdset", 343 test_multifd_file_mapped_ram_fdset); 344 migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio", 345 test_multifd_file_mapped_ram_fdset_dio); 346 #endif 347 } 348