1
2
3
4
5
6
7
8
9
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
24
25const unsigned start_address = 1024 * 1024;
26const unsigned end_address = 100 * 1024 * 1024;
27bool 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
39static 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
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
80
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
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 ChrpNvramPartHdr *header = (ChrpNvramPartHdr *)buf;
141
142 memset(buf, 0, MIN_NVRAM_SIZE);
143
144
145
146 header->signature = CHRP_NVPART_SYSTEM;
147 memcpy(header->name, "common", 6);
148 chrp_nvram_finish_partition(header, MIN_NVRAM_SIZE);
149
150
151
152
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
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
168
169
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");
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
185
186
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
202 break;
203
204 case 'B':
205
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
225
226static 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
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
248
249
250
251static 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
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
269static 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
287static void wait_for_migration_pass(QTestState *who)
288{
289 uint64_t initial_pass = get_migration_pass(who);
290 uint64_t pass;
291
292
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
307static void check_guests_ram(QTestState *who)
308{
309
310
311
312
313
314
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
332
333
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
349static 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
357static void migrate_check_parameter(QTestState *who, const char *parameter,
358 const char *value)
359{
360 QDict *rsp, *rsp_return;
361 const 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 QDECREF(rsp);
369}
370
371static void migrate_set_downtime(QTestState *who, const double value)
372{
373 QDict *rsp;
374 gchar *cmd;
375 char *expected;
376 int64_t result_int;
377
378 cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime',"
379 "'arguments': { 'value': %g } }", value);
380 rsp = qtest_qmp(who, cmd);
381 g_free(cmd);
382 g_assert(qdict_haskey(rsp, "return"));
383 QDECREF(rsp);
384 result_int = value * 1000L;
385 expected = g_strdup_printf("%" PRId64, result_int);
386 migrate_check_parameter(who, "downtime-limit", expected);
387 g_free(expected);
388}
389
390static void migrate_set_speed(QTestState *who, const char *value)
391{
392 QDict *rsp;
393 gchar *cmd;
394
395 cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed',"
396 "'arguments': { 'value': %s } }", value);
397 rsp = qtest_qmp(who, cmd);
398 g_free(cmd);
399 g_assert(qdict_haskey(rsp, "return"));
400 QDECREF(rsp);
401 migrate_check_parameter(who, "max-bandwidth", value);
402}
403
404static void migrate_set_capability(QTestState *who, const char *capability,
405 const char *value)
406{
407 QDict *rsp;
408 gchar *cmd;
409
410 cmd = g_strdup_printf("{ 'execute': 'migrate-set-capabilities',"
411 "'arguments': { "
412 "'capabilities': [ { "
413 "'capability': '%s', 'state': %s } ] } }",
414 capability, value);
415 rsp = qtest_qmp(who, cmd);
416 g_free(cmd);
417 g_assert(qdict_haskey(rsp, "return"));
418 QDECREF(rsp);
419}
420
421static void migrate(QTestState *who, const char *uri)
422{
423 QDict *rsp;
424 gchar *cmd;
425
426 cmd = g_strdup_printf("{ 'execute': 'migrate',"
427 "'arguments': { 'uri': '%s' } }",
428 uri);
429 rsp = qtest_qmp(who, cmd);
430 g_free(cmd);
431 g_assert(qdict_haskey(rsp, "return"));
432 QDECREF(rsp);
433}
434
435static void test_migrate_start(QTestState **from, QTestState **to,
436 const char *uri)
437{
438 gchar *cmd_src, *cmd_dst;
439 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
440 const char *arch = qtest_get_arch();
441
442 got_stop = false;
443
444 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
445 init_bootfile_x86(bootpath);
446 cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
447 " -name pcsource,debug-threads=on"
448 " -serial file:%s/src_serial"
449 " -drive file=%s,format=raw",
450 tmpfs, bootpath);
451 cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
452 " -name pcdest,debug-threads=on"
453 " -serial file:%s/dest_serial"
454 " -drive file=%s,format=raw"
455 " -incoming %s",
456 tmpfs, bootpath, uri);
457 } else if (strcmp(arch, "ppc64") == 0) {
458 const char *accel;
459
460
461 accel = access("/sys/module/kvm_hv", F_OK) ? "tcg" : "kvm:tcg";
462 init_bootfile_ppc(bootpath);
463 cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
464 " -name pcsource,debug-threads=on"
465 " -serial file:%s/src_serial"
466 " -drive file=%s,if=pflash,format=raw",
467 accel, tmpfs, bootpath);
468 cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
469 " -name pcdest,debug-threads=on"
470 " -serial file:%s/dest_serial"
471 " -incoming %s",
472 accel, tmpfs, uri);
473 } else {
474 g_assert_not_reached();
475 }
476
477 g_free(bootpath);
478
479 *from = qtest_start(cmd_src);
480 g_free(cmd_src);
481
482 *to = qtest_init(cmd_dst);
483 g_free(cmd_dst);
484}
485
486static void test_migrate_end(QTestState *from, QTestState *to)
487{
488 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
489
490 qtest_quit(from);
491
492 qtest_memread(to, start_address, &dest_byte_a, 1);
493
494
495 do {
496 qtest_memread(to, start_address, &dest_byte_b, 1);
497 usleep(10 * 1000);
498 } while (dest_byte_a == dest_byte_b);
499
500 qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
501
502 qtest_memread(to, start_address, &dest_byte_c, 1);
503 sleep(1);
504 qtest_memread(to, start_address, &dest_byte_d, 1);
505 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
506
507 check_guests_ram(to);
508
509 qtest_quit(to);
510
511 cleanup("bootsect");
512 cleanup("migsocket");
513 cleanup("src_serial");
514 cleanup("dest_serial");
515}
516
517static void test_migrate(void)
518{
519 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
520 QTestState *from, *to;
521 QDict *rsp;
522
523 test_migrate_start(&from, &to, uri);
524
525 migrate_set_capability(from, "postcopy-ram", "true");
526 migrate_set_capability(to, "postcopy-ram", "true");
527
528
529
530
531
532 migrate_set_speed(from, "100000000");
533 migrate_set_downtime(from, 0.001);
534
535
536 wait_for_serial("src_serial");
537
538 migrate(from, uri);
539
540 wait_for_migration_pass(from);
541
542 rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
543 g_assert(qdict_haskey(rsp, "return"));
544 QDECREF(rsp);
545
546 if (!got_stop) {
547 qtest_qmp_eventwait(from, "STOP");
548 }
549
550 qtest_qmp_eventwait(to, "RESUME");
551
552 wait_for_serial("dest_serial");
553 wait_for_migration_complete(from);
554
555 g_free(uri);
556
557 test_migrate_end(from, to);
558}
559
560int main(int argc, char **argv)
561{
562 char template[] = "/tmp/migration-test-XXXXXX";
563 int ret;
564
565 g_test_init(&argc, &argv, NULL);
566
567 if (!ufd_version_check()) {
568 return 0;
569 }
570
571 tmpfs = mkdtemp(template);
572 if (!tmpfs) {
573 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
574 }
575 g_assert(tmpfs);
576
577 module_call_init(MODULE_INIT_QOM);
578
579 qtest_add_func("/migration/postcopy/unix", test_migrate);
580
581 ret = g_test_run();
582
583 g_assert_cmpint(ret, ==, 0);
584
585 ret = rmdir(tmpfs);
586 if (ret != 0) {
587 g_test_message("unable to rmdir: path (%s): %s\n",
588 tmpfs, strerror(errno));
589 }
590
591 return ret;
592}
593