quorum: Implement .bdrv_recurse_can_replace()
Signed-off-by: Max Reitz <mreitz@redhat.com> Message-Id: <20200218103454.296704-9-mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
998a6b2fc5
commit
a3ed794b36
@ -813,6 +813,59 @@ static bool quorum_recurse_is_first_non_filter(BlockDriverState *bs,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool quorum_recurse_can_replace(BlockDriverState *bs,
|
||||||
|
BlockDriverState *to_replace)
|
||||||
|
{
|
||||||
|
BDRVQuorumState *s = bs->opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < s->num_children; i++) {
|
||||||
|
/*
|
||||||
|
* We have no idea whether our children show the same data as
|
||||||
|
* this node (@bs). It is actually highly likely that
|
||||||
|
* @to_replace does not, because replacing a broken child is
|
||||||
|
* one of the main use cases here.
|
||||||
|
*
|
||||||
|
* We do know that the new BDS will match @bs, so replacing
|
||||||
|
* any of our children by it will be safe. It cannot change
|
||||||
|
* the data this quorum node presents to its parents.
|
||||||
|
*
|
||||||
|
* However, replacing @to_replace by @bs in any of our
|
||||||
|
* children's chains may change visible data somewhere in
|
||||||
|
* there. We therefore cannot recurse down those chains with
|
||||||
|
* bdrv_recurse_can_replace().
|
||||||
|
* (More formally, bdrv_recurse_can_replace() requires that
|
||||||
|
* @to_replace will be replaced by something matching the @bs
|
||||||
|
* passed to it. We cannot guarantee that.)
|
||||||
|
*
|
||||||
|
* Thus, we can only check whether any of our immediate
|
||||||
|
* children matches @to_replace.
|
||||||
|
*
|
||||||
|
* (In the future, we might add a function to recurse down a
|
||||||
|
* chain that checks that nothing there cares about a change
|
||||||
|
* in data from the respective child in question. For
|
||||||
|
* example, most filters do not care when their child's data
|
||||||
|
* suddenly changes, as long as their parents do not care.)
|
||||||
|
*/
|
||||||
|
if (s->children[i]->bs == to_replace) {
|
||||||
|
/*
|
||||||
|
* We now have to ensure that there is no other parent
|
||||||
|
* that cares about replacing this child by a node with
|
||||||
|
* potentially different data.
|
||||||
|
* We do so by checking whether there are any other parents
|
||||||
|
* at all, which is stricter than necessary, but also very
|
||||||
|
* simple. (We may decide to implement something more
|
||||||
|
* complex and permissive when there is an actual need for
|
||||||
|
* it.)
|
||||||
|
*/
|
||||||
|
return QLIST_FIRST(&to_replace->parents) == s->children[i] &&
|
||||||
|
QLIST_NEXT(s->children[i], next_parent) == NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int quorum_valid_threshold(int threshold, int num_children, Error **errp)
|
static int quorum_valid_threshold(int threshold, int num_children, Error **errp)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1164,6 +1217,7 @@ static BlockDriver bdrv_quorum = {
|
|||||||
|
|
||||||
.is_filter = true,
|
.is_filter = true,
|
||||||
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
|
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
|
||||||
|
.bdrv_recurse_can_replace = quorum_recurse_can_replace,
|
||||||
|
|
||||||
.strong_runtime_opts = quorum_strong_runtime_opts,
|
.strong_runtime_opts = quorum_strong_runtime_opts,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user