]>
git.proxmox.com Git - mirror_qemu.git/blob - tests/postcopy-test.c
2 * QTest testcase for postcopy
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.
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.
13 #include "qemu/osdep.h"
17 #include "qemu/option.h"
18 #include "qemu/range.h"
19 #include "sysemu/char.h"
20 #include "sysemu/sysemu.h"
22 #include <qemu/sockets.h>
24 const unsigned start_address
= 1024 * 1024;
25 const unsigned end_address
= 100 * 1024 * 1024;
28 #if defined(__linux__)
29 #include <sys/syscall.h>
33 #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
34 #include <sys/eventfd.h>
35 #include <sys/ioctl.h>
36 #include <linux/userfaultfd.h>
38 static bool ufd_version_check(void)
40 struct uffdio_api api_struct
;
43 int ufd
= ufd
= syscall(__NR_userfaultfd
, O_CLOEXEC
);
46 g_test_message("Skipping test: userfaultfd not available");
50 api_struct
.api
= UFFD_API
;
51 api_struct
.features
= 0;
52 if (ioctl(ufd
, UFFDIO_API
, &api_struct
)) {
53 g_test_message("Skipping test: UFFDIO_API failed");
57 ioctl_mask
= (__u64
)1 << _UFFDIO_REGISTER
|
58 (__u64
)1 << _UFFDIO_UNREGISTER
;
59 if ((api_struct
.ioctls
& ioctl_mask
) != ioctl_mask
) {
60 g_test_message("Skipping test: Missing userfault feature");
68 static bool ufd_version_check(void)
70 g_test_message("Skipping test: Userfault not available (builtdtime)");
76 static const char *tmpfs
;
78 /* A simple PC boot sector that modifies memory (1-100MB) quickly
79 * outputing a 'B' every so often if it's still running.
81 unsigned char bootsect
[] = {
82 0xfa, 0x0f, 0x01, 0x16, 0x74, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00,
83 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02,
85 0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41,
86 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10,
87 0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40,
88 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x75, 0xe9, 0x66, 0xb8, 0x42, 0x00, 0x66,
89 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xde, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00,
91 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x5c, 0x7c,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x55, 0xaa
128 * Wait for some output in the serial output file,
129 * we get an 'A' followed by an endless string of 'B's
130 * but on the destination we won't have the A.
132 static void wait_for_serial(const char *side
)
134 char *serialpath
= g_strdup_printf("%s/%s", tmpfs
, side
);
135 FILE *serialfile
= fopen(serialpath
, "r");
138 int readvalue
= fgetc(serialfile
);
152 fseek(serialfile
, 0, SEEK_SET
);
157 fprintf(stderr
, "Unexpected %d on %s serial\n", readvalue
, side
);
158 g_assert_not_reached();
164 * Events can get in the way of responses we are actually waiting for.
166 static QDict
*return_or_event(QDict
*response
)
168 const char *event_string
;
169 if (!qdict_haskey(response
, "event")) {
173 /* OK, it was an event */
174 event_string
= qdict_get_str(response
, "event");
175 if (!strcmp(event_string
, "STOP")) {
179 return return_or_event(qtest_qmp_receive(global_qtest
));
184 * It's tricky to use qemu's migration event capability with qtest,
185 * events suddenly appearing confuse the qmp()/hmp() responses.
186 * so wait for a couple of passes to have happened before
190 static uint64_t get_migration_pass(void)
192 QDict
*rsp
, *rsp_return
, *rsp_ram
;
195 rsp
= return_or_event(qmp("{ 'execute': 'query-migrate' }"));
196 rsp_return
= qdict_get_qdict(rsp
, "return");
197 if (!qdict_haskey(rsp_return
, "ram")) {
201 rsp_ram
= qdict_get_qdict(rsp_return
, "ram");
202 result
= qdict_get_try_int(rsp_ram
, "dirty-sync-count", 0);
208 static void wait_for_migration_complete(void)
210 QDict
*rsp
, *rsp_return
;
216 rsp
= return_or_event(qmp("{ 'execute': 'query-migrate' }"));
217 rsp_return
= qdict_get_qdict(rsp
, "return");
218 status
= qdict_get_str(rsp_return
, "status");
219 completed
= strcmp(status
, "completed") == 0;
220 g_assert_cmpstr(status
, !=, "failed");
223 } while (!completed
);
226 static void wait_for_migration_pass(void)
228 uint64_t initial_pass
= get_migration_pass();
231 /* Wait for the 1st sync */
233 initial_pass
= get_migration_pass();
234 if (got_stop
|| initial_pass
) {
242 pass
= get_migration_pass();
243 } while (pass
== initial_pass
&& !got_stop
);
246 static void check_guests_ram(void)
248 /* Our ASM test will have been incrementing one byte from each page from
249 * 1MB to <100MB in order.
250 * This gives us a constraint that any page's byte should be equal or less
251 * than the previous pages byte (mod 256); and they should all be equal
252 * except for one transition at the point where we meet the incrementer.
253 * (We're running this with the guest stopped).
258 bool hit_edge
= false;
261 qtest_memread(global_qtest
, start_address
, &first_byte
, 1);
262 last_byte
= first_byte
;
264 for (address
= start_address
+ 4096; address
< end_address
; address
+= 4096)
267 qtest_memread(global_qtest
, address
, &b
, 1);
268 if (b
!= last_byte
) {
269 if (((b
+ 1) % 256) == last_byte
&& !hit_edge
) {
270 /* This is OK, the guest stopped at the point of
271 * incrementing the previous page but didn't get
276 fprintf(stderr
, "Memory content inconsistency at %x"
277 " first_byte = %x last_byte = %x current = %x"
279 address
, first_byte
, last_byte
, b
, hit_edge
);
288 static void cleanup(const char *filename
)
290 char *path
= g_strdup_printf("%s/%s", tmpfs
, filename
);
295 static void test_migrate(void)
297 char *uri
= g_strdup_printf("unix:%s/migsocket", tmpfs
);
298 QTestState
*global
= global_qtest
, *from
, *to
;
299 unsigned char dest_byte_a
, dest_byte_b
, dest_byte_c
, dest_byte_d
;
303 char *bootpath
= g_strdup_printf("%s/bootsect", tmpfs
);
304 FILE *bootfile
= fopen(bootpath
, "wb");
307 g_assert_cmpint(fwrite(bootsect
, 512, 1, bootfile
), ==, 1);
310 cmd
= g_strdup_printf("-machine accel=kvm:tcg -m 150M"
311 " -name pcsource,debug-threads=on"
312 " -serial file:%s/src_serial"
313 " -drive file=%s,format=raw",
315 from
= qtest_start(cmd
);
318 cmd
= g_strdup_printf("-machine accel=kvm:tcg -m 150M"
319 " -name pcdest,debug-threads=on"
320 " -serial file:%s/dest_serial"
321 " -drive file=%s,format=raw"
323 tmpfs
, bootpath
, uri
);
324 to
= qtest_init(cmd
);
328 rsp
= qmp("{ 'execute': 'migrate-set-capabilities',"
330 "'capabilities': [ {"
331 "'capability': 'postcopy-ram',"
332 "'state': true } ] } }");
333 g_assert(qdict_haskey(rsp
, "return"));
337 rsp
= qmp("{ 'execute': 'migrate-set-capabilities',"
339 "'capabilities': [ {"
340 "'capability': 'postcopy-ram',"
341 "'state': true } ] } }");
342 g_assert(qdict_haskey(rsp
, "return"));
345 /* We want to pick a speed slow enough that the test completes
346 * quickly, but that it doesn't complete precopy even on a slow
347 * machine, so also set the downtime.
350 rsp
= qmp("{ 'execute': 'migrate_set_speed',"
351 "'arguments': { 'value': 100000000 } }");
352 g_assert(qdict_haskey(rsp
, "return"));
355 /* 1ms downtime - it should never finish precopy */
356 rsp
= qmp("{ 'execute': 'migrate_set_downtime',"
357 "'arguments': { 'value': 0.001 } }");
358 g_assert(qdict_haskey(rsp
, "return"));
362 /* Wait for the first serial output from the source */
363 wait_for_serial("src_serial");
365 cmd
= g_strdup_printf("{ 'execute': 'migrate',"
366 "'arguments': { 'uri': '%s' } }",
370 g_assert(qdict_haskey(rsp
, "return"));
373 wait_for_migration_pass();
375 rsp
= return_or_event(qmp("{ 'execute': 'migrate-start-postcopy' }"));
376 g_assert(qdict_haskey(rsp
, "return"));
380 qmp_eventwait("STOP");
384 qmp_eventwait("RESUME");
386 wait_for_serial("dest_serial");
388 wait_for_migration_complete();
394 qtest_memread(to
, start_address
, &dest_byte_a
, 1);
396 /* Destination still running, wait for a byte to change */
398 qtest_memread(to
, start_address
, &dest_byte_b
, 1);
400 } while (dest_byte_a
== dest_byte_b
);
402 qmp("{ 'execute' : 'stop'}");
403 /* With it stopped, check nothing changes */
404 qtest_memread(to
, start_address
, &dest_byte_c
, 1);
406 qtest_memread(to
, start_address
, &dest_byte_d
, 1);
407 g_assert_cmpint(dest_byte_c
, ==, dest_byte_d
);
414 global_qtest
= global
;
417 cleanup("migsocket");
418 cleanup("src_serial");
419 cleanup("dest_serial");
422 int main(int argc
, char **argv
)
424 char template[] = "/tmp/postcopy-test-XXXXXX";
427 g_test_init(&argc
, &argv
, NULL
);
429 if (!ufd_version_check()) {
433 tmpfs
= mkdtemp(template);
435 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno
));
439 module_call_init(MODULE_INIT_QOM
);
441 qtest_add_func("/postcopy", test_migrate
);
445 g_assert_cmpint(ret
, ==, 0);
449 g_test_message("unable to rmdir: path (%s): %s\n",
450 tmpfs
, strerror(errno
));