qemu

Форк
0
/
replication.c 
751 строка · 21.7 Кб
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 "block/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
    BlockJob *commit_job;
39
    BdrvChild *hidden_disk;
40
    BdrvChild *secondary_disk;
41
    BlockJob *backup_job;
42
    char *top_id;
43
    ReplicationState *rs;
44
    Error *blocker;
45
    bool orig_hidden_read_only;
46
    bool orig_secondary_read_only;
47
    int error;
48
} BDRVReplicationState;
49

50
static void replication_start(ReplicationState *rs, ReplicationMode mode,
51
                              Error **errp);
52
static void replication_do_checkpoint(ReplicationState *rs, Error **errp);
53
static void replication_get_error(ReplicationState *rs, Error **errp);
54
static void replication_stop(ReplicationState *rs, bool failover,
55
                             Error **errp);
56

57
#define REPLICATION_MODE        "mode"
58
#define REPLICATION_TOP_ID      "top-id"
59
static QemuOptsList replication_runtime_opts = {
60
    .name = "replication",
61
    .head = QTAILQ_HEAD_INITIALIZER(replication_runtime_opts.head),
62
    .desc = {
63
        {
64
            .name = REPLICATION_MODE,
65
            .type = QEMU_OPT_STRING,
66
        },
67
        {
68
            .name = REPLICATION_TOP_ID,
69
            .type = QEMU_OPT_STRING,
70
        },
71
        { /* end of list */ }
72
    },
73
};
74

75
static ReplicationOps replication_ops = {
76
    .start = replication_start,
77
    .checkpoint = replication_do_checkpoint,
78
    .get_error = replication_get_error,
79
    .stop = replication_stop,
80
};
81

82
static int replication_open(BlockDriverState *bs, QDict *options,
83
                            int flags, Error **errp)
84
{
85
    int ret;
86
    BDRVReplicationState *s = bs->opaque;
87
    QemuOpts *opts = NULL;
88
    const char *mode;
89
    const char *top_id;
90

91
    ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
92
    if (ret < 0) {
93
        return ret;
94
    }
95

96
    ret = -EINVAL;
97
    opts = qemu_opts_create(&replication_runtime_opts, NULL, 0, &error_abort);
98
    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
99
        goto fail;
100
    }
101

102
    mode = qemu_opt_get(opts, REPLICATION_MODE);
103
    if (!mode) {
104
        error_setg(errp, "Missing the option mode");
105
        goto fail;
106
    }
107

108
    if (!strcmp(mode, "primary")) {
109
        s->mode = REPLICATION_MODE_PRIMARY;
110
        top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
111
        if (top_id) {
112
            error_setg(errp,
113
                       "The primary side does not support option top-id");
114
            goto fail;
115
        }
116
    } else if (!strcmp(mode, "secondary")) {
117
        s->mode = REPLICATION_MODE_SECONDARY;
118
        top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
119
        s->top_id = g_strdup(top_id);
120
        if (!s->top_id) {
121
            error_setg(errp, "Missing the option top-id");
122
            goto fail;
123
        }
124
    } else {
125
        error_setg(errp,
126
                   "The option mode's value should be primary or secondary");
127
        goto fail;
128
    }
129

130
    s->rs = replication_new(bs, &replication_ops);
131

132
    ret = 0;
133

134
fail:
135
    qemu_opts_del(opts);
136
    return ret;
137
}
138

139
static void replication_close(BlockDriverState *bs)
140
{
141
    BDRVReplicationState *s = bs->opaque;
142
    Job *commit_job;
143
    GLOBAL_STATE_CODE();
144

145
    if (s->stage == BLOCK_REPLICATION_RUNNING) {
146
        replication_stop(s->rs, false, NULL);
147
    }
148
    if (s->stage == BLOCK_REPLICATION_FAILOVER) {
149
        commit_job = &s->commit_job->job;
150
        assert(commit_job->aio_context == qemu_get_current_aio_context());
151
        job_cancel_sync(commit_job, false);
152
    }
153

154
    if (s->mode == REPLICATION_MODE_SECONDARY) {
155
        g_free(s->top_id);
156
    }
157

158
    replication_remove(s->rs);
159
}
160

161
static void replication_child_perm(BlockDriverState *bs, BdrvChild *c,
162
                                   BdrvChildRole role,
163
                                   BlockReopenQueue *reopen_queue,
164
                                   uint64_t perm, uint64_t shared,
165
                                   uint64_t *nperm, uint64_t *nshared)
166
{
167
    if (role & BDRV_CHILD_PRIMARY) {
168
        *nperm = BLK_PERM_CONSISTENT_READ;
169
    } else {
170
        *nperm = 0;
171
    }
172

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 coroutine_fn GRAPH_RDLOCK
183
replication_co_getlength(BlockDriverState *bs)
184
{
185
    return bdrv_co_getlength(bs->file->bs);
186
}
187

188
static int replication_get_io_status(BDRVReplicationState *s)
189
{
190
    switch (s->stage) {
191
    case BLOCK_REPLICATION_NONE:
192
        return -EIO;
193
    case BLOCK_REPLICATION_RUNNING:
194
        return 0;
195
    case BLOCK_REPLICATION_FAILOVER:
196
        return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 0;
197
    case BLOCK_REPLICATION_FAILOVER_FAILED:
198
        return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 1;
199
    case BLOCK_REPLICATION_DONE:
200
        /*
201
         * active commit job completes, and active disk and secondary_disk
202
         * is swapped, so we can operate bs->file directly
203
         */
204
        return s->mode == REPLICATION_MODE_PRIMARY ? -EIO : 0;
205
    default:
206
        abort();
207
    }
208
}
209

210
static int replication_return_value(BDRVReplicationState *s, int ret)
211
{
212
    if (s->mode == REPLICATION_MODE_SECONDARY) {
213
        return ret;
214
    }
215

216
    if (ret < 0) {
217
        s->error = ret;
218
        ret = 0;
219
    }
220

221
    return ret;
222
}
223

224
static int coroutine_fn GRAPH_RDLOCK
225
replication_co_readv(BlockDriverState *bs, int64_t sector_num,
226
                     int remaining_sectors, 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 int coroutine_fn GRAPH_RDLOCK
248
replication_co_writev(BlockDriverState *bs, int64_t sector_num,
249
                      int remaining_sectors, QEMUIOVector *qiov, 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
    ret = replication_get_io_status(s);
261
    if (ret < 0) {
262
        goto out;
263
    }
264

265
    if (ret == 0) {
266
        ret = bdrv_co_pwritev(top, sector_num * BDRV_SECTOR_SIZE,
267
                              remaining_sectors * BDRV_SECTOR_SIZE, qiov, 0);
268
        return replication_return_value(s, ret);
269
    }
270

271
    /*
272
     * Failover failed, only write to active disk if the sectors
273
     * have already been allocated in active disk/hidden disk.
274
     */
275
    qemu_iovec_init(&hd_qiov, qiov->niov);
276
    while (remaining_sectors > 0) {
277
        int64_t count;
278

279
        ret = bdrv_co_is_allocated_above(top->bs, base->bs, false,
280
                                         sector_num * BDRV_SECTOR_SIZE,
281
                                         remaining_sectors * BDRV_SECTOR_SIZE,
282
                                         &count);
283
        if (ret < 0) {
284
            goto out1;
285
        }
286

287
        assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
288
        n = count >> BDRV_SECTOR_BITS;
289
        qemu_iovec_reset(&hd_qiov);
290
        qemu_iovec_concat(&hd_qiov, qiov, bytes_done, count);
291

292
        target = ret ? top : base;
293
        ret = bdrv_co_pwritev(target, sector_num * BDRV_SECTOR_SIZE,
294
                              n * BDRV_SECTOR_SIZE, &hd_qiov, 0);
295
        if (ret < 0) {
296
            goto out1;
297
        }
298

299
        remaining_sectors -= n;
300
        sector_num += n;
301
        bytes_done += count;
302
    }
303

304
out1:
305
    qemu_iovec_destroy(&hd_qiov);
306
out:
307
    return ret;
308
}
309

310
static void GRAPH_UNLOCKED
311
secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
312
{
313
    BDRVReplicationState *s = bs->opaque;
314
    BdrvChild *active_disk;
315
    Error *local_err = NULL;
316
    int ret;
317

318
    GRAPH_RDLOCK_GUARD_MAINLOOP();
319

320
    if (!s->backup_job) {
321
        error_setg(errp, "Backup job was cancelled unexpectedly");
322
        return;
323
    }
324

325
    backup_do_checkpoint(s->backup_job, &local_err);
326
    if (local_err) {
327
        error_propagate(errp, local_err);
328
        return;
329
    }
330

331
    active_disk = bs->file;
332
    if (!active_disk->bs->drv) {
333
        error_setg(errp, "Active disk %s is ejected",
334
                   active_disk->bs->node_name);
335
        return;
336
    }
337

338
    ret = bdrv_make_empty(active_disk, errp);
339
    if (ret < 0) {
340
        return;
341
    }
342

343
    if (!s->hidden_disk->bs->drv) {
344
        error_setg(errp, "Hidden disk %s is ejected",
345
                   s->hidden_disk->bs->node_name);
346
        return;
347
    }
348

349
    ret = bdrv_make_empty(s->hidden_disk, errp);
350
    if (ret < 0) {
351
        return;
352
    }
353
}
354

355
/* This function is supposed to be called twice:
356
 * first with writable = true, then with writable = false.
357
 * The first call puts s->hidden_disk and s->secondary_disk in
358
 * r/w mode, and the second puts them back in their original state.
359
 */
360
static void reopen_backing_file(BlockDriverState *bs, bool writable,
361
                                Error **errp)
362
{
363
    BDRVReplicationState *s = bs->opaque;
364
    BdrvChild *hidden_disk, *secondary_disk;
365
    BlockReopenQueue *reopen_queue = NULL;
366

367
    GLOBAL_STATE_CODE();
368
    GRAPH_RDLOCK_GUARD_MAINLOOP();
369

370
    /*
371
     * s->hidden_disk and s->secondary_disk may not be set yet, as they will
372
     * only be set after the children are writable.
373
     */
374
    hidden_disk = bs->file->bs->backing;
375
    secondary_disk = hidden_disk->bs->backing;
376

377
    if (writable) {
378
        s->orig_hidden_read_only = bdrv_is_read_only(hidden_disk->bs);
379
        s->orig_secondary_read_only = bdrv_is_read_only(secondary_disk->bs);
380
    }
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, 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, secondary_disk->bs,
393
                                         opts, true);
394
    }
395

396
    if (reopen_queue) {
397
        bdrv_reopen_multiple(reopen_queue, errp);
398
    }
399
}
400

401
static void backup_job_cleanup(BlockDriverState *bs)
402
{
403
    BDRVReplicationState *s = bs->opaque;
404
    BlockDriverState *top_bs;
405

406
    s->backup_job = NULL;
407

408
    top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL);
409
    if (!top_bs) {
410
        return;
411
    }
412
    bdrv_op_unblock_all(top_bs, s->blocker);
413
    error_free(s->blocker);
414
    reopen_backing_file(bs, false, NULL);
415
}
416

417
static void backup_job_completed(void *opaque, int ret)
418
{
419
    BlockDriverState *bs = opaque;
420
    BDRVReplicationState *s = bs->opaque;
421

422
    if (s->stage != BLOCK_REPLICATION_FAILOVER) {
423
        /* The backup job is cancelled unexpectedly */
424
        s->error = -EIO;
425
    }
426

427
    backup_job_cleanup(bs);
428
}
429

430
static bool GRAPH_RDLOCK
431
check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs)
432
{
433
    BdrvChild *child;
434

435
    /* The bs itself is the top_bs */
436
    if (top_bs == bs) {
437
        return true;
438
    }
439

440
    /* Iterate over top_bs's children */
441
    QLIST_FOREACH(child, &top_bs->children, next) {
442
        if (child->bs == bs || check_top_bs(child->bs, bs)) {
443
            return true;
444
        }
445
    }
446

447
    return false;
448
}
449

450
static void replication_start(ReplicationState *rs, ReplicationMode mode,
451
                              Error **errp)
452
{
453
    BlockDriverState *bs = rs->opaque;
454
    BDRVReplicationState *s;
455
    BlockDriverState *top_bs;
456
    BdrvChild *active_disk, *hidden_disk, *secondary_disk;
457
    int64_t active_length, hidden_length, disk_length;
458
    Error *local_err = NULL;
459
    BackupPerf perf = { .use_copy_range = true, .max_workers = 1 };
460

461
    GLOBAL_STATE_CODE();
462

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
        return;
473
    }
474

475
    if (s->stage != BLOCK_REPLICATION_NONE) {
476
        error_setg(errp, "Block replication is running or done");
477
        return;
478
    }
479

480
    if (s->mode != mode) {
481
        error_setg(errp, "The parameter mode's value is invalid, needs %d,"
482
                   " but got %d", s->mode, mode);
483
        return;
484
    }
485

486
    switch (s->mode) {
487
    case REPLICATION_MODE_PRIMARY:
488
        break;
489
    case REPLICATION_MODE_SECONDARY:
490
        bdrv_graph_rdlock_main_loop();
491
        active_disk = bs->file;
492
        if (!active_disk || !active_disk->bs || !active_disk->bs->backing) {
493
            error_setg(errp, "Active disk doesn't have backing file");
494
            bdrv_graph_rdunlock_main_loop();
495
            return;
496
        }
497

498
        hidden_disk = active_disk->bs->backing;
499
        if (!hidden_disk->bs || !hidden_disk->bs->backing) {
500
            error_setg(errp, "Hidden disk doesn't have backing file");
501
            bdrv_graph_rdunlock_main_loop();
502
            return;
503
        }
504

505
        secondary_disk = hidden_disk->bs->backing;
506
        if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) {
507
            error_setg(errp, "The secondary disk doesn't have block backend");
508
            bdrv_graph_rdunlock_main_loop();
509
            return;
510
        }
511
        bdrv_graph_rdunlock_main_loop();
512

513
        /* verify the length */
514
        active_length = bdrv_getlength(active_disk->bs);
515
        hidden_length = bdrv_getlength(hidden_disk->bs);
516
        disk_length = bdrv_getlength(secondary_disk->bs);
517
        if (active_length < 0 || hidden_length < 0 || disk_length < 0 ||
518
            active_length != hidden_length || hidden_length != disk_length) {
519
            error_setg(errp, "Active disk, hidden disk, secondary disk's length"
520
                       " are not the same");
521
            return;
522
        }
523

524
        /* Must be true, or the bdrv_getlength() calls would have failed */
525
        assert(active_disk->bs->drv && hidden_disk->bs->drv);
526

527
        bdrv_graph_rdlock_main_loop();
528
        if (!active_disk->bs->drv->bdrv_make_empty ||
529
            !hidden_disk->bs->drv->bdrv_make_empty) {
530
            error_setg(errp,
531
                       "Active disk or hidden disk doesn't support make_empty");
532
            bdrv_graph_rdunlock_main_loop();
533
            return;
534
        }
535
        bdrv_graph_rdunlock_main_loop();
536

537
        /* reopen the backing file in r/w mode */
538
        reopen_backing_file(bs, true, &local_err);
539
        if (local_err) {
540
            error_propagate(errp, local_err);
541
            return;
542
        }
543

544
        bdrv_graph_wrlock();
545

546
        bdrv_ref(hidden_disk->bs);
547
        s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk",
548
                                           &child_of_bds, BDRV_CHILD_DATA,
549
                                           &local_err);
550
        if (local_err) {
551
            error_propagate(errp, local_err);
552
            bdrv_graph_wrunlock();
553
            return;
554
        }
555

556
        bdrv_ref(secondary_disk->bs);
557
        s->secondary_disk = bdrv_attach_child(bs, secondary_disk->bs,
558
                                              "secondary disk", &child_of_bds,
559
                                              BDRV_CHILD_DATA, &local_err);
560
        if (local_err) {
561
            error_propagate(errp, local_err);
562
            bdrv_graph_wrunlock();
563
            return;
564
        }
565

566
        /* start backup job now */
567
        error_setg(&s->blocker,
568
                   "Block device is in use by internal backup job");
569

570
        top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL);
571
        if (!top_bs || !bdrv_is_root_node(top_bs) ||
572
            !check_top_bs(top_bs, bs)) {
573
            error_setg(errp, "No top_bs or it is invalid");
574
            bdrv_graph_wrunlock();
575
            reopen_backing_file(bs, false, NULL);
576
            return;
577
        }
578
        bdrv_op_block_all(top_bs, s->blocker);
579
        bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
580

581
        bdrv_graph_wrunlock();
582

583
        s->backup_job = backup_job_create(
584
                                NULL, s->secondary_disk->bs, s->hidden_disk->bs,
585
                                0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, false,
586
                                NULL, &perf,
587
                                BLOCKDEV_ON_ERROR_REPORT,
588
                                BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL,
589
                                backup_job_completed, bs, NULL, &local_err);
590
        if (local_err) {
591
            error_propagate(errp, local_err);
592
            backup_job_cleanup(bs);
593
            return;
594
        }
595
        job_start(&s->backup_job->job);
596
        break;
597
    default:
598
        abort();
599
    }
600

601
    s->stage = BLOCK_REPLICATION_RUNNING;
602

603
    if (s->mode == REPLICATION_MODE_SECONDARY) {
604
        secondary_do_checkpoint(bs, errp);
605
    }
606

607
    s->error = 0;
608
}
609

610
static void replication_do_checkpoint(ReplicationState *rs, Error **errp)
611
{
612
    BlockDriverState *bs = rs->opaque;
613
    BDRVReplicationState *s = bs->opaque;
614

615
    if (s->stage == BLOCK_REPLICATION_DONE ||
616
        s->stage == BLOCK_REPLICATION_FAILOVER) {
617
        /*
618
         * This case happens when a secondary was promoted to primary.
619
         * Ignore the request because the secondary side of replication
620
         * doesn't have to do anything anymore.
621
         */
622
        return;
623
    }
624

625
    if (s->mode == REPLICATION_MODE_SECONDARY) {
626
        secondary_do_checkpoint(bs, errp);
627
    }
628
}
629

630
static void replication_get_error(ReplicationState *rs, Error **errp)
631
{
632
    BlockDriverState *bs = rs->opaque;
633
    BDRVReplicationState *s = bs->opaque;
634

635
    if (s->stage == BLOCK_REPLICATION_NONE) {
636
        error_setg(errp, "Block replication is not running");
637
        return;
638
    }
639

640
    if (s->error) {
641
        error_setg(errp, "I/O error occurred");
642
        return;
643
    }
644
}
645

646
static void replication_done(void *opaque, int ret)
647
{
648
    BlockDriverState *bs = opaque;
649
    BDRVReplicationState *s = bs->opaque;
650

651
    if (ret == 0) {
652
        s->stage = BLOCK_REPLICATION_DONE;
653

654
        bdrv_graph_wrlock();
655
        bdrv_unref_child(bs, s->secondary_disk);
656
        s->secondary_disk = NULL;
657
        bdrv_unref_child(bs, s->hidden_disk);
658
        s->hidden_disk = NULL;
659
        bdrv_graph_wrunlock();
660

661
        s->error = 0;
662
    } else {
663
        s->stage = BLOCK_REPLICATION_FAILOVER_FAILED;
664
        s->error = -EIO;
665
    }
666
}
667

668
static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
669
{
670
    BlockDriverState *bs = rs->opaque;
671
    BDRVReplicationState *s = bs->opaque;
672

673
    if (s->stage == BLOCK_REPLICATION_DONE ||
674
        s->stage == BLOCK_REPLICATION_FAILOVER) {
675
        /*
676
         * This case happens when a secondary was promoted to primary.
677
         * Ignore the request because the secondary side of replication
678
         * doesn't have to do anything anymore.
679
         */
680
        return;
681
    }
682

683
    if (s->stage != BLOCK_REPLICATION_RUNNING) {
684
        error_setg(errp, "Block replication is not running");
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, true);
701
        }
702

703
        if (!failover) {
704
            secondary_do_checkpoint(bs, errp);
705
            s->stage = BLOCK_REPLICATION_DONE;
706
            return;
707
        }
708

709
        bdrv_graph_rdlock_main_loop();
710
        s->stage = BLOCK_REPLICATION_FAILOVER;
711
        s->commit_job = commit_active_start(
712
                            NULL, bs->file->bs, s->secondary_disk->bs,
713
                            JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
714
                            NULL, replication_done, bs, true, errp);
715
        bdrv_graph_rdunlock_main_loop();
716
        break;
717
    default:
718
        abort();
719
    }
720
}
721

722
static const char *const replication_strong_runtime_opts[] = {
723
    REPLICATION_MODE,
724
    REPLICATION_TOP_ID,
725

726
    NULL
727
};
728

729
static BlockDriver bdrv_replication = {
730
    .format_name                = "replication",
731
    .instance_size              = sizeof(BDRVReplicationState),
732

733
    .bdrv_open                  = replication_open,
734
    .bdrv_close                 = replication_close,
735
    .bdrv_child_perm            = replication_child_perm,
736

737
    .bdrv_co_getlength          = replication_co_getlength,
738
    .bdrv_co_readv              = replication_co_readv,
739
    .bdrv_co_writev             = replication_co_writev,
740

741
    .is_filter                  = true,
742

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);
752

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.