]> git.proxmox.com Git - mirror_qemu.git/blob - block/replication.c
b844a09eb1add3c16b3594897ddb5a70cb8280b2
[mirror_qemu.git] / block / replication.c
1 /*
2 * Replication Block filter
3 *
4 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
5 * Copyright (c) 2016 Intel Corporation
6 * Copyright (c) 2016 FUJITSU LIMITED
7 *
8 * Author:
9 * Wen Congyang <wency@cn.fujitsu.com>
10 *
11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
12 * See the COPYING file in the top-level directory.
13 */
14
15 #include "qemu/osdep.h"
16 #include "qemu/module.h"
17 #include "qemu/option.h"
18 #include "block/nbd.h"
19 #include "block/blockjob.h"
20 #include "block/block_int.h"
21 #include "block/block_backup.h"
22 #include "sysemu/block-backend.h"
23 #include "qapi/error.h"
24 #include "qapi/qmp/qdict.h"
25 #include "replication.h"
26
27 typedef enum {
28 BLOCK_REPLICATION_NONE, /* block replication is not started */
29 BLOCK_REPLICATION_RUNNING, /* block replication is running */
30 BLOCK_REPLICATION_FAILOVER, /* failover is running in background */
31 BLOCK_REPLICATION_FAILOVER_FAILED, /* failover failed */
32 BLOCK_REPLICATION_DONE, /* block replication is done */
33 } ReplicationStage;
34
35 typedef struct BDRVReplicationState {
36 ReplicationMode mode;
37 ReplicationStage stage;
38 BdrvChild *active_disk;
39 BlockJob *commit_job;
40 BdrvChild *hidden_disk;
41 BdrvChild *secondary_disk;
42 BlockJob *backup_job;
43 char *top_id;
44 ReplicationState *rs;
45 Error *blocker;
46 bool orig_hidden_read_only;
47 bool orig_secondary_read_only;
48 int error;
49 } BDRVReplicationState;
50
51 static void replication_start(ReplicationState *rs, ReplicationMode mode,
52 Error **errp);
53 static void replication_do_checkpoint(ReplicationState *rs, Error **errp);
54 static void replication_get_error(ReplicationState *rs, Error **errp);
55 static void replication_stop(ReplicationState *rs, bool failover,
56 Error **errp);
57
58 #define REPLICATION_MODE "mode"
59 #define REPLICATION_TOP_ID "top-id"
60 static QemuOptsList replication_runtime_opts = {
61 .name = "replication",
62 .head = QTAILQ_HEAD_INITIALIZER(replication_runtime_opts.head),
63 .desc = {
64 {
65 .name = REPLICATION_MODE,
66 .type = QEMU_OPT_STRING,
67 },
68 {
69 .name = REPLICATION_TOP_ID,
70 .type = QEMU_OPT_STRING,
71 },
72 { /* end of list */ }
73 },
74 };
75
76 static ReplicationOps replication_ops = {
77 .start = replication_start,
78 .checkpoint = replication_do_checkpoint,
79 .get_error = replication_get_error,
80 .stop = replication_stop,
81 };
82
83 static int replication_open(BlockDriverState *bs, QDict *options,
84 int flags, Error **errp)
85 {
86 int ret;
87 BDRVReplicationState *s = bs->opaque;
88 Error *local_err = NULL;
89 QemuOpts *opts = NULL;
90 const char *mode;
91 const char *top_id;
92
93 bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
94 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
95 false, errp);
96 if (!bs->file) {
97 return -EINVAL;
98 }
99
100 ret = -EINVAL;
101 opts = qemu_opts_create(&replication_runtime_opts, NULL, 0, &error_abort);
102 if (!qemu_opts_absorb_qdict(opts, options, &local_err)) {
103 goto fail;
104 }
105
106 mode = qemu_opt_get(opts, REPLICATION_MODE);
107 if (!mode) {
108 error_setg(errp, "Missing the option mode");
109 goto fail;
110 }
111
112 if (!strcmp(mode, "primary")) {
113 s->mode = REPLICATION_MODE_PRIMARY;
114 top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
115 if (top_id) {
116 error_setg(errp,
117 "The primary side does not support option top-id");
118 goto fail;
119 }
120 } else if (!strcmp(mode, "secondary")) {
121 s->mode = REPLICATION_MODE_SECONDARY;
122 top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
123 s->top_id = g_strdup(top_id);
124 if (!s->top_id) {
125 error_setg(errp, "Missing the option top-id");
126 goto fail;
127 }
128 } else {
129 error_setg(errp,
130 "The option mode's value should be primary or secondary");
131 goto fail;
132 }
133
134 s->rs = replication_new(bs, &replication_ops);
135
136 ret = 0;
137
138 fail:
139 qemu_opts_del(opts);
140 return ret;
141 }
142
143 static void replication_close(BlockDriverState *bs)
144 {
145 BDRVReplicationState *s = bs->opaque;
146 Job *commit_job;
147
148 if (s->stage == BLOCK_REPLICATION_RUNNING) {
149 replication_stop(s->rs, false, NULL);
150 }
151 if (s->stage == BLOCK_REPLICATION_FAILOVER) {
152 commit_job = &s->commit_job->job;
153 assert(commit_job->aio_context == qemu_get_current_aio_context());
154 job_cancel_sync(commit_job);
155 }
156
157 if (s->mode == REPLICATION_MODE_SECONDARY) {
158 g_free(s->top_id);
159 }
160
161 replication_remove(s->rs);
162 }
163
164 static void replication_child_perm(BlockDriverState *bs, BdrvChild *c,
165 BdrvChildRole role,
166 BlockReopenQueue *reopen_queue,
167 uint64_t perm, uint64_t shared,
168 uint64_t *nperm, uint64_t *nshared)
169 {
170 *nperm = BLK_PERM_CONSISTENT_READ;
171 if ((bs->open_flags & (BDRV_O_INACTIVE | BDRV_O_RDWR)) == BDRV_O_RDWR) {
172 *nperm |= BLK_PERM_WRITE;
173 }
174 *nshared = BLK_PERM_CONSISTENT_READ
175 | BLK_PERM_WRITE
176 | BLK_PERM_WRITE_UNCHANGED;
177 return;
178 }
179
180 static int64_t replication_getlength(BlockDriverState *bs)
181 {
182 return bdrv_getlength(bs->file->bs);
183 }
184
185 static int replication_get_io_status(BDRVReplicationState *s)
186 {
187 switch (s->stage) {
188 case BLOCK_REPLICATION_NONE:
189 return -EIO;
190 case BLOCK_REPLICATION_RUNNING:
191 return 0;
192 case BLOCK_REPLICATION_FAILOVER:
193 return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 0;
194 case BLOCK_REPLICATION_FAILOVER_FAILED:
195 return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 1;
196 case BLOCK_REPLICATION_DONE:
197 /*
198 * active commit job completes, and active disk and secondary_disk
199 * is swapped, so we can operate bs->file directly
200 */
201 return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 0;
202 default:
203 abort();
204 }
205 }
206
207 static int replication_return_value(BDRVReplicationState *s, int ret)
208 {
209 if (s->mode == REPLICATION_MODE_SECONDARY) {
210 return ret;
211 }
212
213 if (ret < 0) {
214 s->error = ret;
215 ret = 0;
216 }
217
218 return ret;
219 }
220
221 static coroutine_fn int replication_co_readv(BlockDriverState *bs,
222 int64_t sector_num,
223 int remaining_sectors,
224 QEMUIOVector *qiov)
225 {
226 BDRVReplicationState *s = bs->opaque;
227 int ret;
228
229 if (s->mode == REPLICATION_MODE_PRIMARY) {
230 /* We only use it to forward primary write requests */
231 return -EIO;
232 }
233
234 ret = replication_get_io_status(s);
235 if (ret < 0) {
236 return ret;
237 }
238
239 ret = bdrv_co_preadv(bs->file, sector_num * BDRV_SECTOR_SIZE,
240 remaining_sectors * BDRV_SECTOR_SIZE, qiov, 0);
241
242 return replication_return_value(s, ret);
243 }
244
245 static coroutine_fn int replication_co_writev(BlockDriverState *bs,
246 int64_t sector_num,
247 int remaining_sectors,
248 QEMUIOVector *qiov,
249 int flags)
250 {
251 BDRVReplicationState *s = bs->opaque;
252 QEMUIOVector hd_qiov;
253 uint64_t bytes_done = 0;
254 BdrvChild *top = bs->file;
255 BdrvChild *base = s->secondary_disk;
256 BdrvChild *target;
257 int ret;
258 int64_t n;
259
260 assert(!flags);
261 ret = replication_get_io_status(s);
262 if (ret < 0) {
263 goto out;
264 }
265
266 if (ret == 0) {
267 ret = bdrv_co_pwritev(top, sector_num * BDRV_SECTOR_SIZE,
268 remaining_sectors * BDRV_SECTOR_SIZE, qiov, 0);
269 return replication_return_value(s, ret);
270 }
271
272 /*
273 * Failover failed, only write to active disk if the sectors
274 * have already been allocated in active disk/hidden disk.
275 */
276 qemu_iovec_init(&hd_qiov, qiov->niov);
277 while (remaining_sectors > 0) {
278 int64_t count;
279
280 ret = bdrv_is_allocated_above(top->bs, base->bs, false,
281 sector_num * BDRV_SECTOR_SIZE,
282 remaining_sectors * BDRV_SECTOR_SIZE,
283 &count);
284 if (ret < 0) {
285 goto out1;
286 }
287
288 assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
289 n = count >> BDRV_SECTOR_BITS;
290 qemu_iovec_reset(&hd_qiov);
291 qemu_iovec_concat(&hd_qiov, qiov, bytes_done, count);
292
293 target = ret ? top : base;
294 ret = bdrv_co_pwritev(target, sector_num * BDRV_SECTOR_SIZE,
295 n * BDRV_SECTOR_SIZE, &hd_qiov, 0);
296 if (ret < 0) {
297 goto out1;
298 }
299
300 remaining_sectors -= n;
301 sector_num += n;
302 bytes_done += count;
303 }
304
305 out1:
306 qemu_iovec_destroy(&hd_qiov);
307 out:
308 return ret;
309 }
310
311 static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
312 {
313 Error *local_err = NULL;
314 int ret;
315
316 if (!s->backup_job) {
317 error_setg(errp, "Backup job was cancelled unexpectedly");
318 return;
319 }
320
321 backup_do_checkpoint(s->backup_job, &local_err);
322 if (local_err) {
323 error_propagate(errp, local_err);
324 return;
325 }
326
327 if (!s->active_disk->bs->drv) {
328 error_setg(errp, "Active disk %s is ejected",
329 s->active_disk->bs->node_name);
330 return;
331 }
332
333 ret = bdrv_make_empty(s->active_disk, errp);
334 if (ret < 0) {
335 return;
336 }
337
338 if (!s->hidden_disk->bs->drv) {
339 error_setg(errp, "Hidden disk %s is ejected",
340 s->hidden_disk->bs->node_name);
341 return;
342 }
343
344 BlockBackend *blk = blk_new(qemu_get_current_aio_context(),
345 BLK_PERM_WRITE, BLK_PERM_ALL);
346 blk_insert_bs(blk, s->hidden_disk->bs, &local_err);
347 if (local_err) {
348 error_propagate(errp, local_err);
349 blk_unref(blk);
350 return;
351 }
352
353 ret = blk_make_empty(blk, errp);
354 blk_unref(blk);
355 if (ret < 0) {
356 return;
357 }
358 }
359
360 /* This function is supposed to be called twice:
361 * first with writable = true, then with writable = false.
362 * The first call puts s->hidden_disk and s->secondary_disk in
363 * r/w mode, and the second puts them back in their original state.
364 */
365 static void reopen_backing_file(BlockDriverState *bs, bool writable,
366 Error **errp)
367 {
368 BDRVReplicationState *s = bs->opaque;
369 BlockReopenQueue *reopen_queue = NULL;
370 Error *local_err = NULL;
371
372 if (writable) {
373 s->orig_hidden_read_only = bdrv_is_read_only(s->hidden_disk->bs);
374 s->orig_secondary_read_only = bdrv_is_read_only(s->secondary_disk->bs);
375 }
376
377 bdrv_subtree_drained_begin(s->hidden_disk->bs);
378 bdrv_subtree_drained_begin(s->secondary_disk->bs);
379
380 if (s->orig_hidden_read_only) {
381 QDict *opts = qdict_new();
382 qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
383 reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs,
384 opts, true);
385 }
386
387 if (s->orig_secondary_read_only) {
388 QDict *opts = qdict_new();
389 qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
390 reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs,
391 opts, true);
392 }
393
394 if (reopen_queue) {
395 bdrv_reopen_multiple(reopen_queue, &local_err);
396 error_propagate(errp, local_err);
397 }
398
399 bdrv_subtree_drained_end(s->hidden_disk->bs);
400 bdrv_subtree_drained_end(s->secondary_disk->bs);
401 }
402
403 static void backup_job_cleanup(BlockDriverState *bs)
404 {
405 BDRVReplicationState *s = bs->opaque;
406 BlockDriverState *top_bs;
407
408 s->backup_job = NULL;
409
410 top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL);
411 if (!top_bs) {
412 return;
413 }
414 bdrv_op_unblock_all(top_bs, s->blocker);
415 error_free(s->blocker);
416 reopen_backing_file(bs, false, NULL);
417 }
418
419 static void backup_job_completed(void *opaque, int ret)
420 {
421 BlockDriverState *bs = opaque;
422 BDRVReplicationState *s = bs->opaque;
423
424 if (s->stage != BLOCK_REPLICATION_FAILOVER) {
425 /* The backup job is cancelled unexpectedly */
426 s->error = -EIO;
427 }
428
429 backup_job_cleanup(bs);
430 }
431
432 static bool check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs)
433 {
434 BdrvChild *child;
435
436 /* The bs itself is the top_bs */
437 if (top_bs == bs) {
438 return true;
439 }
440
441 /* Iterate over top_bs's children */
442 QLIST_FOREACH(child, &top_bs->children, next) {
443 if (child->bs == bs || check_top_bs(child->bs, bs)) {
444 return true;
445 }
446 }
447
448 return false;
449 }
450
451 static void replication_start(ReplicationState *rs, ReplicationMode mode,
452 Error **errp)
453 {
454 BlockDriverState *bs = rs->opaque;
455 BDRVReplicationState *s;
456 BlockDriverState *top_bs;
457 int64_t active_length, hidden_length, disk_length;
458 AioContext *aio_context;
459 Error *local_err = NULL;
460
461 aio_context = bdrv_get_aio_context(bs);
462 aio_context_acquire(aio_context);
463 s = bs->opaque;
464
465 if (s->stage == BLOCK_REPLICATION_DONE ||
466 s->stage == BLOCK_REPLICATION_FAILOVER) {
467 /*
468 * This case happens when a secondary is promoted to primary.
469 * Ignore the request because the secondary side of replication
470 * doesn't have to do anything anymore.
471 */
472 aio_context_release(aio_context);
473 return;
474 }
475
476 if (s->stage != BLOCK_REPLICATION_NONE) {
477 error_setg(errp, "Block replication is running or done");
478 aio_context_release(aio_context);
479 return;
480 }
481
482 if (s->mode != mode) {
483 error_setg(errp, "The parameter mode's value is invalid, needs %d,"
484 " but got %d", s->mode, mode);
485 aio_context_release(aio_context);
486 return;
487 }
488
489 switch (s->mode) {
490 case REPLICATION_MODE_PRIMARY:
491 break;
492 case REPLICATION_MODE_SECONDARY:
493 s->active_disk = bs->file;
494 if (!s->active_disk || !s->active_disk->bs ||
495 !s->active_disk->bs->backing) {
496 error_setg(errp, "Active disk doesn't have backing file");
497 aio_context_release(aio_context);
498 return;
499 }
500
501 s->hidden_disk = s->active_disk->bs->backing;
502 if (!s->hidden_disk->bs || !s->hidden_disk->bs->backing) {
503 error_setg(errp, "Hidden disk doesn't have backing file");
504 aio_context_release(aio_context);
505 return;
506 }
507
508 s->secondary_disk = s->hidden_disk->bs->backing;
509 if (!s->secondary_disk->bs || !bdrv_has_blk(s->secondary_disk->bs)) {
510 error_setg(errp, "The secondary disk doesn't have block backend");
511 aio_context_release(aio_context);
512 return;
513 }
514
515 /* verify the length */
516 active_length = bdrv_getlength(s->active_disk->bs);
517 hidden_length = bdrv_getlength(s->hidden_disk->bs);
518 disk_length = bdrv_getlength(s->secondary_disk->bs);
519 if (active_length < 0 || hidden_length < 0 || disk_length < 0 ||
520 active_length != hidden_length || hidden_length != disk_length) {
521 error_setg(errp, "Active disk, hidden disk, secondary disk's length"
522 " are not the same");
523 aio_context_release(aio_context);
524 return;
525 }
526
527 /* Must be true, or the bdrv_getlength() calls would have failed */
528 assert(s->active_disk->bs->drv && s->hidden_disk->bs->drv);
529
530 if (!s->active_disk->bs->drv->bdrv_make_empty ||
531 !s->hidden_disk->bs->drv->bdrv_make_empty) {
532 error_setg(errp,
533 "Active disk or hidden disk doesn't support make_empty");
534 aio_context_release(aio_context);
535 return;
536 }
537
538 /* reopen the backing file in r/w mode */
539 reopen_backing_file(bs, true, &local_err);
540 if (local_err) {
541 error_propagate(errp, local_err);
542 aio_context_release(aio_context);
543 return;
544 }
545
546 /* start backup job now */
547 error_setg(&s->blocker,
548 "Block device is in use by internal backup job");
549
550 top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL);
551 if (!top_bs || !bdrv_is_root_node(top_bs) ||
552 !check_top_bs(top_bs, bs)) {
553 error_setg(errp, "No top_bs or it is invalid");
554 reopen_backing_file(bs, false, NULL);
555 aio_context_release(aio_context);
556 return;
557 }
558 bdrv_op_block_all(top_bs, s->blocker);
559 bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
560
561 s->backup_job = backup_job_create(
562 NULL, s->secondary_disk->bs, s->hidden_disk->bs,
563 0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, NULL,
564 BLOCKDEV_ON_ERROR_REPORT,
565 BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL,
566 backup_job_completed, bs, NULL, &local_err);
567 if (local_err) {
568 error_propagate(errp, local_err);
569 backup_job_cleanup(bs);
570 aio_context_release(aio_context);
571 return;
572 }
573 job_start(&s->backup_job->job);
574 break;
575 default:
576 aio_context_release(aio_context);
577 abort();
578 }
579
580 s->stage = BLOCK_REPLICATION_RUNNING;
581
582 if (s->mode == REPLICATION_MODE_SECONDARY) {
583 secondary_do_checkpoint(s, errp);
584 }
585
586 s->error = 0;
587 aio_context_release(aio_context);
588 }
589
590 static void replication_do_checkpoint(ReplicationState *rs, Error **errp)
591 {
592 BlockDriverState *bs = rs->opaque;
593 BDRVReplicationState *s;
594 AioContext *aio_context;
595
596 aio_context = bdrv_get_aio_context(bs);
597 aio_context_acquire(aio_context);
598 s = bs->opaque;
599
600 if (s->stage == BLOCK_REPLICATION_DONE ||
601 s->stage == BLOCK_REPLICATION_FAILOVER) {
602 /*
603 * This case happens when a secondary was promoted to primary.
604 * Ignore the request because the secondary side of replication
605 * doesn't have to do anything anymore.
606 */
607 aio_context_release(aio_context);
608 return;
609 }
610
611 if (s->mode == REPLICATION_MODE_SECONDARY) {
612 secondary_do_checkpoint(s, errp);
613 }
614 aio_context_release(aio_context);
615 }
616
617 static void replication_get_error(ReplicationState *rs, Error **errp)
618 {
619 BlockDriverState *bs = rs->opaque;
620 BDRVReplicationState *s;
621 AioContext *aio_context;
622
623 aio_context = bdrv_get_aio_context(bs);
624 aio_context_acquire(aio_context);
625 s = bs->opaque;
626
627 if (s->stage == BLOCK_REPLICATION_NONE) {
628 error_setg(errp, "Block replication is not running");
629 aio_context_release(aio_context);
630 return;
631 }
632
633 if (s->error) {
634 error_setg(errp, "I/O error occurred");
635 aio_context_release(aio_context);
636 return;
637 }
638 aio_context_release(aio_context);
639 }
640
641 static void replication_done(void *opaque, int ret)
642 {
643 BlockDriverState *bs = opaque;
644 BDRVReplicationState *s = bs->opaque;
645
646 if (ret == 0) {
647 s->stage = BLOCK_REPLICATION_DONE;
648
649 s->active_disk = NULL;
650 s->secondary_disk = NULL;
651 s->hidden_disk = NULL;
652 s->error = 0;
653 } else {
654 s->stage = BLOCK_REPLICATION_FAILOVER_FAILED;
655 s->error = -EIO;
656 }
657 }
658
659 static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
660 {
661 BlockDriverState *bs = rs->opaque;
662 BDRVReplicationState *s;
663 AioContext *aio_context;
664
665 aio_context = bdrv_get_aio_context(bs);
666 aio_context_acquire(aio_context);
667 s = bs->opaque;
668
669 if (s->stage == BLOCK_REPLICATION_DONE ||
670 s->stage == BLOCK_REPLICATION_FAILOVER) {
671 /*
672 * This case happens when a secondary was promoted to primary.
673 * Ignore the request because the secondary side of replication
674 * doesn't have to do anything anymore.
675 */
676 aio_context_release(aio_context);
677 return;
678 }
679
680 if (s->stage != BLOCK_REPLICATION_RUNNING) {
681 error_setg(errp, "Block replication is not running");
682 aio_context_release(aio_context);
683 return;
684 }
685
686 switch (s->mode) {
687 case REPLICATION_MODE_PRIMARY:
688 s->stage = BLOCK_REPLICATION_DONE;
689 s->error = 0;
690 break;
691 case REPLICATION_MODE_SECONDARY:
692 /*
693 * This BDS will be closed, and the job should be completed
694 * before the BDS is closed, because we will access hidden
695 * disk, secondary disk in backup_job_completed().
696 */
697 if (s->backup_job) {
698 job_cancel_sync(&s->backup_job->job);
699 }
700
701 if (!failover) {
702 secondary_do_checkpoint(s, errp);
703 s->stage = BLOCK_REPLICATION_DONE;
704 aio_context_release(aio_context);
705 return;
706 }
707
708 s->stage = BLOCK_REPLICATION_FAILOVER;
709 s->commit_job = commit_active_start(
710 NULL, s->active_disk->bs, s->secondary_disk->bs,
711 JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
712 NULL, replication_done, bs, true, errp);
713 break;
714 default:
715 aio_context_release(aio_context);
716 abort();
717 }
718 aio_context_release(aio_context);
719 }
720
721 static const char *const replication_strong_runtime_opts[] = {
722 REPLICATION_MODE,
723 REPLICATION_TOP_ID,
724
725 NULL
726 };
727
728 static BlockDriver bdrv_replication = {
729 .format_name = "replication",
730 .instance_size = sizeof(BDRVReplicationState),
731
732 .bdrv_open = replication_open,
733 .bdrv_close = replication_close,
734 .bdrv_child_perm = replication_child_perm,
735
736 .bdrv_getlength = replication_getlength,
737 .bdrv_co_readv = replication_co_readv,
738 .bdrv_co_writev = replication_co_writev,
739
740 .is_filter = true,
741
742 .has_variable_length = true,
743 .strong_runtime_opts = replication_strong_runtime_opts,
744 };
745
746 static void bdrv_replication_init(void)
747 {
748 bdrv_register(&bdrv_replication);
749 }
750
751 block_init(bdrv_replication_init);