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