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