]> git.proxmox.com Git - mirror_qemu.git/blame - tests/migration-test.c
tests: rename postcopy-test to migration-test
[mirror_qemu.git] / tests / migration-test.c
CommitLineData
ea0c6d62 1/*
2656bfd9 2 * QTest testcase for migration
ea0c6d62
DDAG
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"
8228e353 19#include "chardev/char.h"
ea0c6d62 20#include "sysemu/sysemu.h"
ad723fe5 21#include "hw/nvram/chrp_nvram.h"
aaf89c8a 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
e1ae9fb6 44 int ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
ea0c6d62
DDAG
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];
ad723fe5 140 ChrpNvramPartHdr *header = (ChrpNvramPartHdr *)buf;
aaf89c8a 141
142 memset(buf, 0, MIN_NVRAM_SIZE);
143
144 /* Create a "common" partition in nvram to store boot-command property */
145
ad723fe5 146 header->signature = CHRP_NVPART_SYSTEM;
aaf89c8a 147 memcpy(header->name, "common", 6);
ad723fe5 148 chrp_nvram_finish_partition(header, MIN_NVRAM_SIZE);
aaf89c8a 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.
ea0c6d62
DDAG
246 */
247
248static uint64_t get_migration_pass(void)
249{
250 QDict *rsp, *rsp_return, *rsp_ram;
251 uint64_t result;
252
253 rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }"));
254 rsp_return = qdict_get_qdict(rsp, "return");
255 if (!qdict_haskey(rsp_return, "ram")) {
256 /* Still in setup */
257 result = 0;
258 } else {
259 rsp_ram = qdict_get_qdict(rsp_return, "ram");
260 result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0);
ea0c6d62 261 }
5b1ded22 262 QDECREF(rsp);
ea0c6d62
DDAG
263 return result;
264}
265
266static void wait_for_migration_complete(void)
267{
268 QDict *rsp, *rsp_return;
269 bool completed;
270
271 do {
272 const char *status;
273
274 rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }"));
275 rsp_return = qdict_get_qdict(rsp, "return");
276 status = qdict_get_str(rsp_return, "status");
277 completed = strcmp(status, "completed") == 0;
278 g_assert_cmpstr(status, !=, "failed");
279 QDECREF(rsp);
280 usleep(1000 * 100);
281 } while (!completed);
282}
283
284static void wait_for_migration_pass(void)
285{
286 uint64_t initial_pass = get_migration_pass();
287 uint64_t pass;
288
289 /* Wait for the 1st sync */
290 do {
291 initial_pass = get_migration_pass();
292 if (got_stop || initial_pass) {
293 break;
294 }
295 usleep(1000 * 100);
296 } while (true);
297
298 do {
299 usleep(1000 * 100);
300 pass = get_migration_pass();
301 } while (pass == initial_pass && !got_stop);
302}
303
304static void check_guests_ram(void)
305{
306 /* Our ASM test will have been incrementing one byte from each page from
307 * 1MB to <100MB in order.
308 * This gives us a constraint that any page's byte should be equal or less
309 * than the previous pages byte (mod 256); and they should all be equal
310 * except for one transition at the point where we meet the incrementer.
311 * (We're running this with the guest stopped).
312 */
313 unsigned address;
314 uint8_t first_byte;
315 uint8_t last_byte;
316 bool hit_edge = false;
317 bool bad = false;
318
319 qtest_memread(global_qtest, start_address, &first_byte, 1);
320 last_byte = first_byte;
321
322 for (address = start_address + 4096; address < end_address; address += 4096)
323 {
324 uint8_t b;
325 qtest_memread(global_qtest, address, &b, 1);
326 if (b != last_byte) {
327 if (((b + 1) % 256) == last_byte && !hit_edge) {
328 /* This is OK, the guest stopped at the point of
329 * incrementing the previous page but didn't get
330 * to us yet.
331 */
332 hit_edge = true;
333 } else {
334 fprintf(stderr, "Memory content inconsistency at %x"
335 " first_byte = %x last_byte = %x current = %x"
336 " hit_edge = %x\n",
337 address, first_byte, last_byte, b, hit_edge);
338 bad = true;
339 }
340 }
341 last_byte = b;
342 }
343 g_assert_false(bad);
344}
345
346static void cleanup(const char *filename)
347{
348 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
349
350 unlink(path);
e2dd21e5 351 g_free(path);
ea0c6d62
DDAG
352}
353
354static void test_migrate(void)
355{
356 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
357 QTestState *global = global_qtest, *from, *to;
358 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
aaf89c8a 359 gchar *cmd, *cmd_src, *cmd_dst;
ea0c6d62
DDAG
360 QDict *rsp;
361
362 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
aaf89c8a 363 const char *arch = qtest_get_arch();
ea0c6d62
DDAG
364
365 got_stop = false;
ea0c6d62 366
aaf89c8a 367 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
368 init_bootfile_x86(bootpath);
369 cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
370 " -name pcsource,debug-threads=on"
371 " -serial file:%s/src_serial"
372 " -drive file=%s,format=raw",
373 tmpfs, bootpath);
374 cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
375 " -name pcdest,debug-threads=on"
376 " -serial file:%s/dest_serial"
377 " -drive file=%s,format=raw"
378 " -incoming %s",
379 tmpfs, bootpath, uri);
380 } else if (strcmp(arch, "ppc64") == 0) {
171da9d5
TH
381 const char *accel;
382
383 /* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
384 accel = access("/sys/module/kvm_hv", F_OK) ? "tcg" : "kvm:tcg";
aaf89c8a 385 init_bootfile_ppc(bootpath);
171da9d5 386 cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
aaf89c8a 387 " -name pcsource,debug-threads=on"
388 " -serial file:%s/src_serial"
389 " -drive file=%s,if=pflash,format=raw",
171da9d5
TH
390 accel, tmpfs, bootpath);
391 cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
aaf89c8a 392 " -name pcdest,debug-threads=on"
393 " -serial file:%s/dest_serial"
394 " -incoming %s",
171da9d5 395 accel, tmpfs, uri);
aaf89c8a 396 } else {
397 g_assert_not_reached();
398 }
399
e2dd21e5
MAL
400 g_free(bootpath);
401
aaf89c8a 402 from = qtest_start(cmd_src);
403 g_free(cmd_src);
404
405 to = qtest_init(cmd_dst);
406 g_free(cmd_dst);
ea0c6d62
DDAG
407
408 global_qtest = from;
409 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
410 "'arguments': { "
411 "'capabilities': [ {"
412 "'capability': 'postcopy-ram',"
413 "'state': true } ] } }");
414 g_assert(qdict_haskey(rsp, "return"));
415 QDECREF(rsp);
416
417 global_qtest = to;
418 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
419 "'arguments': { "
420 "'capabilities': [ {"
421 "'capability': 'postcopy-ram',"
422 "'state': true } ] } }");
423 g_assert(qdict_haskey(rsp, "return"));
424 QDECREF(rsp);
425
426 /* We want to pick a speed slow enough that the test completes
427 * quickly, but that it doesn't complete precopy even on a slow
428 * machine, so also set the downtime.
429 */
430 global_qtest = from;
431 rsp = qmp("{ 'execute': 'migrate_set_speed',"
432 "'arguments': { 'value': 100000000 } }");
433 g_assert(qdict_haskey(rsp, "return"));
434 QDECREF(rsp);
435
436 /* 1ms downtime - it should never finish precopy */
437 rsp = qmp("{ 'execute': 'migrate_set_downtime',"
438 "'arguments': { 'value': 0.001 } }");
439 g_assert(qdict_haskey(rsp, "return"));
440 QDECREF(rsp);
441
442
443 /* Wait for the first serial output from the source */
444 wait_for_serial("src_serial");
445
446 cmd = g_strdup_printf("{ 'execute': 'migrate',"
447 "'arguments': { 'uri': '%s' } }",
448 uri);
449 rsp = qmp(cmd);
450 g_free(cmd);
451 g_assert(qdict_haskey(rsp, "return"));
452 QDECREF(rsp);
453
454 wait_for_migration_pass();
455
456 rsp = return_or_event(qmp("{ 'execute': 'migrate-start-postcopy' }"));
457 g_assert(qdict_haskey(rsp, "return"));
458 QDECREF(rsp);
459
460 if (!got_stop) {
461 qmp_eventwait("STOP");
462 }
463
464 global_qtest = to;
465 qmp_eventwait("RESUME");
466
467 wait_for_serial("dest_serial");
468 global_qtest = from;
469 wait_for_migration_complete();
470
471 qtest_quit(from);
472
473 global_qtest = to;
474
475 qtest_memread(to, start_address, &dest_byte_a, 1);
476
477 /* Destination still running, wait for a byte to change */
478 do {
479 qtest_memread(to, start_address, &dest_byte_b, 1);
480 usleep(10 * 1000);
481 } while (dest_byte_a == dest_byte_b);
482
dc491fea 483 qmp_discard_response("{ 'execute' : 'stop'}");
ea0c6d62
DDAG
484 /* With it stopped, check nothing changes */
485 qtest_memread(to, start_address, &dest_byte_c, 1);
486 sleep(1);
487 qtest_memread(to, start_address, &dest_byte_d, 1);
488 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
489
490 check_guests_ram();
491
492 qtest_quit(to);
493 g_free(uri);
494
495 global_qtest = global;
496
497 cleanup("bootsect");
498 cleanup("migsocket");
499 cleanup("src_serial");
500 cleanup("dest_serial");
501}
502
503int main(int argc, char **argv)
504{
2656bfd9 505 char template[] = "/tmp/migration-test-XXXXXX";
ea0c6d62
DDAG
506 int ret;
507
508 g_test_init(&argc, &argv, NULL);
509
510 if (!ufd_version_check()) {
511 return 0;
512 }
513
514 tmpfs = mkdtemp(template);
515 if (!tmpfs) {
516 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
517 }
518 g_assert(tmpfs);
519
520 module_call_init(MODULE_INIT_QOM);
521
2656bfd9 522 qtest_add_func("/migration/postcopy/unix", test_migrate);
ea0c6d62
DDAG
523
524 ret = g_test_run();
525
526 g_assert_cmpint(ret, ==, 0);
527
528 ret = rmdir(tmpfs);
529 if (ret != 0) {
530 g_test_message("unable to rmdir: path (%s): %s\n",
531 tmpfs, strerror(errno));
532 }
533
534 return ret;
535}