diff options
Diffstat (limited to 'block/quorum.c')
-rw-r--r-- | block/quorum.c | 100 |
1 files changed, 66 insertions, 34 deletions
diff --git a/block/quorum.c b/block/quorum.c index da15465a9a..9cf876fb34 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -14,6 +14,7 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "block/block_int.h" #include "qapi/qmp/qbool.h" #include "qapi/qmp/qdict.h" @@ -67,6 +68,9 @@ typedef struct QuorumVotes { typedef struct BDRVQuorumState { BdrvChild **children; /* children BlockDriverStates */ int num_children; /* children count */ + unsigned next_child_index; /* the index of the next child that should + * be added + */ int threshold; /* if less than threshold children reads gave the * same result a quorum error occurs. */ @@ -379,7 +383,7 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb, continue; } QLIST_FOREACH(item, &version->items, next) { - bdrv_aio_writev(s->children[item->index]->bs, acb->sector_num, + bdrv_aio_writev(s->children[item->index], acb->sector_num, acb->qiov, acb->nb_sectors, quorum_rewrite_aio_cb, acb); } @@ -656,7 +660,7 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb) } for (i = 0; i < s->num_children; i++) { - acb->qcrs[i].aiocb = bdrv_aio_readv(s->children[i]->bs, acb->sector_num, + acb->qcrs[i].aiocb = bdrv_aio_readv(s->children[i], acb->sector_num, &acb->qcrs[i].qiov, acb->nb_sectors, quorum_aio_cb, &acb->qcrs[i]); } @@ -674,7 +678,7 @@ static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb) qemu_iovec_clone(&acb->qcrs[acb->child_iter].qiov, acb->qiov, acb->qcrs[acb->child_iter].buf); acb->qcrs[acb->child_iter].aiocb = - bdrv_aio_readv(s->children[acb->child_iter]->bs, acb->sector_num, + bdrv_aio_readv(s->children[acb->child_iter], acb->sector_num, &acb->qcrs[acb->child_iter].qiov, acb->nb_sectors, quorum_aio_cb, &acb->qcrs[acb->child_iter]); @@ -715,7 +719,7 @@ static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs, int i; for (i = 0; i < s->num_children; i++) { - acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i]->bs, sector_num, + acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i], sector_num, qiov, nb_sectors, &quorum_aio_cb, &acb->qcrs[i]); } @@ -747,21 +751,6 @@ static int64_t quorum_getlength(BlockDriverState *bs) return result; } -static void quorum_invalidate_cache(BlockDriverState *bs, Error **errp) -{ - BDRVQuorumState *s = bs->opaque; - Error *local_err = NULL; - int i; - - for (i = 0; i < s->num_children; i++) { - bdrv_invalidate_cache(s->children[i]->bs, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } -} - static coroutine_fn int quorum_co_flush(BlockDriverState *bs) { BDRVQuorumState *s = bs->opaque; @@ -898,9 +887,9 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, ret = -EINVAL; goto exit; } - if (s->num_children < 2) { + if (s->num_children < 1) { error_setg(&local_err, - "Number of provided children must be greater than 1"); + "Number of provided children must be 1 or more"); ret = -EINVAL; goto exit; } @@ -964,6 +953,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, opened[i] = true; } + s->next_child_index = s->num_children; g_free(opened); goto exit; @@ -981,9 +971,7 @@ close_exit: exit: qemu_opts_del(opts); /* propagate error */ - if (local_err) { - error_propagate(errp, local_err); - } + error_propagate(errp, local_err); return ret; } @@ -999,25 +987,70 @@ static void quorum_close(BlockDriverState *bs) g_free(s->children); } -static void quorum_detach_aio_context(BlockDriverState *bs) +static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, + Error **errp) { BDRVQuorumState *s = bs->opaque; - int i; + BdrvChild *child; + char indexstr[32]; + int ret; - for (i = 0; i < s->num_children; i++) { - bdrv_detach_aio_context(s->children[i]->bs); + assert(s->num_children <= INT_MAX / sizeof(BdrvChild *)); + if (s->num_children == INT_MAX / sizeof(BdrvChild *) || + s->next_child_index == UINT_MAX) { + error_setg(errp, "Too many children"); + return; } + + ret = snprintf(indexstr, 32, "children.%u", s->next_child_index); + if (ret < 0 || ret >= 32) { + error_setg(errp, "cannot generate child name"); + return; + } + s->next_child_index++; + + bdrv_drained_begin(bs); + + /* We can safely add the child now */ + bdrv_ref(child_bs); + child = bdrv_attach_child(bs, child_bs, indexstr, &child_format); + s->children = g_renew(BdrvChild *, s->children, s->num_children + 1); + s->children[s->num_children++] = child; + + bdrv_drained_end(bs); } -static void quorum_attach_aio_context(BlockDriverState *bs, - AioContext *new_context) +static void quorum_del_child(BlockDriverState *bs, BdrvChild *child, + Error **errp) { BDRVQuorumState *s = bs->opaque; int i; for (i = 0; i < s->num_children; i++) { - bdrv_attach_aio_context(s->children[i]->bs, new_context); + if (s->children[i] == child) { + break; + } } + + /* we have checked it in bdrv_del_child() */ + assert(i < s->num_children); + + if (s->num_children <= s->threshold) { + error_setg(errp, + "The number of children cannot be lower than the vote threshold %d", + s->threshold); + return; + } + + bdrv_drained_begin(bs); + + /* We can safely remove this child now */ + memmove(&s->children[i], &s->children[i + 1], + (s->num_children - i - 1) * sizeof(BdrvChild *)); + s->children = g_renew(BdrvChild *, s->children, --s->num_children); + bdrv_unref_child(bs, child); + + bdrv_drained_end(bs); } static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) @@ -1070,10 +1103,9 @@ static BlockDriver bdrv_quorum = { .bdrv_aio_readv = quorum_aio_readv, .bdrv_aio_writev = quorum_aio_writev, - .bdrv_invalidate_cache = quorum_invalidate_cache, - .bdrv_detach_aio_context = quorum_detach_aio_context, - .bdrv_attach_aio_context = quorum_attach_aio_context, + .bdrv_add_child = quorum_add_child, + .bdrv_del_child = quorum_del_child, .is_filter = true, .bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter, |