wxx: Fix compilation of host-libusb.c
[qemu/kevin.git] / tests / postcopy-test.c
blob229e9e901a6a175d05095f38edae995e7670d94c
1 /*
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"
15 #include "libqtest.h"
16 #include "qemu/option.h"
17 #include "qemu/range.h"
18 #include "qemu/sockets.h"
19 #include "sysemu/char.h"
20 #include "sysemu/sysemu.h"
21 #include "hw/nvram/openbios_firmware_abi.h"
23 #define MIN_NVRAM_SIZE 8192 /* from spapr_nvram.c */
25 const unsigned start_address = 1024 * 1024;
26 const unsigned end_address = 100 * 1024 * 1024;
27 bool got_stop;
29 #if defined(__linux__)
30 #include <sys/syscall.h>
31 #include <sys/vfs.h>
32 #endif
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>
39 static bool ufd_version_check(void)
41 struct uffdio_api api_struct;
42 uint64_t ioctl_mask;
44 int ufd = ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
46 if (ufd == -1) {
47 g_test_message("Skipping test: userfaultfd not available");
48 return false;
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;
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;
65 return true;
68 #else
69 static bool ufd_version_check(void)
71 g_test_message("Skipping test: Userfault not available (builtdtime)");
72 return false;
75 #endif
77 static const char *tmpfs;
79 /* A simple PC boot sector that modifies memory (1-100MB) quickly
80 * outputing a 'B' every so often if it's still running.
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
128 static void init_bootfile_x86(const char *bootpath)
130 FILE *bootfile = fopen(bootpath, "wb");
132 g_assert_cmpint(fwrite(bootsect, 512, 1, bootfile), ==, 1);
133 fclose(bootfile);
136 static void init_bootfile_ppc(const char *bootpath)
138 FILE *bootfile;
139 char buf[MIN_NVRAM_SIZE];
140 struct OpenBIOS_nvpart_v1 *header = (struct OpenBIOS_nvpart_v1 *)buf;
142 memset(buf, 0, MIN_NVRAM_SIZE);
144 /* Create a "common" partition in nvram to store boot-command property */
146 header->signature = OPENBIOS_PART_SYSTEM;
147 memcpy(header->name, "common", 6);
148 OpenBIOS_finish_partition(header, MIN_NVRAM_SIZE);
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
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);
159 /* Write partition to the NVRAM file */
161 bootfile = fopen(bootpath, "wb");
162 g_assert_cmpint(fwrite(buf, MIN_NVRAM_SIZE, 1, bootfile), ==, 1);
163 fclose(bootfile);
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.
171 static void wait_for_serial(const char *side)
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;
179 do {
180 int readvalue = fgetc(serialfile);
182 if (!started) {
183 /* SLOF prints its banner before starting test,
184 * to ignore it, mark the start of the test with '_',
185 * ignore all characters until this marker
187 switch (readvalue) {
188 case '_':
189 started = 1;
190 break;
191 case EOF:
192 fseek(serialfile, 0, SEEK_SET);
193 usleep(1000);
194 break;
196 continue;
198 switch (readvalue) {
199 case 'A':
200 /* Fine */
201 break;
203 case 'B':
204 /* It's alive! */
205 fclose(serialfile);
206 g_free(serialpath);
207 return;
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;
216 default:
217 fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
218 g_assert_not_reached();
220 } while (true);
224 * Events can get in the way of responses we are actually waiting for.
226 static QDict *return_or_event(QDict *response)
228 const char *event_string;
229 if (!qdict_haskey(response, "event")) {
230 return response;
233 /* OK, it was an event */
234 event_string = qdict_get_str(response, "event");
235 if (!strcmp(event_string, "STOP")) {
236 got_stop = true;
238 QDECREF(response);
239 return return_or_event(qtest_qmp_receive(global_qtest));
244 * It's tricky to use qemu's migration event capability with qtest,
245 * events suddenly appearing confuse the qmp()/hmp() responses.
246 * so wait for a couple of passes to have happened before
247 * going postcopy.
250 static uint64_t get_migration_pass(void)
252 QDict *rsp, *rsp_return, *rsp_ram;
253 uint64_t result;
255 rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }"));
256 rsp_return = qdict_get_qdict(rsp, "return");
257 if (!qdict_haskey(rsp_return, "ram")) {
258 /* Still in setup */
259 result = 0;
260 } else {
261 rsp_ram = qdict_get_qdict(rsp_return, "ram");
262 result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0);
263 QDECREF(rsp);
265 return result;
268 static void wait_for_migration_complete(void)
270 QDict *rsp, *rsp_return;
271 bool completed;
273 do {
274 const char *status;
276 rsp = return_or_event(qmp("{ '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 usleep(1000 * 100);
283 } while (!completed);
286 static void wait_for_migration_pass(void)
288 uint64_t initial_pass = get_migration_pass();
289 uint64_t pass;
291 /* Wait for the 1st sync */
292 do {
293 initial_pass = get_migration_pass();
294 if (got_stop || initial_pass) {
295 break;
297 usleep(1000 * 100);
298 } while (true);
300 do {
301 usleep(1000 * 100);
302 pass = get_migration_pass();
303 } while (pass == initial_pass && !got_stop);
306 static void check_guests_ram(void)
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).
315 unsigned address;
316 uint8_t first_byte;
317 uint8_t last_byte;
318 bool hit_edge = false;
319 bool bad = false;
321 qtest_memread(global_qtest, start_address, &first_byte, 1);
322 last_byte = first_byte;
324 for (address = start_address + 4096; address < end_address; address += 4096)
326 uint8_t b;
327 qtest_memread(global_qtest, 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.
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;
343 last_byte = b;
345 g_assert_false(bad);
348 static void cleanup(const char *filename)
350 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
352 unlink(path);
355 static void test_migrate(void)
357 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
358 QTestState *global = global_qtest, *from, *to;
359 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
360 gchar *cmd, *cmd_src, *cmd_dst;
361 QDict *rsp;
363 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
364 const char *arch = qtest_get_arch();
366 got_stop = false;
368 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
369 init_bootfile_x86(bootpath);
370 cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
371 " -name pcsource,debug-threads=on"
372 " -serial file:%s/src_serial"
373 " -drive file=%s,format=raw",
374 tmpfs, bootpath);
375 cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
376 " -name pcdest,debug-threads=on"
377 " -serial file:%s/dest_serial"
378 " -drive file=%s,format=raw"
379 " -incoming %s",
380 tmpfs, bootpath, uri);
381 } else if (strcmp(arch, "ppc64") == 0) {
382 init_bootfile_ppc(bootpath);
383 cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 256M"
384 " -name pcsource,debug-threads=on"
385 " -serial file:%s/src_serial"
386 " -drive file=%s,if=pflash,format=raw",
387 tmpfs, bootpath);
388 cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 256M"
389 " -name pcdest,debug-threads=on"
390 " -serial file:%s/dest_serial"
391 " -incoming %s",
392 tmpfs, uri);
393 } else {
394 g_assert_not_reached();
397 from = qtest_start(cmd_src);
398 g_free(cmd_src);
400 to = qtest_init(cmd_dst);
401 g_free(cmd_dst);
403 global_qtest = from;
404 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
405 "'arguments': { "
406 "'capabilities': [ {"
407 "'capability': 'postcopy-ram',"
408 "'state': true } ] } }");
409 g_assert(qdict_haskey(rsp, "return"));
410 QDECREF(rsp);
412 global_qtest = to;
413 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
414 "'arguments': { "
415 "'capabilities': [ {"
416 "'capability': 'postcopy-ram',"
417 "'state': true } ] } }");
418 g_assert(qdict_haskey(rsp, "return"));
419 QDECREF(rsp);
421 /* We want to pick a speed slow enough that the test completes
422 * quickly, but that it doesn't complete precopy even on a slow
423 * machine, so also set the downtime.
425 global_qtest = from;
426 rsp = qmp("{ 'execute': 'migrate_set_speed',"
427 "'arguments': { 'value': 100000000 } }");
428 g_assert(qdict_haskey(rsp, "return"));
429 QDECREF(rsp);
431 /* 1ms downtime - it should never finish precopy */
432 rsp = qmp("{ 'execute': 'migrate_set_downtime',"
433 "'arguments': { 'value': 0.001 } }");
434 g_assert(qdict_haskey(rsp, "return"));
435 QDECREF(rsp);
438 /* Wait for the first serial output from the source */
439 wait_for_serial("src_serial");
441 cmd = g_strdup_printf("{ 'execute': 'migrate',"
442 "'arguments': { 'uri': '%s' } }",
443 uri);
444 rsp = qmp(cmd);
445 g_free(cmd);
446 g_assert(qdict_haskey(rsp, "return"));
447 QDECREF(rsp);
449 wait_for_migration_pass();
451 rsp = return_or_event(qmp("{ 'execute': 'migrate-start-postcopy' }"));
452 g_assert(qdict_haskey(rsp, "return"));
453 QDECREF(rsp);
455 if (!got_stop) {
456 qmp_eventwait("STOP");
459 global_qtest = to;
460 qmp_eventwait("RESUME");
462 wait_for_serial("dest_serial");
463 global_qtest = from;
464 wait_for_migration_complete();
466 qtest_quit(from);
468 global_qtest = to;
470 qtest_memread(to, start_address, &dest_byte_a, 1);
472 /* Destination still running, wait for a byte to change */
473 do {
474 qtest_memread(to, start_address, &dest_byte_b, 1);
475 usleep(10 * 1000);
476 } while (dest_byte_a == dest_byte_b);
478 qmp("{ 'execute' : 'stop'}");
479 /* With it stopped, check nothing changes */
480 qtest_memread(to, start_address, &dest_byte_c, 1);
481 sleep(1);
482 qtest_memread(to, start_address, &dest_byte_d, 1);
483 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
485 check_guests_ram();
487 qtest_quit(to);
488 g_free(uri);
490 global_qtest = global;
492 cleanup("bootsect");
493 cleanup("migsocket");
494 cleanup("src_serial");
495 cleanup("dest_serial");
498 int main(int argc, char **argv)
500 char template[] = "/tmp/postcopy-test-XXXXXX";
501 int ret;
503 g_test_init(&argc, &argv, NULL);
505 if (!ufd_version_check()) {
506 return 0;
509 tmpfs = mkdtemp(template);
510 if (!tmpfs) {
511 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
513 g_assert(tmpfs);
515 module_call_init(MODULE_INIT_QOM);
517 qtest_add_func("/postcopy", test_migrate);
519 ret = g_test_run();
521 g_assert_cmpint(ret, ==, 0);
523 ret = rmdir(tmpfs);
524 if (ret != 0) {
525 g_test_message("unable to rmdir: path (%s): %s\n",
526 tmpfs, strerror(errno));
529 return ret;