4 * Copyright (C) 2012-2014 Nodalink, EURL.
7 * BenoƮt Canet <benoit.canet@irqsave.net>
9 * Based on the design and code of blkverify.c (Copyright (C) 2010 IBM, Corp)
10 * and blkmirror.c (Copyright (C) 2011 Red Hat, Inc).
12 * This work is licensed under the terms of the GNU GPL, version 2 or later.
13 * See the COPYING file in the top-level directory.
16 #include "block/block_int.h"
18 /* the following structure holds the state of one quorum instance */
19 typedef struct BDRVQuorumState
{
20 BlockDriverState
**bs
; /* children BlockDriverStates */
21 int num_children
; /* children count */
22 int threshold
; /* if less than threshold children reads gave the
23 * same result a quorum error occurs.
25 bool is_blkverify
; /* true if the driver is in blkverify mode
26 * Writes are mirrored on two children devices.
27 * On reads the two children devices' contents are
28 * compared and if a difference is spotted its
29 * location is printed and the code aborts.
30 * It is useful to debug other block drivers by
31 * comparing them with a reference one.
35 typedef struct QuorumAIOCB QuorumAIOCB
;
37 /* Quorum will create one instance of the following structure per operation it
38 * performs on its children.
39 * So for each read/write operation coming from the upper layer there will be
40 * $children_count QuorumChildRequest.
42 typedef struct QuorumChildRequest
{
43 BlockDriverAIOCB
*aiocb
;
50 /* Quorum will use the following structure to track progress of each read/write
51 * operation received by the upper layer.
52 * This structure hold pointers to the QuorumChildRequest structures instances
53 * used to do operations on each children and track overall progress.
56 BlockDriverAIOCB common
;
58 /* Request metadata */
62 QEMUIOVector
*qiov
; /* calling IOV */
64 QuorumChildRequest
*qcrs
; /* individual child requests */
65 int count
; /* number of completed AIOCB */
66 int success_count
; /* number of successfully completed AIOCB */
72 static void quorum_aio_cancel(BlockDriverAIOCB
*blockacb
)
74 QuorumAIOCB
*acb
= container_of(blockacb
, QuorumAIOCB
, common
);
75 BDRVQuorumState
*s
= acb
->common
.bs
->opaque
;
78 /* cancel all callbacks */
79 for (i
= 0; i
< s
->num_children
; i
++) {
80 bdrv_aio_cancel(acb
->qcrs
[i
].aiocb
);
84 qemu_aio_release(acb
);
87 static AIOCBInfo quorum_aiocb_info
= {
88 .aiocb_size
= sizeof(QuorumAIOCB
),
89 .cancel
= quorum_aio_cancel
,
92 static void quorum_aio_finalize(QuorumAIOCB
*acb
)
96 acb
->common
.cb(acb
->common
.opaque
, ret
);
99 qemu_aio_release(acb
);
102 static QuorumAIOCB
*quorum_aio_get(BDRVQuorumState
*s
,
103 BlockDriverState
*bs
,
107 BlockDriverCompletionFunc
*cb
,
110 QuorumAIOCB
*acb
= qemu_aio_get(&quorum_aiocb_info
, bs
, cb
, opaque
);
113 acb
->common
.bs
->opaque
= s
;
114 acb
->sector_num
= sector_num
;
115 acb
->nb_sectors
= nb_sectors
;
117 acb
->qcrs
= g_new0(QuorumChildRequest
, s
->num_children
);
119 acb
->success_count
= 0;
120 acb
->is_read
= false;
123 for (i
= 0; i
< s
->num_children
; i
++) {
124 acb
->qcrs
[i
].buf
= NULL
;
125 acb
->qcrs
[i
].ret
= 0;
126 acb
->qcrs
[i
].parent
= acb
;
132 static void quorum_aio_cb(void *opaque
, int ret
)
134 QuorumChildRequest
*sacb
= opaque
;
135 QuorumAIOCB
*acb
= sacb
->parent
;
136 BDRVQuorumState
*s
= acb
->common
.bs
->opaque
;
141 acb
->success_count
++;
143 assert(acb
->count
<= s
->num_children
);
144 assert(acb
->success_count
<= s
->num_children
);
145 if (acb
->count
< s
->num_children
) {
149 quorum_aio_finalize(acb
);
152 static BlockDriverAIOCB
*quorum_aio_writev(BlockDriverState
*bs
,
156 BlockDriverCompletionFunc
*cb
,
159 BDRVQuorumState
*s
= bs
->opaque
;
160 QuorumAIOCB
*acb
= quorum_aio_get(s
, bs
, qiov
, sector_num
, nb_sectors
,
164 for (i
= 0; i
< s
->num_children
; i
++) {
165 acb
->qcrs
[i
].aiocb
= bdrv_aio_writev(s
->bs
[i
], sector_num
, qiov
,
166 nb_sectors
, &quorum_aio_cb
,
173 static BlockDriver bdrv_quorum
= {
174 .format_name
= "quorum",
175 .protocol_name
= "quorum",
177 .instance_size
= sizeof(BDRVQuorumState
),
179 .bdrv_aio_writev
= quorum_aio_writev
,
182 static void bdrv_quorum_init(void)
184 bdrv_register(&bdrv_quorum
);
187 block_init(bdrv_quorum_init
);