aboutsummaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
authorMax Reitz <mreitz@redhat.com>2020-02-18 11:34:41 +0100
committerKevin Wolf <kwolf@redhat.com>2020-02-18 11:55:39 +0100
commit5d69b5ab85d30201c1f5ef34651ba910977fc583 (patch)
tree331cf09380c717614400c7905a3a0e8aa0681128 /block.c
parent37a3791b380584949046af6b62b54869390616dc (diff)
block: Add bdrv_recurse_can_replace()
After a couple of follow-up patches, this function will replace bdrv_recurse_is_first_non_filter() in check_to_replace_node(). bdrv_recurse_is_first_non_filter() is both not sufficiently specific for check_to_replace_node() (it allows cases that should not be allowed, like replacing child nodes of quorum with dissenting data that have more parents than just quorum), and it is too restrictive (it is perfectly fine to replace filters). Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Message-Id: <20200218103454.296704-7-mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block.c')
-rw-r--r--block.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/block.c b/block.c
index 145d0baf5e..e2fefe5883 100644
--- a/block.c
+++ b/block.c
@@ -6234,6 +6234,44 @@ bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
return false;
}
+/*
+ * This function checks whether the given @to_replace is allowed to be
+ * replaced by a node that always shows the same data as @bs. This is
+ * used for example to verify whether the mirror job can replace
+ * @to_replace by the target mirrored from @bs.
+ * To be replaceable, @bs and @to_replace may either be guaranteed to
+ * always show the same data (because they are only connected through
+ * filters), or some driver may allow replacing one of its children
+ * because it can guarantee that this child's data is not visible at
+ * all (for example, for dissenting quorum children that have no other
+ * parents).
+ */
+bool bdrv_recurse_can_replace(BlockDriverState *bs,
+ BlockDriverState *to_replace)
+{
+ if (!bs || !bs->drv) {
+ return false;
+ }
+
+ if (bs == to_replace) {
+ return true;
+ }
+
+ /* See what the driver can do */
+ if (bs->drv->bdrv_recurse_can_replace) {
+ return bs->drv->bdrv_recurse_can_replace(bs, to_replace);
+ }
+
+ /* For filters without an own implementation, we can recurse on our own */
+ if (bs->drv->is_filter) {
+ BdrvChild *child = bs->file ?: bs->backing;
+ return bdrv_recurse_can_replace(child->bs, to_replace);
+ }
+
+ /* Safe default */
+ return false;
+}
+
BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs,
const char *node_name, Error **errp)
{