]> git.proxmox.com Git - mirror_qemu.git/blob - tests/postcopy-test.c
Use #include "..." for our own headers, <...> for others
[mirror_qemu.git] / tests / postcopy-test.c
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"
14
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
22 const unsigned start_address = 1024 * 1024;
23 const unsigned end_address = 100 * 1024 * 1024;
24 bool got_stop;
25
26 #if defined(__linux__)
27 #include <sys/syscall.h>
28 #include <sys/vfs.h>
29 #endif
30
31 #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
32 #include <sys/eventfd.h>
33 #include <sys/ioctl.h>
34 #include <linux/userfaultfd.h>
35
36 static bool ufd_version_check(void)
37 {
38 struct uffdio_api api_struct;
39 uint64_t ioctl_mask;
40
41 int ufd = ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
42
43 if (ufd == -1) {
44 g_test_message("Skipping test: userfaultfd not available");
45 return false;
46 }
47
48 api_struct.api = UFFD_API;
49 api_struct.features = 0;
50 if (ioctl(ufd, UFFDIO_API, &api_struct)) {
51 g_test_message("Skipping test: UFFDIO_API failed");
52 return false;
53 }
54
55 ioctl_mask = (__u64)1 << _UFFDIO_REGISTER |
56 (__u64)1 << _UFFDIO_UNREGISTER;
57 if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
58 g_test_message("Skipping test: Missing userfault feature");
59 return false;
60 }
61
62 return true;
63 }
64
65 #else
66 static bool ufd_version_check(void)
67 {
68 g_test_message("Skipping test: Userfault not available (builtdtime)");
69 return false;
70 }
71
72 #endif
73
74 static const char *tmpfs;
75
76 /* A simple PC boot sector that modifies memory (1-100MB) quickly
77 * outputing a 'B' every so often if it's still running.
78 */
79 unsigned char bootsect[] = {
80 0xfa, 0x0f, 0x01, 0x16, 0x74, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00,
81 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02,
83 0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41,
84 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10,
85 0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40,
86 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x75, 0xe9, 0x66, 0xb8, 0x42, 0x00, 0x66,
87 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xde, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00,
88 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00,
89 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x5c, 0x7c,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x55, 0xaa
123 };
124
125 /*
126 * Wait for some output in the serial output file,
127 * we get an 'A' followed by an endless string of 'B's
128 * but on the destination we won't have the A.
129 */
130 static void wait_for_serial(const char *side)
131 {
132 char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
133 FILE *serialfile = fopen(serialpath, "r");
134
135 do {
136 int readvalue = fgetc(serialfile);
137
138 switch (readvalue) {
139 case 'A':
140 /* Fine */
141 break;
142
143 case 'B':
144 /* It's alive! */
145 fclose(serialfile);
146 g_free(serialpath);
147 return;
148
149 case EOF:
150 fseek(serialfile, 0, SEEK_SET);
151 usleep(1000);
152 break;
153
154 default:
155 fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
156 g_assert_not_reached();
157 }
158 } while (true);
159 }
160
161 /*
162 * Events can get in the way of responses we are actually waiting for.
163 */
164 static QDict *return_or_event(QDict *response)
165 {
166 const char *event_string;
167 if (!qdict_haskey(response, "event")) {
168 return response;
169 }
170
171 /* OK, it was an event */
172 event_string = qdict_get_str(response, "event");
173 if (!strcmp(event_string, "STOP")) {
174 got_stop = true;
175 }
176 QDECREF(response);
177 return return_or_event(qtest_qmp_receive(global_qtest));
178 }
179
180
181 /*
182 * It's tricky to use qemu's migration event capability with qtest,
183 * events suddenly appearing confuse the qmp()/hmp() responses.
184 * so wait for a couple of passes to have happened before
185 * going postcopy.
186 */
187
188 static uint64_t get_migration_pass(void)
189 {
190 QDict *rsp, *rsp_return, *rsp_ram;
191 uint64_t result;
192
193 rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }"));
194 rsp_return = qdict_get_qdict(rsp, "return");
195 if (!qdict_haskey(rsp_return, "ram")) {
196 /* Still in setup */
197 result = 0;
198 } else {
199 rsp_ram = qdict_get_qdict(rsp_return, "ram");
200 result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0);
201 QDECREF(rsp);
202 }
203 return result;
204 }
205
206 static void wait_for_migration_complete(void)
207 {
208 QDict *rsp, *rsp_return;
209 bool completed;
210
211 do {
212 const char *status;
213
214 rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }"));
215 rsp_return = qdict_get_qdict(rsp, "return");
216 status = qdict_get_str(rsp_return, "status");
217 completed = strcmp(status, "completed") == 0;
218 g_assert_cmpstr(status, !=, "failed");
219 QDECREF(rsp);
220 usleep(1000 * 100);
221 } while (!completed);
222 }
223
224 static void wait_for_migration_pass(void)
225 {
226 uint64_t initial_pass = get_migration_pass();
227 uint64_t pass;
228
229 /* Wait for the 1st sync */
230 do {
231 initial_pass = get_migration_pass();
232 if (got_stop || initial_pass) {
233 break;
234 }
235 usleep(1000 * 100);
236 } while (true);
237
238 do {
239 usleep(1000 * 100);
240 pass = get_migration_pass();
241 } while (pass == initial_pass && !got_stop);
242 }
243
244 static void check_guests_ram(void)
245 {
246 /* Our ASM test will have been incrementing one byte from each page from
247 * 1MB to <100MB in order.
248 * This gives us a constraint that any page's byte should be equal or less
249 * than the previous pages byte (mod 256); and they should all be equal
250 * except for one transition at the point where we meet the incrementer.
251 * (We're running this with the guest stopped).
252 */
253 unsigned address;
254 uint8_t first_byte;
255 uint8_t last_byte;
256 bool hit_edge = false;
257 bool bad = false;
258
259 qtest_memread(global_qtest, start_address, &first_byte, 1);
260 last_byte = first_byte;
261
262 for (address = start_address + 4096; address < end_address; address += 4096)
263 {
264 uint8_t b;
265 qtest_memread(global_qtest, address, &b, 1);
266 if (b != last_byte) {
267 if (((b + 1) % 256) == last_byte && !hit_edge) {
268 /* This is OK, the guest stopped at the point of
269 * incrementing the previous page but didn't get
270 * to us yet.
271 */
272 hit_edge = true;
273 } else {
274 fprintf(stderr, "Memory content inconsistency at %x"
275 " first_byte = %x last_byte = %x current = %x"
276 " hit_edge = %x\n",
277 address, first_byte, last_byte, b, hit_edge);
278 bad = true;
279 }
280 }
281 last_byte = b;
282 }
283 g_assert_false(bad);
284 }
285
286 static void cleanup(const char *filename)
287 {
288 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
289
290 unlink(path);
291 }
292
293 static void test_migrate(void)
294 {
295 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
296 QTestState *global = global_qtest, *from, *to;
297 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
298 gchar *cmd;
299 QDict *rsp;
300
301 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
302 FILE *bootfile = fopen(bootpath, "wb");
303
304 got_stop = false;
305 g_assert_cmpint(fwrite(bootsect, 512, 1, bootfile), ==, 1);
306 fclose(bootfile);
307
308 cmd = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
309 " -name pcsource,debug-threads=on"
310 " -serial file:%s/src_serial"
311 " -drive file=%s,format=raw",
312 tmpfs, bootpath);
313 from = qtest_start(cmd);
314 g_free(cmd);
315
316 cmd = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
317 " -name pcdest,debug-threads=on"
318 " -serial file:%s/dest_serial"
319 " -drive file=%s,format=raw"
320 " -incoming %s",
321 tmpfs, bootpath, uri);
322 to = qtest_init(cmd);
323 g_free(cmd);
324
325 global_qtest = from;
326 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
327 "'arguments': { "
328 "'capabilities': [ {"
329 "'capability': 'postcopy-ram',"
330 "'state': true } ] } }");
331 g_assert(qdict_haskey(rsp, "return"));
332 QDECREF(rsp);
333
334 global_qtest = to;
335 rsp = qmp("{ 'execute': 'migrate-set-capabilities',"
336 "'arguments': { "
337 "'capabilities': [ {"
338 "'capability': 'postcopy-ram',"
339 "'state': true } ] } }");
340 g_assert(qdict_haskey(rsp, "return"));
341 QDECREF(rsp);
342
343 /* We want to pick a speed slow enough that the test completes
344 * quickly, but that it doesn't complete precopy even on a slow
345 * machine, so also set the downtime.
346 */
347 global_qtest = from;
348 rsp = qmp("{ 'execute': 'migrate_set_speed',"
349 "'arguments': { 'value': 100000000 } }");
350 g_assert(qdict_haskey(rsp, "return"));
351 QDECREF(rsp);
352
353 /* 1ms downtime - it should never finish precopy */
354 rsp = qmp("{ 'execute': 'migrate_set_downtime',"
355 "'arguments': { 'value': 0.001 } }");
356 g_assert(qdict_haskey(rsp, "return"));
357 QDECREF(rsp);
358
359
360 /* Wait for the first serial output from the source */
361 wait_for_serial("src_serial");
362
363 cmd = g_strdup_printf("{ 'execute': 'migrate',"
364 "'arguments': { 'uri': '%s' } }",
365 uri);
366 rsp = qmp(cmd);
367 g_free(cmd);
368 g_assert(qdict_haskey(rsp, "return"));
369 QDECREF(rsp);
370
371 wait_for_migration_pass();
372
373 rsp = return_or_event(qmp("{ 'execute': 'migrate-start-postcopy' }"));
374 g_assert(qdict_haskey(rsp, "return"));
375 QDECREF(rsp);
376
377 if (!got_stop) {
378 qmp_eventwait("STOP");
379 }
380
381 global_qtest = to;
382 qmp_eventwait("RESUME");
383
384 wait_for_serial("dest_serial");
385 global_qtest = from;
386 wait_for_migration_complete();
387
388 qtest_quit(from);
389
390 global_qtest = to;
391
392 qtest_memread(to, start_address, &dest_byte_a, 1);
393
394 /* Destination still running, wait for a byte to change */
395 do {
396 qtest_memread(to, start_address, &dest_byte_b, 1);
397 usleep(10 * 1000);
398 } while (dest_byte_a == dest_byte_b);
399
400 qmp("{ 'execute' : 'stop'}");
401 /* With it stopped, check nothing changes */
402 qtest_memread(to, start_address, &dest_byte_c, 1);
403 sleep(1);
404 qtest_memread(to, start_address, &dest_byte_d, 1);
405 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
406
407 check_guests_ram();
408
409 qtest_quit(to);
410 g_free(uri);
411
412 global_qtest = global;
413
414 cleanup("bootsect");
415 cleanup("migsocket");
416 cleanup("src_serial");
417 cleanup("dest_serial");
418 }
419
420 int main(int argc, char **argv)
421 {
422 char template[] = "/tmp/postcopy-test-XXXXXX";
423 int ret;
424
425 g_test_init(&argc, &argv, NULL);
426
427 if (!ufd_version_check()) {
428 return 0;
429 }
430
431 tmpfs = mkdtemp(template);
432 if (!tmpfs) {
433 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
434 }
435 g_assert(tmpfs);
436
437 module_call_init(MODULE_INIT_QOM);
438
439 qtest_add_func("/postcopy", test_migrate);
440
441 ret = g_test_run();
442
443 g_assert_cmpint(ret, ==, 0);
444
445 ret = rmdir(tmpfs);
446 if (ret != 0) {
447 g_test_message("unable to rmdir: path (%s): %s\n",
448 tmpfs, strerror(errno));
449 }
450
451 return ret;
452 }