block: use the block job list in qmp_query_block_jobs()
[qemu/ar7.git] / tests / postcopy-test.c
blob9ff88eea0fe220c8ab755f30d90def5c393ccd31
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"
14 #include <glib.h>
16 #include "libqtest.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;
26 bool got_stop;
28 #if defined(__linux__)
29 #include <sys/mman.h>
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
129 * Wait for some output in the serial output file,
130 * we get an 'A' followed by an endless string of 'B's
131 * but on the destination we won't have the A.
133 static void wait_for_serial(const char *side)
135 char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
136 FILE *serialfile = fopen(serialpath, "r");
138 do {
139 int readvalue = fgetc(serialfile);
141 switch (readvalue) {
142 case 'A':
143 /* Fine */
144 break;
146 case 'B':
147 /* It's alive! */
148 fclose(serialfile);
149 g_free(serialpath);
150 return;
152 case EOF:
153 fseek(serialfile, 0, SEEK_SET);
154 usleep(1000);
155 break;
157 default:
158 fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
159 g_assert_not_reached();
161 } while (true);
165 * Events can get in the way of responses we are actually waiting for.
167 static QDict *return_or_event(QDict *response)
169 const char *event_string;
170 if (!qdict_haskey(response, "event")) {
171 return response;
174 /* OK, it was an event */
175 event_string = qdict_get_str(response, "event");
176 if (!strcmp(event_string, "STOP")) {
177 got_stop = true;
179 QDECREF(response);
180 return return_or_event(qtest_qmp_receive(global_qtest));
185 * It's tricky to use qemu's migration event capability with qtest,
186 * events suddenly appearing confuse the qmp()/hmp() responses.
187 * so wait for a couple of passes to have happened before
188 * going postcopy.
191 static uint64_t get_migration_pass(void)
193 QDict *rsp, *rsp_return, *rsp_ram;
194 uint64_t result;
196 rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }"));
197 rsp_return = qdict_get_qdict(rsp, "return");
198 if (!qdict_haskey(rsp_return, "ram")) {
199 /* Still in setup */
200 result = 0;
201 } else {
202 rsp_ram = qdict_get_qdict(rsp_return, "ram");
203 result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0);
204 QDECREF(rsp);
206 return result;
209 static void wait_for_migration_complete(void)
211 QDict *rsp, *rsp_return;
212 bool completed;
214 do {
215 const char *status;
217 rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }"));
218 rsp_return = qdict_get_qdict(rsp, "return");
219 status = qdict_get_str(rsp_return, "status");
220 completed = strcmp(status, "completed") == 0;
221 g_assert_cmpstr(status, !=, "failed");
222 QDECREF(rsp);
223 usleep(1000 * 100);
224 } while (!completed);
227 static void wait_for_migration_pass(void)
229 uint64_t initial_pass = get_migration_pass();
230 uint64_t pass;
232 /* Wait for the 1st sync */
233 do {
234 initial_pass = get_migration_pass();
235 if (got_stop || initial_pass) {
236 break;
238 usleep(1000 * 100);
239 } while (true);
241 do {
242 usleep(1000 * 100);
243 pass = get_migration_pass();
244 } while (pass == initial_pass && !got_stop);
247 static void check_guests_ram(void)
249 /* Our ASM test will have been incrementing one byte from each page from
250 * 1MB to <100MB in order.
251 * This gives us a constraint that any page's byte should be equal or less
252 * than the previous pages byte (mod 256); and they should all be equal
253 * except for one transition at the point where we meet the incrementer.
254 * (We're running this with the guest stopped).
256 unsigned address;
257 uint8_t first_byte;
258 uint8_t last_byte;
259 bool hit_edge = false;
260 bool bad = false;
262 qtest_memread(global_qtest, start_address, &first_byte, 1);
263 last_byte = first_byte;
265 for (address = start_address + 4096; address < end_address; address += 4096)
267 uint8_t b;
268 qtest_memread(global_qtest, address, &b, 1);
269 if (b != last_byte) {
270 if (((b + 1) % 256) == last_byte && !hit_edge) {
271 /* This is OK, the guest stopped at the point of
272 * incrementing the previous page but didn't get
273 * to us yet.
275 hit_edge = true;
276 } else {
277 fprintf(stderr, "Memory content inconsistency at %x"
278 " first_byte = %x last_byte = %x current = %x"
279 " hit_edge = %x\n",
280 address, first_byte, last_byte, b, hit_edge);
281 bad = true;
284 last_byte = b;
286 g_assert_false(bad);
289 static void cleanup(const char *filename)
291 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
293 unlink(path);
296 static void test_migrate(void)
298 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
299 QTestState *global = global_qtest, *from, *to;
300 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
301 gchar *cmd;
302 QDict *rsp;
304 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
305 FILE *bootfile = fopen(bootpath, "wb");
307 got_stop = false;
308 g_assert_cmpint(fwrite(bootsect, 512, 1, bootfile), ==, 1);
309 fclose(bootfile);
311 cmd = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
312 " -name pcsource,debug-threads=on"
313 " -serial file:%s/src_serial"
314 " -drive file=%s,format=raw",
315 tmpfs, bootpath);
316 from = qtest_start(cmd);
317 g_free(cmd);
319 cmd = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
320 " -name pcdest,debug-threads=on"
321 " -serial file:%s/dest_serial"
322 " -drive file=%s,format=raw"
323 " -incoming %s",
324 tmpfs, bootpath, uri);
325 to = qtest_init(cmd);
326 g_free(cmd);
328 global_qtest = from;
329 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
330 "'arguments': { "
331 "'capabilities': [ {"
332 "'capability': 'postcopy-ram',"
333 "'state': true } ] } }");
334 g_assert(qdict_haskey(rsp, "return"));
335 QDECREF(rsp);
337 global_qtest = to;
338 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
339 "'arguments': { "
340 "'capabilities': [ {"
341 "'capability': 'postcopy-ram',"
342 "'state': true } ] } }");
343 g_assert(qdict_haskey(rsp, "return"));
344 QDECREF(rsp);
346 /* We want to pick a speed slow enough that the test completes
347 * quickly, but that it doesn't complete precopy even on a slow
348 * machine, so also set the downtime.
350 global_qtest = from;
351 rsp = qmp("{ 'execute': 'migrate_set_speed',"
352 "'arguments': { 'value': 100000000 } }");
353 g_assert(qdict_haskey(rsp, "return"));
354 QDECREF(rsp);
356 /* 1ms downtime - it should never finish precopy */
357 rsp = qmp("{ 'execute': 'migrate_set_downtime',"
358 "'arguments': { 'value': 0.001 } }");
359 g_assert(qdict_haskey(rsp, "return"));
360 QDECREF(rsp);
363 /* Wait for the first serial output from the source */
364 wait_for_serial("src_serial");
366 cmd = g_strdup_printf("{ 'execute': 'migrate',"
367 "'arguments': { 'uri': '%s' } }",
368 uri);
369 rsp = qmp(cmd);
370 g_free(cmd);
371 g_assert(qdict_haskey(rsp, "return"));
372 QDECREF(rsp);
374 wait_for_migration_pass();
376 rsp = return_or_event(qmp("{ 'execute': 'migrate-start-postcopy' }"));
377 g_assert(qdict_haskey(rsp, "return"));
378 QDECREF(rsp);
380 if (!got_stop) {
381 qmp_eventwait("STOP");
384 global_qtest = to;
385 qmp_eventwait("RESUME");
387 wait_for_serial("dest_serial");
388 global_qtest = from;
389 wait_for_migration_complete();
391 qtest_quit(from);
393 global_qtest = to;
395 qtest_memread(to, start_address, &dest_byte_a, 1);
397 /* Destination still running, wait for a byte to change */
398 do {
399 qtest_memread(to, start_address, &dest_byte_b, 1);
400 usleep(10 * 1000);
401 } while (dest_byte_a == dest_byte_b);
403 qmp("{ 'execute' : 'stop'}");
404 /* With it stopped, check nothing changes */
405 qtest_memread(to, start_address, &dest_byte_c, 1);
406 sleep(1);
407 qtest_memread(to, start_address, &dest_byte_d, 1);
408 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
410 check_guests_ram();
412 qtest_quit(to);
413 g_free(uri);
415 global_qtest = global;
417 cleanup("bootsect");
418 cleanup("migsocket");
419 cleanup("src_serial");
420 cleanup("dest_serial");
423 int main(int argc, char **argv)
425 char template[] = "/tmp/postcopy-test-XXXXXX";
426 int ret;
428 g_test_init(&argc, &argv, NULL);
430 if (!ufd_version_check()) {
431 return 0;
434 tmpfs = mkdtemp(template);
435 if (!tmpfs) {
436 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
438 g_assert(tmpfs);
440 module_call_init(MODULE_INIT_QOM);
442 qtest_add_func("/postcopy", test_migrate);
444 ret = g_test_run();
446 g_assert_cmpint(ret, ==, 0);
448 ret = rmdir(tmpfs);
449 if (ret != 0) {
450 g_test_message("unable to rmdir: path (%s): %s\n",
451 tmpfs, strerror(errno));
454 return ret;