]> git.proxmox.com Git - mirror_qemu.git/blame - tests/postcopy-test.c
virtio-pci: error out when both legacy and modern modes are disabled
[mirror_qemu.git] / tests / postcopy-test.c
CommitLineData
ea0c6d62
DDAG
1/*
2 * QTest testcase for postcopy
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"
ea0c6d62
DDAG
14
15#include "libqtest.h"
16#include "qemu/option.h"
17#include "qemu/range.h"
a9c94277 18#include "qemu/sockets.h"
ea0c6d62
DDAG
19#include "sysemu/char.h"
20#include "sysemu/sysemu.h"
aaf89c8a 21#include "hw/nvram/openbios_firmware_abi.h"
22
23#define MIN_NVRAM_SIZE 8192 /* from spapr_nvram.c */
ea0c6d62 24
ea0c6d62
DDAG
25const unsigned start_address = 1024 * 1024;
26const unsigned end_address = 100 * 1024 * 1024;
27bool got_stop;
28
29#if defined(__linux__)
ea0c6d62
DDAG
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
39static bool ufd_version_check(void)
40{
41 struct uffdio_api api_struct;
42 uint64_t ioctl_mask;
43
44 int ufd = 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
69static bool ufd_version_check(void)
70{
71 g_test_message("Skipping test: Userfault not available (builtdtime)");
72 return false;
73}
74
75#endif
76
77static 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 */
82unsigned 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
aaf89c8a 128static 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
136static void init_bootfile_ppc(const char *bootpath)
137{
138 FILE *bootfile;
139 char buf[MIN_NVRAM_SIZE];
140 struct OpenBIOS_nvpart_v1 *header = (struct OpenBIOS_nvpart_v1 *)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 = OPENBIOS_PART_SYSTEM;
147 memcpy(header->name, "common", 6);
148 OpenBIOS_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
ea0c6d62
DDAG
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 */
171static void wait_for_serial(const char *side)
172{
173 char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
174 FILE *serialfile = fopen(serialpath, "r");
aaf89c8a 175 const char *arch = qtest_get_arch();
176 int started = (strcmp(side, "src_serial") == 0 &&
177 strcmp(arch, "ppc64") == 0) ? 0 : 1;
ea0c6d62 178
e2dd21e5 179 g_free(serialpath);
ea0c6d62
DDAG
180 do {
181 int readvalue = fgetc(serialfile);
182
aaf89c8a 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 }
ea0c6d62
DDAG
199 switch (readvalue) {
200 case 'A':
201 /* Fine */
202 break;
203
204 case 'B':
205 /* It's alive! */
206 fclose(serialfile);
ea0c6d62
DDAG
207 return;
208
209 case EOF:
aaf89c8a 210 started = (strcmp(side, "src_serial") == 0 &&
211 strcmp(arch, "ppc64") == 0) ? 0 : 1;
ea0c6d62
DDAG
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 */
226static QDict *return_or_event(QDict *response)
227{
228 const char *event_string;
229 if (!qdict_haskey(response, "event")) {
230 return response;
231 }
232
233 /* OK, it was an event */
234 event_string = qdict_get_str(response, "event");
235 if (!strcmp(event_string, "STOP")) {
236 got_stop = true;
237 }
238 QDECREF(response);
239 return return_or_event(qtest_qmp_receive(global_qtest));
240}
241
242
243/*
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.
248 */
249
250static uint64_t get_migration_pass(void)
251{
252 QDict *rsp, *rsp_return, *rsp_ram;
253 uint64_t result;
254
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);
ea0c6d62 263 }
5b1ded22 264 QDECREF(rsp);
ea0c6d62
DDAG
265 return result;
266}
267
268static void wait_for_migration_complete(void)
269{
270 QDict *rsp, *rsp_return;
271 bool completed;
272
273 do {
274 const char *status;
275
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);
284}
285
286static void wait_for_migration_pass(void)
287{
288 uint64_t initial_pass = get_migration_pass();
289 uint64_t pass;
290
291 /* Wait for the 1st sync */
292 do {
293 initial_pass = get_migration_pass();
294 if (got_stop || initial_pass) {
295 break;
296 }
297 usleep(1000 * 100);
298 } while (true);
299
300 do {
301 usleep(1000 * 100);
302 pass = get_migration_pass();
303 } while (pass == initial_pass && !got_stop);
304}
305
306static void check_guests_ram(void)
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(global_qtest, 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(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.
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
348static void cleanup(const char *filename)
349{
350 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
351
352 unlink(path);
e2dd21e5 353 g_free(path);
ea0c6d62
DDAG
354}
355
356static void test_migrate(void)
357{
358 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
359 QTestState *global = global_qtest, *from, *to;
360 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
aaf89c8a 361 gchar *cmd, *cmd_src, *cmd_dst;
ea0c6d62
DDAG
362 QDict *rsp;
363
364 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
aaf89c8a 365 const char *arch = qtest_get_arch();
ea0c6d62
DDAG
366
367 got_stop = false;
ea0c6d62 368
aaf89c8a 369 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
370 init_bootfile_x86(bootpath);
371 cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
372 " -name pcsource,debug-threads=on"
373 " -serial file:%s/src_serial"
374 " -drive file=%s,format=raw",
375 tmpfs, bootpath);
376 cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
377 " -name pcdest,debug-threads=on"
378 " -serial file:%s/dest_serial"
379 " -drive file=%s,format=raw"
380 " -incoming %s",
381 tmpfs, bootpath, uri);
382 } else if (strcmp(arch, "ppc64") == 0) {
383 init_bootfile_ppc(bootpath);
384 cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 256M"
385 " -name pcsource,debug-threads=on"
386 " -serial file:%s/src_serial"
387 " -drive file=%s,if=pflash,format=raw",
388 tmpfs, bootpath);
389 cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 256M"
390 " -name pcdest,debug-threads=on"
391 " -serial file:%s/dest_serial"
392 " -incoming %s",
393 tmpfs, uri);
394 } else {
395 g_assert_not_reached();
396 }
397
e2dd21e5
MAL
398 g_free(bootpath);
399
aaf89c8a 400 from = qtest_start(cmd_src);
401 g_free(cmd_src);
402
403 to = qtest_init(cmd_dst);
404 g_free(cmd_dst);
ea0c6d62
DDAG
405
406 global_qtest = from;
407 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
408 "'arguments': { "
409 "'capabilities': [ {"
410 "'capability': 'postcopy-ram',"
411 "'state': true } ] } }");
412 g_assert(qdict_haskey(rsp, "return"));
413 QDECREF(rsp);
414
415 global_qtest = to;
416 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
417 "'arguments': { "
418 "'capabilities': [ {"
419 "'capability': 'postcopy-ram',"
420 "'state': true } ] } }");
421 g_assert(qdict_haskey(rsp, "return"));
422 QDECREF(rsp);
423
424 /* We want to pick a speed slow enough that the test completes
425 * quickly, but that it doesn't complete precopy even on a slow
426 * machine, so also set the downtime.
427 */
428 global_qtest = from;
429 rsp = qmp("{ 'execute': 'migrate_set_speed',"
430 "'arguments': { 'value': 100000000 } }");
431 g_assert(qdict_haskey(rsp, "return"));
432 QDECREF(rsp);
433
434 /* 1ms downtime - it should never finish precopy */
435 rsp = qmp("{ 'execute': 'migrate_set_downtime',"
436 "'arguments': { 'value': 0.001 } }");
437 g_assert(qdict_haskey(rsp, "return"));
438 QDECREF(rsp);
439
440
441 /* Wait for the first serial output from the source */
442 wait_for_serial("src_serial");
443
444 cmd = g_strdup_printf("{ 'execute': 'migrate',"
445 "'arguments': { 'uri': '%s' } }",
446 uri);
447 rsp = qmp(cmd);
448 g_free(cmd);
449 g_assert(qdict_haskey(rsp, "return"));
450 QDECREF(rsp);
451
452 wait_for_migration_pass();
453
454 rsp = return_or_event(qmp("{ 'execute': 'migrate-start-postcopy' }"));
455 g_assert(qdict_haskey(rsp, "return"));
456 QDECREF(rsp);
457
458 if (!got_stop) {
459 qmp_eventwait("STOP");
460 }
461
462 global_qtest = to;
463 qmp_eventwait("RESUME");
464
465 wait_for_serial("dest_serial");
466 global_qtest = from;
467 wait_for_migration_complete();
468
469 qtest_quit(from);
470
471 global_qtest = to;
472
473 qtest_memread(to, start_address, &dest_byte_a, 1);
474
475 /* Destination still running, wait for a byte to change */
476 do {
477 qtest_memread(to, start_address, &dest_byte_b, 1);
478 usleep(10 * 1000);
479 } while (dest_byte_a == dest_byte_b);
480
481 qmp("{ 'execute' : 'stop'}");
482 /* With it stopped, check nothing changes */
483 qtest_memread(to, start_address, &dest_byte_c, 1);
484 sleep(1);
485 qtest_memread(to, start_address, &dest_byte_d, 1);
486 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
487
488 check_guests_ram();
489
490 qtest_quit(to);
491 g_free(uri);
492
493 global_qtest = global;
494
495 cleanup("bootsect");
496 cleanup("migsocket");
497 cleanup("src_serial");
498 cleanup("dest_serial");
499}
500
501int main(int argc, char **argv)
502{
503 char template[] = "/tmp/postcopy-test-XXXXXX";
504 int ret;
505
506 g_test_init(&argc, &argv, NULL);
507
508 if (!ufd_version_check()) {
509 return 0;
510 }
511
512 tmpfs = mkdtemp(template);
513 if (!tmpfs) {
514 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
515 }
516 g_assert(tmpfs);
517
518 module_call_init(MODULE_INIT_QOM);
519
520 qtest_add_func("/postcopy", test_migrate);
521
522 ret = g_test_run();
523
524 g_assert_cmpint(ret, ==, 0);
525
526 ret = rmdir(tmpfs);
527 if (ret != 0) {
528 g_test_message("unable to rmdir: path (%s): %s\n",
529 tmpfs, strerror(errno));
530 }
531
532 return ret;
533}