]> Git Repo - qemu.git/blob - tests/test-replication.c
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[qemu.git] / tests / test-replication.c
1 /*
2  * Block replication tests
3  *
4  * Copyright (c) 2016 FUJITSU LIMITED
5  * Author: Changlong Xie <[email protected]>
6  *
7  * This work is licensed under the terms of the GNU GPL, version 2 or
8  * later.  See the COPYING file in the top-level directory.
9  */
10
11 #include "qemu/osdep.h"
12
13 #include "qapi/error.h"
14 #include "replication.h"
15 #include "block/block_int.h"
16 #include "sysemu/block-backend.h"
17
18 #define IMG_SIZE (64 * 1024 * 1024)
19
20 /* primary */
21 #define P_ID "primary-id"
22 static char p_local_disk[] = "/tmp/p_local_disk.XXXXXX";
23
24 /* secondary */
25 #define S_ID "secondary-id"
26 #define S_LOCAL_DISK_ID "secondary-local-disk-id"
27 static char s_local_disk[] = "/tmp/s_local_disk.XXXXXX";
28 static char s_active_disk[] = "/tmp/s_active_disk.XXXXXX";
29 static char s_hidden_disk[] = "/tmp/s_hidden_disk.XXXXXX";
30
31 /* FIXME: steal from blockdev.c */
32 QemuOptsList qemu_drive_opts = {
33     .name = "drive",
34     .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
35     .desc = {
36         { /* end of list */ }
37     },
38 };
39
40 #define NOT_DONE 0x7fffffff
41
42 static void blk_rw_done(void *opaque, int ret)
43 {
44     *(int *)opaque = ret;
45 }
46
47 static void test_blk_read(BlockBackend *blk, long pattern,
48                           int64_t pattern_offset, int64_t pattern_count,
49                           int64_t offset, int64_t count,
50                           bool expect_failed)
51 {
52     void *pattern_buf = NULL;
53     QEMUIOVector qiov;
54     void *cmp_buf = NULL;
55     int async_ret = NOT_DONE;
56
57     if (pattern) {
58         cmp_buf = g_malloc(pattern_count);
59         memset(cmp_buf, pattern, pattern_count);
60     }
61
62     pattern_buf = g_malloc(count);
63     if (pattern) {
64         memset(pattern_buf, pattern, count);
65     } else {
66         memset(pattern_buf, 0x00, count);
67     }
68
69     qemu_iovec_init(&qiov, 1);
70     qemu_iovec_add(&qiov, pattern_buf, count);
71
72     blk_aio_preadv(blk, offset, &qiov, 0, blk_rw_done, &async_ret);
73     while (async_ret == NOT_DONE) {
74         main_loop_wait(false);
75     }
76
77     if (expect_failed) {
78         g_assert(async_ret != 0);
79     } else {
80         g_assert(async_ret == 0);
81         if (pattern) {
82             g_assert(memcmp(pattern_buf + pattern_offset,
83                             cmp_buf, pattern_count) <= 0);
84         }
85     }
86
87     g_free(pattern_buf);
88 }
89
90 static void test_blk_write(BlockBackend *blk, long pattern, int64_t offset,
91                            int64_t count, bool expect_failed)
92 {
93     void *pattern_buf = NULL;
94     QEMUIOVector qiov;
95     int async_ret = NOT_DONE;
96
97     pattern_buf = g_malloc(count);
98     if (pattern) {
99         memset(pattern_buf, pattern, count);
100     } else {
101         memset(pattern_buf, 0x00, count);
102     }
103
104     qemu_iovec_init(&qiov, 1);
105     qemu_iovec_add(&qiov, pattern_buf, count);
106
107     blk_aio_pwritev(blk, offset, &qiov, 0, blk_rw_done, &async_ret);
108     while (async_ret == NOT_DONE) {
109         main_loop_wait(false);
110     }
111
112     if (expect_failed) {
113         g_assert(async_ret != 0);
114     } else {
115         g_assert(async_ret == 0);
116     }
117
118     g_free(pattern_buf);
119 }
120
121 /*
122  * Create a uniquely-named empty temporary file.
123  */
124 static void make_temp(char *template)
125 {
126     int fd;
127
128     fd = mkstemp(template);
129     g_assert(fd >= 0);
130     close(fd);
131 }
132
133 static void prepare_imgs(void)
134 {
135     Error *local_err = NULL;
136
137     make_temp(p_local_disk);
138     make_temp(s_local_disk);
139     make_temp(s_active_disk);
140     make_temp(s_hidden_disk);
141
142     /* Primary */
143     bdrv_img_create(p_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
144                     BDRV_O_RDWR, &local_err, true);
145     g_assert(!local_err);
146
147     /* Secondary */
148     bdrv_img_create(s_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
149                     BDRV_O_RDWR, &local_err, true);
150     g_assert(!local_err);
151     bdrv_img_create(s_active_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
152                     BDRV_O_RDWR, &local_err, true);
153     g_assert(!local_err);
154     bdrv_img_create(s_hidden_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
155                     BDRV_O_RDWR, &local_err, true);
156     g_assert(!local_err);
157 }
158
159 static void cleanup_imgs(void)
160 {
161     /* Primary */
162     unlink(p_local_disk);
163
164     /* Secondary */
165     unlink(s_local_disk);
166     unlink(s_active_disk);
167     unlink(s_hidden_disk);
168 }
169
170 static BlockBackend *start_primary(void)
171 {
172     BlockBackend *blk;
173     QemuOpts *opts;
174     QDict *qdict;
175     Error *local_err = NULL;
176     char *cmdline;
177
178     cmdline = g_strdup_printf("driver=replication,mode=primary,node-name=xxx,"
179                               "file.driver=qcow2,file.file.filename=%s"
180                               , p_local_disk);
181     opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
182     g_free(cmdline);
183
184     qdict = qemu_opts_to_qdict(opts, NULL);
185     qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
186     qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
187
188     blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
189     g_assert(blk);
190     g_assert(!local_err);
191
192     monitor_add_blk(blk, P_ID, &local_err);
193     g_assert(!local_err);
194
195     qemu_opts_del(opts);
196
197     return blk;
198 }
199
200 static void teardown_primary(void)
201 {
202     BlockBackend *blk;
203
204     /* remove P_ID */
205     blk = blk_by_name(P_ID);
206     assert(blk);
207
208     monitor_remove_blk(blk);
209     blk_unref(blk);
210 }
211
212 static void test_primary_read(void)
213 {
214     BlockBackend *blk;
215
216     blk = start_primary();
217
218     /* read from 0 to IMG_SIZE */
219     test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true);
220
221     teardown_primary();
222 }
223
224 static void test_primary_write(void)
225 {
226     BlockBackend *blk;
227
228     blk = start_primary();
229
230     /* write from 0 to IMG_SIZE */
231     test_blk_write(blk, 0, 0, IMG_SIZE, true);
232
233     teardown_primary();
234 }
235
236 static void test_primary_start(void)
237 {
238     BlockBackend *blk = NULL;
239     Error *local_err = NULL;
240
241     blk = start_primary();
242
243     replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
244     g_assert(!local_err);
245
246     /* read from 0 to IMG_SIZE */
247     test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true);
248
249     /* write 0x22 from 0 to IMG_SIZE */
250     test_blk_write(blk, 0x22, 0, IMG_SIZE, false);
251
252     teardown_primary();
253 }
254
255 static void test_primary_stop(void)
256 {
257     Error *local_err = NULL;
258     bool failover = true;
259
260     start_primary();
261
262     replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
263     g_assert(!local_err);
264
265     replication_stop_all(failover, &local_err);
266     g_assert(!local_err);
267
268     teardown_primary();
269 }
270
271 static void test_primary_do_checkpoint(void)
272 {
273     Error *local_err = NULL;
274
275     start_primary();
276
277     replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
278     g_assert(!local_err);
279
280     replication_do_checkpoint_all(&local_err);
281     g_assert(!local_err);
282
283     teardown_primary();
284 }
285
286 static void test_primary_get_error_all(void)
287 {
288     Error *local_err = NULL;
289
290     start_primary();
291
292     replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
293     g_assert(!local_err);
294
295     replication_get_error_all(&local_err);
296     g_assert(!local_err);
297
298     teardown_primary();
299 }
300
301 static BlockBackend *start_secondary(void)
302 {
303     QemuOpts *opts;
304     QDict *qdict;
305     BlockBackend *blk;
306     char *cmdline;
307     Error *local_err = NULL;
308
309     /* add s_local_disk and forge S_LOCAL_DISK_ID */
310     cmdline = g_strdup_printf("file.filename=%s,driver=qcow2", s_local_disk);
311     opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
312     g_free(cmdline);
313
314     qdict = qemu_opts_to_qdict(opts, NULL);
315     qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
316     qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
317
318     blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
319     assert(blk);
320     monitor_add_blk(blk, S_LOCAL_DISK_ID, &local_err);
321     g_assert(!local_err);
322
323     /* format s_local_disk with pattern "0x11" */
324     test_blk_write(blk, 0x11, 0, IMG_SIZE, false);
325
326     qemu_opts_del(opts);
327
328     /* add S_(ACTIVE/HIDDEN)_DISK and forge S_ID */
329     cmdline = g_strdup_printf("driver=replication,mode=secondary,top-id=%s,"
330                               "file.driver=qcow2,file.file.filename=%s,"
331                               "file.backing.driver=qcow2,"
332                               "file.backing.file.filename=%s,"
333                               "file.backing.backing=%s"
334                               , S_ID, s_active_disk, s_hidden_disk
335                               , S_LOCAL_DISK_ID);
336     opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
337     g_free(cmdline);
338
339     qdict = qemu_opts_to_qdict(opts, NULL);
340     qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
341     qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
342
343     blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
344     assert(blk);
345     monitor_add_blk(blk, S_ID, &local_err);
346     g_assert(!local_err);
347
348     qemu_opts_del(opts);
349
350     return blk;
351 }
352
353 static void teardown_secondary(void)
354 {
355     /* only need to destroy two BBs */
356     BlockBackend *blk;
357
358     /* remove S_LOCAL_DISK_ID */
359     blk = blk_by_name(S_LOCAL_DISK_ID);
360     assert(blk);
361
362     monitor_remove_blk(blk);
363     blk_unref(blk);
364
365     /* remove S_ID */
366     blk = blk_by_name(S_ID);
367     assert(blk);
368
369     monitor_remove_blk(blk);
370     blk_unref(blk);
371 }
372
373 static void test_secondary_read(void)
374 {
375     BlockBackend *blk;
376
377     blk = start_secondary();
378
379     /* read from 0 to IMG_SIZE */
380     test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true);
381
382     teardown_secondary();
383 }
384
385 static void test_secondary_write(void)
386 {
387     BlockBackend *blk;
388
389     blk = start_secondary();
390
391     /* write from 0 to IMG_SIZE */
392     test_blk_write(blk, 0, 0, IMG_SIZE, true);
393
394     teardown_secondary();
395 }
396
397 static void test_secondary_start(void)
398 {
399     BlockBackend *top_blk, *local_blk;
400     Error *local_err = NULL;
401     bool failover = true;
402
403     top_blk = start_secondary();
404     replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
405     g_assert(!local_err);
406
407     /* read from s_local_disk (0, IMG_SIZE) */
408     test_blk_read(top_blk, 0x11, 0, IMG_SIZE, 0, IMG_SIZE, false);
409
410     /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
411     local_blk = blk_by_name(S_LOCAL_DISK_ID);
412     test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false);
413
414     /* replication will backup s_local_disk to s_hidden_disk */
415     test_blk_read(top_blk, 0x11, IMG_SIZE / 2,
416                   IMG_SIZE / 2, 0, IMG_SIZE, false);
417
418     /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */
419     test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false);
420
421     /* read from s_active_disk (0, IMG_SIZE/2) */
422     test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2,
423                   0, IMG_SIZE / 2, false);
424
425     /* unblock top_bs */
426     replication_stop_all(failover, &local_err);
427     g_assert(!local_err);
428
429     teardown_secondary();
430 }
431
432
433 static void test_secondary_stop(void)
434 {
435     BlockBackend *top_blk, *local_blk;
436     Error *local_err = NULL;
437     bool failover = true;
438
439     top_blk = start_secondary();
440     replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
441     g_assert(!local_err);
442
443     /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
444     local_blk = blk_by_name(S_LOCAL_DISK_ID);
445     test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false);
446
447     /* replication will backup s_local_disk to s_hidden_disk */
448     test_blk_read(top_blk, 0x11, IMG_SIZE / 2,
449                   IMG_SIZE / 2, 0, IMG_SIZE, false);
450
451     /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */
452     test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false);
453
454     /* do active commit */
455     replication_stop_all(failover, &local_err);
456     g_assert(!local_err);
457
458     /* read from s_local_disk (0, IMG_SIZE / 2) */
459     test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2,
460                   0, IMG_SIZE / 2, false);
461
462
463     /* read from s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
464     test_blk_read(top_blk, 0x22, IMG_SIZE / 2,
465                   IMG_SIZE / 2, 0, IMG_SIZE, false);
466
467     teardown_secondary();
468 }
469
470 static void test_secondary_do_checkpoint(void)
471 {
472     BlockBackend *top_blk, *local_blk;
473     Error *local_err = NULL;
474     bool failover = true;
475
476     top_blk = start_secondary();
477     replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
478     g_assert(!local_err);
479
480     /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
481     local_blk = blk_by_name(S_LOCAL_DISK_ID);
482     test_blk_write(local_blk, 0x22, IMG_SIZE / 2,
483                    IMG_SIZE / 2, false);
484
485     /* replication will backup s_local_disk to s_hidden_disk */
486     test_blk_read(top_blk, 0x11, IMG_SIZE / 2,
487                   IMG_SIZE / 2, 0, IMG_SIZE, false);
488
489     replication_do_checkpoint_all(&local_err);
490     g_assert(!local_err);
491
492     /* after checkpoint, read pattern 0x22 from s_local_disk */
493     test_blk_read(top_blk, 0x22, IMG_SIZE / 2,
494                   IMG_SIZE / 2, 0, IMG_SIZE, false);
495
496     /* unblock top_bs */
497     replication_stop_all(failover, &local_err);
498     g_assert(!local_err);
499
500     teardown_secondary();
501 }
502
503 static void test_secondary_get_error_all(void)
504 {
505     Error *local_err = NULL;
506     bool failover = true;
507
508     start_secondary();
509     replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
510     g_assert(!local_err);
511
512     replication_get_error_all(&local_err);
513     g_assert(!local_err);
514
515     /* unblock top_bs */
516     replication_stop_all(failover, &local_err);
517     g_assert(!local_err);
518
519     teardown_secondary();
520 }
521
522 static void sigabrt_handler(int signo)
523 {
524     cleanup_imgs();
525 }
526
527 static void setup_sigabrt_handler(void)
528 {
529     struct sigaction sigact;
530
531     sigact = (struct sigaction) {
532         .sa_handler = sigabrt_handler,
533         .sa_flags = SA_RESETHAND,
534     };
535     sigemptyset(&sigact.sa_mask);
536     sigaction(SIGABRT, &sigact, NULL);
537 }
538
539 int main(int argc, char **argv)
540 {
541     int ret;
542     qemu_init_main_loop(&error_fatal);
543     bdrv_init();
544
545     g_test_init(&argc, &argv, NULL);
546     setup_sigabrt_handler();
547
548     prepare_imgs();
549
550     /* Primary */
551     g_test_add_func("/replication/primary/read",    test_primary_read);
552     g_test_add_func("/replication/primary/write",   test_primary_write);
553     g_test_add_func("/replication/primary/start",   test_primary_start);
554     g_test_add_func("/replication/primary/stop",    test_primary_stop);
555     g_test_add_func("/replication/primary/do_checkpoint",
556                     test_primary_do_checkpoint);
557     g_test_add_func("/replication/primary/get_error_all",
558                     test_primary_get_error_all);
559
560     /* Secondary */
561     g_test_add_func("/replication/secondary/read",  test_secondary_read);
562     g_test_add_func("/replication/secondary/write", test_secondary_write);
563     g_test_add_func("/replication/secondary/start", test_secondary_start);
564     g_test_add_func("/replication/secondary/stop",  test_secondary_stop);
565     g_test_add_func("/replication/secondary/do_checkpoint",
566                     test_secondary_do_checkpoint);
567     g_test_add_func("/replication/secondary/get_error_all",
568                     test_secondary_get_error_all);
569
570     ret = g_test_run();
571
572     cleanup_imgs();
573
574     return ret;
575 }
This page took 0.052219 seconds and 4 git commands to generate.