aboutsummaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
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)
{