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