]> git.proxmox.com Git - mirror_qemu.git/blob - tests/migration-test.c
Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20180206.0' into...
[mirror_qemu.git] / tests / migration-test.c
1 /*
2 * QTest testcase for migration
3 *
4 * Copyright (c) 2016 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
15 #include "libqtest.h"
16 #include "qemu/option.h"
17 #include "qemu/range.h"
18 #include "qemu/sockets.h"
19 #include "chardev/char.h"
20 #include "sysemu/sysemu.h"
21 #include "hw/nvram/chrp_nvram.h"
22
23 #define MIN_NVRAM_SIZE 8192 /* from spapr_nvram.c */
24
25 const unsigned start_address = 1024 * 1024;
26 const unsigned end_address = 100 * 1024 * 1024;
27 bool got_stop;
28
29 #if defined(__linux__)
30 #include <sys/syscall.h>
31 #include <sys/vfs.h>
32 #endif
33
34 #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
35 #include <sys/eventfd.h>
36 #include <sys/ioctl.h>
37 #include <linux/userfaultfd.h>
38
39 static bool ufd_version_check(void)
40 {
41 struct uffdio_api api_struct;
42 uint64_t ioctl_mask;
43
44 int ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
45
46 if (ufd == -1) {
47 g_test_message("Skipping test: userfaultfd not available");
48 return false;
49 }
50
51 api_struct.api = UFFD_API;
52 api_struct.features = 0;
53 if (ioctl(ufd, UFFDIO_API, &api_struct)) {
54 g_test_message("Skipping test: UFFDIO_API failed");
55 return false;
56 }
57
58 ioctl_mask = (__u64)1 << _UFFDIO_REGISTER |
59 (__u64)1 << _UFFDIO_UNREGISTER;
60 if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
61 g_test_message("Skipping test: Missing userfault feature");
62 return false;
63 }
64
65 return true;
66 }
67
68 #else
69 static bool ufd_version_check(void)
70 {
71 g_test_message("Skipping test: Userfault not available (builtdtime)");
72 return false;
73 }
74
75 #endif
76
77 static const char *tmpfs;
78
79 /* A simple PC boot sector that modifies memory (1-100MB) quickly
80 * outputing a 'B' every so often if it's still running.
81 */
82 unsigned char bootsect[] = {
83 0xfa, 0x0f, 0x01, 0x16, 0x74, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00,
84 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02,
86 0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41,
87 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10,
88 0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40,
89 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x75, 0xe9, 0x66, 0xb8, 0x42, 0x00, 0x66,
90 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xde, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00,
92 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x5c, 0x7c,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
126 };
127
128 static void init_bootfile_x86(const char *bootpath)
129 {
130 FILE *bootfile = fopen(bootpath, "wb");
131
132 g_assert_cmpint(fwrite(bootsect, 512, 1, bootfile), ==, 1);
133 fclose(bootfile);
134 }
135
136 static void init_bootfile_ppc(const char *bootpath)
137 {
138 FILE *bootfile;
139 char buf[MIN_NVRAM_SIZE];
140 ChrpNvramPartHdr *header = (ChrpNvramPartHdr *)buf;
141
142 memset(buf, 0, MIN_NVRAM_SIZE);
143
144 /* Create a "common" partition in nvram to store boot-command property */
145
146 header->signature = CHRP_NVPART_SYSTEM;
147 memcpy(header->name, "common", 6);
148 chrp_nvram_finish_partition(header, MIN_NVRAM_SIZE);
149
150 /* FW_MAX_SIZE is 4MB, but slof.bin is only 900KB,
151 * so let's modify memory between 1MB and 100MB
152 * to do like PC bootsector
153 */
154
155 sprintf(buf + 16,
156 "boot-command=hex .\" _\" begin %x %x do i c@ 1 + i c! 1000 +loop "
157 ".\" B\" 0 until", end_address, start_address);
158
159 /* Write partition to the NVRAM file */
160
161 bootfile = fopen(bootpath, "wb");
162 g_assert_cmpint(fwrite(buf, MIN_NVRAM_SIZE, 1, bootfile), ==, 1);
163 fclose(bootfile);
164 }
165
166 /*
167 * Wait for some output in the serial output file,
168 * we get an 'A' followed by an endless string of 'B's
169 * but on the destination we won't have the A.
170 */
171 static void wait_for_serial(const char *side)
172 {
173 char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
174 FILE *serialfile = fopen(serialpath, "r");
175 const char *arch = qtest_get_arch();
176 int started = (strcmp(side, "src_serial") == 0 &&
177 strcmp(arch, "ppc64") == 0) ? 0 : 1;
178
179 g_free(serialpath);
180 do {
181 int readvalue = fgetc(serialfile);
182
183 if (!started) {
184 /* SLOF prints its banner before starting test,
185 * to ignore it, mark the start of the test with '_',
186 * ignore all characters until this marker
187 */
188 switch (readvalue) {
189 case '_':
190 started = 1;
191 break;
192 case EOF:
193 fseek(serialfile, 0, SEEK_SET);
194 usleep(1000);
195 break;
196 }
197 continue;
198 }
199 switch (readvalue) {
200 case 'A':
201 /* Fine */
202 break;
203
204 case 'B':
205 /* It's alive! */
206 fclose(serialfile);
207 return;
208
209 case EOF:
210 started = (strcmp(side, "src_serial") == 0 &&
211 strcmp(arch, "ppc64") == 0) ? 0 : 1;
212 fseek(serialfile, 0, SEEK_SET);
213 usleep(1000);
214 break;
215
216 default:
217 fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
218 g_assert_not_reached();
219 }
220 } while (true);
221 }
222
223 /*
224 * Events can get in the way of responses we are actually waiting for.
225 */
226 static QDict *wait_command(QTestState *who, const char *command)
227 {
228 const char *event_string;
229 QDict *response;
230
231 response = qtest_qmp(who, command);
232
233 while (qdict_haskey(response, "event")) {
234 /* OK, it was an event */
235 event_string = qdict_get_str(response, "event");
236 if (!strcmp(event_string, "STOP")) {
237 got_stop = true;
238 }
239 QDECREF(response);
240 response = qtest_qmp_receive(who);
241 }
242 return response;
243 }
244
245
246 /*
247 * It's tricky to use qemu's migration event capability with qtest,
248 * events suddenly appearing confuse the qmp()/hmp() responses.
249 */
250
251 static uint64_t get_migration_pass(QTestState *who)
252 {
253 QDict *rsp, *rsp_return, *rsp_ram;
254 uint64_t result;
255
256 rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
257 rsp_return = qdict_get_qdict(rsp, "return");
258 if (!qdict_haskey(rsp_return, "ram")) {
259 /* Still in setup */
260 result = 0;
261 } else {
262 rsp_ram = qdict_get_qdict(rsp_return, "ram");
263 result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0);
264 }
265 QDECREF(rsp);
266 return result;
267 }
268
269 static void wait_for_migration_complete(QTestState *who)
270 {
271 while (true) {
272 QDict *rsp, *rsp_return;
273 bool completed;
274 const char *status;
275
276 rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
277 rsp_return = qdict_get_qdict(rsp, "return");
278 status = qdict_get_str(rsp_return, "status");
279 completed = strcmp(status, "completed") == 0;
280 g_assert_cmpstr(status, !=, "failed");
281 QDECREF(rsp);
282 if (completed) {
283 return;
284 }
285 usleep(1000);
286 }
287 }
288
289 static void wait_for_migration_pass(QTestState *who)
290 {
291 uint64_t initial_pass = get_migration_pass(who);
292 uint64_t pass;
293
294 /* Wait for the 1st sync */
295 while (!got_stop && !initial_pass) {
296 usleep(1000);
297 initial_pass = get_migration_pass(who);
298 }
299
300 do {
301 usleep(1000);
302 pass = get_migration_pass(who);
303 } while (pass == initial_pass && !got_stop);
304 }
305
306 static void check_guests_ram(QTestState *who)
307 {
308 /* Our ASM test will have been incrementing one byte from each page from
309 * 1MB to <100MB in order.
310 * This gives us a constraint that any page's byte should be equal or less
311 * than the previous pages byte (mod 256); and they should all be equal
312 * except for one transition at the point where we meet the incrementer.
313 * (We're running this with the guest stopped).
314 */
315 unsigned address;
316 uint8_t first_byte;
317 uint8_t last_byte;
318 bool hit_edge = false;
319 bool bad = false;
320
321 qtest_memread(who, start_address, &first_byte, 1);
322 last_byte = first_byte;
323
324 for (address = start_address + 4096; address < end_address; address += 4096)
325 {
326 uint8_t b;
327 qtest_memread(who, address, &b, 1);
328 if (b != last_byte) {
329 if (((b + 1) % 256) == last_byte && !hit_edge) {
330 /* This is OK, the guest stopped at the point of
331 * incrementing the previous page but didn't get
332 * to us yet.
333 */
334 hit_edge = true;
335 } else {
336 fprintf(stderr, "Memory content inconsistency at %x"
337 " first_byte = %x last_byte = %x current = %x"
338 " hit_edge = %x\n",
339 address, first_byte, last_byte, b, hit_edge);
340 bad = true;
341 }
342 }
343 last_byte = b;
344 }
345 g_assert_false(bad);
346 }
347
348 static void cleanup(const char *filename)
349 {
350 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
351
352 unlink(path);
353 g_free(path);
354 }
355
356 static void migrate_check_parameter(QTestState *who, const char *parameter,
357 const char *value)
358 {
359 QDict *rsp, *rsp_return;
360 char *result;
361
362 rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
363 rsp_return = qdict_get_qdict(rsp, "return");
364 result = g_strdup_printf("%" PRId64,
365 qdict_get_try_int(rsp_return, parameter, -1));
366 g_assert_cmpstr(result, ==, value);
367 g_free(result);
368 QDECREF(rsp);
369 }
370
371 static void migrate_set_parameter(QTestState *who, const char *parameter,
372 const char *value)
373 {
374 QDict *rsp;
375 gchar *cmd;
376
377 cmd = g_strdup_printf("{ 'execute': 'migrate-set-parameters',"
378 "'arguments': { '%s': %s } }",
379 parameter, value);
380 rsp = qtest_qmp(who, cmd);
381 g_free(cmd);
382 g_assert(qdict_haskey(rsp, "return"));
383 QDECREF(rsp);
384 migrate_check_parameter(who, parameter, value);
385 }
386
387 static void migrate_set_capability(QTestState *who, const char *capability,
388 const char *value)
389 {
390 QDict *rsp;
391 gchar *cmd;
392
393 cmd = g_strdup_printf("{ 'execute': 'migrate-set-capabilities',"
394 "'arguments': { "
395 "'capabilities': [ { "
396 "'capability': '%s', 'state': %s } ] } }",
397 capability, value);
398 rsp = qtest_qmp(who, cmd);
399 g_free(cmd);
400 g_assert(qdict_haskey(rsp, "return"));
401 QDECREF(rsp);
402 }
403
404 static void migrate(QTestState *who, const char *uri)
405 {
406 QDict *rsp;
407 gchar *cmd;
408
409 cmd = g_strdup_printf("{ 'execute': 'migrate',"
410 "'arguments': { 'uri': '%s' } }",
411 uri);
412 rsp = qtest_qmp(who, cmd);
413 g_free(cmd);
414 g_assert(qdict_haskey(rsp, "return"));
415 QDECREF(rsp);
416 }
417
418 static void migrate_start_postcopy(QTestState *who)
419 {
420 QDict *rsp;
421
422 rsp = wait_command(who, "{ 'execute': 'migrate-start-postcopy' }");
423 g_assert(qdict_haskey(rsp, "return"));
424 QDECREF(rsp);
425 }
426
427 static void test_migrate_start(QTestState **from, QTestState **to,
428 const char *uri)
429 {
430 gchar *cmd_src, *cmd_dst;
431 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
432 const char *arch = qtest_get_arch();
433 const char *accel = "kvm:tcg";
434
435 got_stop = false;
436
437 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
438 init_bootfile_x86(bootpath);
439 cmd_src = g_strdup_printf("-machine accel=%s -m 150M"
440 " -name source,debug-threads=on"
441 " -serial file:%s/src_serial"
442 " -drive file=%s,format=raw",
443 accel, tmpfs, bootpath);
444 cmd_dst = g_strdup_printf("-machine accel=%s -m 150M"
445 " -name target,debug-threads=on"
446 " -serial file:%s/dest_serial"
447 " -drive file=%s,format=raw"
448 " -incoming %s",
449 accel, tmpfs, bootpath, uri);
450 } else if (strcmp(arch, "ppc64") == 0) {
451
452 /* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
453 if (access("/sys/module/kvm_hv", F_OK)) {
454 accel = "tcg";
455 }
456 init_bootfile_ppc(bootpath);
457 cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
458 " -name source,debug-threads=on"
459 " -serial file:%s/src_serial"
460 " -drive file=%s,if=pflash,format=raw",
461 accel, tmpfs, bootpath);
462 cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
463 " -name target,debug-threads=on"
464 " -serial file:%s/dest_serial"
465 " -incoming %s",
466 accel, tmpfs, uri);
467 } else {
468 g_assert_not_reached();
469 }
470
471 g_free(bootpath);
472
473 *from = qtest_start(cmd_src);
474 g_free(cmd_src);
475
476 *to = qtest_init(cmd_dst);
477 g_free(cmd_dst);
478 }
479
480 static void test_migrate_end(QTestState *from, QTestState *to)
481 {
482 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
483
484 qtest_quit(from);
485
486 qtest_memread(to, start_address, &dest_byte_a, 1);
487
488 /* Destination still running, wait for a byte to change */
489 do {
490 qtest_memread(to, start_address, &dest_byte_b, 1);
491 usleep(1000 * 10);
492 } while (dest_byte_a == dest_byte_b);
493
494 qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
495 /* With it stopped, check nothing changes */
496 qtest_memread(to, start_address, &dest_byte_c, 1);
497 usleep(1000 * 200);
498 qtest_memread(to, start_address, &dest_byte_d, 1);
499 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
500
501 check_guests_ram(to);
502
503 qtest_quit(to);
504
505 cleanup("bootsect");
506 cleanup("migsocket");
507 cleanup("src_serial");
508 cleanup("dest_serial");
509 }
510
511 static void deprecated_set_downtime(QTestState *who, const double value)
512 {
513 QDict *rsp;
514 gchar *cmd;
515 char *expected;
516 int64_t result_int;
517
518 cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime',"
519 "'arguments': { 'value': %g } }", value);
520 rsp = qtest_qmp(who, cmd);
521 g_free(cmd);
522 g_assert(qdict_haskey(rsp, "return"));
523 QDECREF(rsp);
524 result_int = value * 1000L;
525 expected = g_strdup_printf("%" PRId64, result_int);
526 migrate_check_parameter(who, "downtime-limit", expected);
527 g_free(expected);
528 }
529
530 static void deprecated_set_speed(QTestState *who, const char *value)
531 {
532 QDict *rsp;
533 gchar *cmd;
534
535 cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed',"
536 "'arguments': { 'value': %s } }", value);
537 rsp = qtest_qmp(who, cmd);
538 g_free(cmd);
539 g_assert(qdict_haskey(rsp, "return"));
540 QDECREF(rsp);
541 migrate_check_parameter(who, "max-bandwidth", value);
542 }
543
544 static void test_deprecated(void)
545 {
546 QTestState *from;
547
548 from = qtest_start("");
549
550 deprecated_set_downtime(from, 0.12345);
551 deprecated_set_speed(from, "12345");
552
553 qtest_quit(from);
554 }
555
556 static void test_migrate(void)
557 {
558 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
559 QTestState *from, *to;
560
561 test_migrate_start(&from, &to, uri);
562
563 migrate_set_capability(from, "postcopy-ram", "true");
564 migrate_set_capability(to, "postcopy-ram", "true");
565
566 /* We want to pick a speed slow enough that the test completes
567 * quickly, but that it doesn't complete precopy even on a slow
568 * machine, so also set the downtime.
569 */
570 migrate_set_parameter(from, "max-bandwidth", "100000000");
571 migrate_set_parameter(from, "downtime-limit", "1");
572
573 /* Wait for the first serial output from the source */
574 wait_for_serial("src_serial");
575
576 migrate(from, uri);
577
578 wait_for_migration_pass(from);
579
580 migrate_start_postcopy(from);
581
582 if (!got_stop) {
583 qtest_qmp_eventwait(from, "STOP");
584 }
585
586 qtest_qmp_eventwait(to, "RESUME");
587
588 wait_for_serial("dest_serial");
589 wait_for_migration_complete(from);
590
591 g_free(uri);
592
593 test_migrate_end(from, to);
594 }
595
596 int main(int argc, char **argv)
597 {
598 char template[] = "/tmp/migration-test-XXXXXX";
599 int ret;
600
601 g_test_init(&argc, &argv, NULL);
602
603 if (!ufd_version_check()) {
604 return 0;
605 }
606
607 tmpfs = mkdtemp(template);
608 if (!tmpfs) {
609 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
610 }
611 g_assert(tmpfs);
612
613 module_call_init(MODULE_INIT_QOM);
614
615 qtest_add_func("/migration/postcopy/unix", test_migrate);
616 qtest_add_func("/migration/deprecated", test_deprecated);
617
618 ret = g_test_run();
619
620 g_assert_cmpint(ret, ==, 0);
621
622 ret = rmdir(tmpfs);
623 if (ret != 0) {
624 g_test_message("unable to rmdir: path (%s): %s\n",
625 tmpfs, strerror(errno));
626 }
627
628 return ret;
629 }