Signed-off-by: Benoit Canet <ben...@irqsave.net> --- block/qorum.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 6 deletions(-)
diff --git a/block/qorum.c b/block/qorum.c index 772d138..1f307b6 100644 --- a/block/qorum.c +++ b/block/qorum.c @@ -175,7 +175,7 @@ static int qorum_check_ret(QorumAIOCB *acb) static void qorum_aio_bh(void *opaque) { QorumAIOCB *acb = opaque; - int i; + int i, ret; for (i = 0; i <= 2; i++) { if (acb->aios[i].buf) { @@ -185,7 +185,12 @@ static void qorum_aio_bh(void *opaque) } qemu_bh_delete(acb->bh); - acb->common.cb(acb->common.opaque, qorum_check_ret(acb)); + if (acb->vote_ret) { + ret = acb->vote_ret; + } else { + ret = qorum_check_ret(acb); + } + acb->common.cb(acb->common.opaque, ret); if (acb->finished) { *acb->finished = true; } @@ -229,10 +234,75 @@ static void qorum_aio_cb(void *opaque, int ret) sacb->ret = ret; acb->count++; assert(acb->count <= 3); - if (acb->count == 3) { - acb->bh = qemu_bh_new(qorum_aio_bh, acb); - qemu_bh_schedule(acb->bh); + if (acb->count < 3) { + return; } + + /* Do the qorum */ + if (acb->vote) { + acb->vote(acb); + } + + acb->bh = qemu_bh_new(qorum_aio_bh, acb); + qemu_bh_schedule(acb->bh); +} + +static void qorum_print_bad(QorumAIOCB *acb, const char *filename) +{ + fprintf(stderr, "qorum: corrected error in qorum file %s: sector_num=%" + PRId64 " nb_sectors=%i\n", filename, acb->sector_num, + acb->nb_sectors); +} + +static void qorum_print_failure(QorumAIOCB *acb) +{ + fprintf(stderr, "qorum: failure sector_num=%" PRId64 " nb_sectors=%i\n", + acb->sector_num, acb->nb_sectors); +} + +static void qorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source) +{ + int i; + for (i = 0; i < source->niov; i++) { + memcpy(dest->iov[i].iov_base, + source->iov[i].iov_base, + source->iov[i].iov_len); + dest->iov[i].iov_len = source->iov[i].iov_len; + } + dest->niov = source->niov; + dest->nalloc = source->nalloc; + dest->size = source->size; +} + +static void qorum_vote(QorumAIOCB *acb) +{ + ssize_t a_b, b_c, a_c; + a_b = blkverify_iovec_compare(&acb->qiovs[0], &acb->qiovs[1]); + b_c = blkverify_iovec_compare(&acb->qiovs[1], &acb->qiovs[2]); + + /* Three vector identical -> qorum */ + if (a_b == b_c && a_b == -1) { + qorum_copy_qiov(acb->qiov, &acb->qiovs[0]); /*clone a */ + return; + } + if (a_b == -1) { + qorum_print_bad(acb, "C"); + qorum_copy_qiov(acb->qiov, &acb->qiovs[0]); /*clone a */ + return; + } + if (b_c == -1) { + qorum_print_bad(acb, "A"); + qorum_copy_qiov(acb->qiov, &acb->qiovs[1]); /*clone b */ + return; + } + a_c = blkverify_iovec_compare(&acb->qiovs[0], &acb->qiovs[2]); + if (a_c == -1) { + qorum_print_bad(acb, "B"); + qorum_copy_qiov(acb->qiov, &acb->qiovs[0]); /*clone a */ + return; + } + qorum_print_failure(acb); + acb->vote_ret = -EIO; } static BlockDriverAIOCB *qorum_aio_readv(BlockDriverState *bs, @@ -247,6 +317,8 @@ static BlockDriverAIOCB *qorum_aio_readv(BlockDriverState *bs, nb_sectors, cb, opaque); int i; + acb->vote = qorum_vote; + for (i = 0; i <= 2; i++) { acb->aios[i].buf = qemu_blockalign(bs->file, qiov->size); qemu_iovec_init(&acb->qiovs[i], qiov->niov); @@ -254,7 +326,7 @@ static BlockDriverAIOCB *qorum_aio_readv(BlockDriverState *bs, } for (i = 0; i <= 2; i++) { - bdrv_aio_readv(s->bs[i], sector_num, qiov, nb_sectors, + bdrv_aio_readv(s->bs[i], sector_num, &acb->qiovs[i], nb_sectors, qorum_aio_cb, &acb->aios[i]); } -- 1.7.9.5