]> Git Repo - qemu.git/blob - tests/migration-test.c
tests: Add deprecated commands migration test
[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     QDict *rsp, *rsp_return;
272     bool completed;
273
274     do {
275         const char *status;
276
277         rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
278         rsp_return = qdict_get_qdict(rsp, "return");
279         status = qdict_get_str(rsp_return, "status");
280         completed = strcmp(status, "completed") == 0;
281         g_assert_cmpstr(status, !=,  "failed");
282         QDECREF(rsp);
283         usleep(1000 * 100);
284     } while (!completed);
285 }
286
287 static void wait_for_migration_pass(QTestState *who)
288 {
289     uint64_t initial_pass = get_migration_pass(who);
290     uint64_t pass;
291
292     /* Wait for the 1st sync */
293     do {
294         initial_pass = get_migration_pass(who);
295         if (got_stop || initial_pass) {
296             break;
297         }
298         usleep(1000 * 100);
299     } while (true);
300
301     do {
302         usleep(1000 * 100);
303         pass = get_migration_pass(who);
304     } while (pass == initial_pass && !got_stop);
305 }
306
307 static void check_guests_ram(QTestState *who)
308 {
309     /* Our ASM test will have been incrementing one byte from each page from
310      * 1MB to <100MB in order.
311      * This gives us a constraint that any page's byte should be equal or less
312      * than the previous pages byte (mod 256); and they should all be equal
313      * except for one transition at the point where we meet the incrementer.
314      * (We're running this with the guest stopped).
315      */
316     unsigned address;
317     uint8_t first_byte;
318     uint8_t last_byte;
319     bool hit_edge = false;
320     bool bad = false;
321
322     qtest_memread(who, start_address, &first_byte, 1);
323     last_byte = first_byte;
324
325     for (address = start_address + 4096; address < end_address; address += 4096)
326     {
327         uint8_t b;
328         qtest_memread(who, address, &b, 1);
329         if (b != last_byte) {
330             if (((b + 1) % 256) == last_byte && !hit_edge) {
331                 /* This is OK, the guest stopped at the point of
332                  * incrementing the previous page but didn't get
333                  * to us yet.
334                  */
335                 hit_edge = true;
336             } else {
337                 fprintf(stderr, "Memory content inconsistency at %x"
338                                 " first_byte = %x last_byte = %x current = %x"
339                                 " hit_edge = %x\n",
340                                 address, first_byte, last_byte, b, hit_edge);
341                 bad = true;
342             }
343         }
344         last_byte = b;
345     }
346     g_assert_false(bad);
347 }
348
349 static void cleanup(const char *filename)
350 {
351     char *path = g_strdup_printf("%s/%s", tmpfs, filename);
352
353     unlink(path);
354     g_free(path);
355 }
356
357 static void migrate_check_parameter(QTestState *who, const char *parameter,
358                                     const char *value)
359 {
360     QDict *rsp, *rsp_return;
361     char *result;
362
363     rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
364     rsp_return = qdict_get_qdict(rsp, "return");
365     result = g_strdup_printf("%" PRId64,
366                              qdict_get_try_int(rsp_return,  parameter, -1));
367     g_assert_cmpstr(result, ==, value);
368     g_free(result);
369     QDECREF(rsp);
370 }
371
372 static void migrate_set_parameter(QTestState *who, const char *parameter,
373                                   const char *value)
374 {
375     QDict *rsp;
376     gchar *cmd;
377
378     cmd = g_strdup_printf("{ 'execute': 'migrate-set-parameters',"
379                           "'arguments': { '%s': %s } }",
380                           parameter, value);
381     rsp = qtest_qmp(who, cmd);
382     g_free(cmd);
383     g_assert(qdict_haskey(rsp, "return"));
384     QDECREF(rsp);
385     migrate_check_parameter(who, parameter, value);
386 }
387
388 static void migrate_set_capability(QTestState *who, const char *capability,
389                                    const char *value)
390 {
391     QDict *rsp;
392     gchar *cmd;
393
394     cmd = g_strdup_printf("{ 'execute': 'migrate-set-capabilities',"
395                           "'arguments': { "
396                           "'capabilities': [ { "
397                           "'capability': '%s', 'state': %s } ] } }",
398                           capability, value);
399     rsp = qtest_qmp(who, cmd);
400     g_free(cmd);
401     g_assert(qdict_haskey(rsp, "return"));
402     QDECREF(rsp);
403 }
404
405 static void migrate(QTestState *who, const char *uri)
406 {
407     QDict *rsp;
408     gchar *cmd;
409
410     cmd = g_strdup_printf("{ 'execute': 'migrate',"
411                           "'arguments': { 'uri': '%s' } }",
412                           uri);
413     rsp = qtest_qmp(who, cmd);
414     g_free(cmd);
415     g_assert(qdict_haskey(rsp, "return"));
416     QDECREF(rsp);
417 }
418
419 static void test_migrate_start(QTestState **from, QTestState **to,
420                                const char *uri)
421 {
422     gchar *cmd_src, *cmd_dst;
423     char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
424     const char *arch = qtest_get_arch();
425     const char *accel = "kvm:tcg";
426
427     got_stop = false;
428
429     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
430         init_bootfile_x86(bootpath);
431         cmd_src = g_strdup_printf("-machine accel=%s -m 150M"
432                                   " -name source,debug-threads=on"
433                                   " -serial file:%s/src_serial"
434                                   " -drive file=%s,format=raw",
435                                   accel, tmpfs, bootpath);
436         cmd_dst = g_strdup_printf("-machine accel=%s -m 150M"
437                                   " -name target,debug-threads=on"
438                                   " -serial file:%s/dest_serial"
439                                   " -drive file=%s,format=raw"
440                                   " -incoming %s",
441                                   accel, tmpfs, bootpath, uri);
442     } else if (strcmp(arch, "ppc64") == 0) {
443
444         /* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
445         if (access("/sys/module/kvm_hv", F_OK)) {
446             accel = "tcg";
447         }
448         init_bootfile_ppc(bootpath);
449         cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
450                                   " -name source,debug-threads=on"
451                                   " -serial file:%s/src_serial"
452                                   " -drive file=%s,if=pflash,format=raw",
453                                   accel, tmpfs, bootpath);
454         cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
455                                   " -name target,debug-threads=on"
456                                   " -serial file:%s/dest_serial"
457                                   " -incoming %s",
458                                   accel, tmpfs, uri);
459     } else {
460         g_assert_not_reached();
461     }
462
463     g_free(bootpath);
464
465     *from = qtest_start(cmd_src);
466     g_free(cmd_src);
467
468     *to = qtest_init(cmd_dst);
469     g_free(cmd_dst);
470 }
471
472 static void test_migrate_end(QTestState *from, QTestState *to)
473 {
474     unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
475
476     qtest_quit(from);
477
478     qtest_memread(to, start_address, &dest_byte_a, 1);
479
480     /* Destination still running, wait for a byte to change */
481     do {
482         qtest_memread(to, start_address, &dest_byte_b, 1);
483         usleep(10 * 1000);
484     } while (dest_byte_a == dest_byte_b);
485
486     qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
487     /* With it stopped, check nothing changes */
488     qtest_memread(to, start_address, &dest_byte_c, 1);
489     sleep(1);
490     qtest_memread(to, start_address, &dest_byte_d, 1);
491     g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
492
493     check_guests_ram(to);
494
495     qtest_quit(to);
496
497     cleanup("bootsect");
498     cleanup("migsocket");
499     cleanup("src_serial");
500     cleanup("dest_serial");
501 }
502
503 static void deprecated_set_downtime(QTestState *who, const double value)
504 {
505     QDict *rsp;
506     gchar *cmd;
507     char *expected;
508     int64_t result_int;
509
510     cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime',"
511                           "'arguments': { 'value': %g } }", value);
512     rsp = qtest_qmp(who, cmd);
513     g_free(cmd);
514     g_assert(qdict_haskey(rsp, "return"));
515     QDECREF(rsp);
516     result_int = value * 1000L;
517     expected = g_strdup_printf("%" PRId64, result_int);
518     migrate_check_parameter(who, "downtime-limit", expected);
519     g_free(expected);
520 }
521
522 static void deprecated_set_speed(QTestState *who, const char *value)
523 {
524     QDict *rsp;
525     gchar *cmd;
526
527     cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed',"
528                           "'arguments': { 'value': %s } }", value);
529     rsp = qtest_qmp(who, cmd);
530     g_free(cmd);
531     g_assert(qdict_haskey(rsp, "return"));
532     QDECREF(rsp);
533     migrate_check_parameter(who, "max-bandwidth", value);
534 }
535
536 static void test_deprecated(void)
537 {
538     QTestState *from;
539
540     from = qtest_start("");
541
542     deprecated_set_downtime(from, 0.12345);
543     deprecated_set_speed(from, "12345");
544
545     qtest_quit(from);
546 }
547
548 static void test_migrate(void)
549 {
550     char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
551     QTestState *from, *to;
552     QDict *rsp;
553
554     test_migrate_start(&from, &to, uri);
555
556     migrate_set_capability(from, "postcopy-ram", "true");
557     migrate_set_capability(to, "postcopy-ram", "true");
558
559     /* We want to pick a speed slow enough that the test completes
560      * quickly, but that it doesn't complete precopy even on a slow
561      * machine, so also set the downtime.
562      */
563     migrate_set_parameter(from, "max-bandwidth", "100000000");
564     migrate_set_parameter(from, "downtime-limit", "1");
565
566     /* Wait for the first serial output from the source */
567     wait_for_serial("src_serial");
568
569     migrate(from, uri);
570
571     wait_for_migration_pass(from);
572
573     rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
574     g_assert(qdict_haskey(rsp, "return"));
575     QDECREF(rsp);
576
577     if (!got_stop) {
578         qtest_qmp_eventwait(from, "STOP");
579     }
580
581     qtest_qmp_eventwait(to, "RESUME");
582
583     wait_for_serial("dest_serial");
584     wait_for_migration_complete(from);
585
586     g_free(uri);
587
588     test_migrate_end(from, to);
589 }
590
591 int main(int argc, char **argv)
592 {
593     char template[] = "/tmp/migration-test-XXXXXX";
594     int ret;
595
596     g_test_init(&argc, &argv, NULL);
597
598     if (!ufd_version_check()) {
599         return 0;
600     }
601
602     tmpfs = mkdtemp(template);
603     if (!tmpfs) {
604         g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
605     }
606     g_assert(tmpfs);
607
608     module_call_init(MODULE_INIT_QOM);
609
610     qtest_add_func("/migration/postcopy/unix", test_migrate);
611     qtest_add_func("/migration/deprecated", test_deprecated);
612
613     ret = g_test_run();
614
615     g_assert_cmpint(ret, ==, 0);
616
617     ret = rmdir(tmpfs);
618     if (ret != 0) {
619         g_test_message("unable to rmdir: path (%s): %s\n",
620                        tmpfs, strerror(errno));
621     }
622
623     return ret;
624 }
This page took 0.058747 seconds and 4 git commands to generate.