aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Reitz <mreitz@redhat.com>2016-06-10 20:57:46 +0200
committerMax Reitz <mreitz@redhat.com>2016-06-16 15:20:37 +0200
commit9bd910e2cbe413ab5927068bf189e929cb6790bc (patch)
tree3fc6200baa141e7a361d3fe927be7d826ea90b22
parent87cd3d20e1e9b31315bf416d6e720cf7e3eb2ea9 (diff)
block: Allow replacement of a BDS by its overlay
change_parent_backing_link() asserts that the BDS to be replaced is not used as a backing file. However, we may want to replace a BDS by its overlay in which case that very link should not be redirected. For instance, when doing a sync=none drive-mirror operation, we may have the following BDS/BB forest before block job completion: target base <- source <- BlockBackend During job completion, we want to establish the source BDS as the target's backing node: target | v base <- source <- BlockBackend This makes the target a valid replacement for the source: target <- BlockBackend | v base <- source Without this modification to change_parent_backing_link() we have to inject the target into the graph before the source is its backing node, thus temporarily creating a wrong graph: target <- BlockBackend base <- source Signed-off-by: Max Reitz <mreitz@redhat.com> Message-id: 20160610185750.30956-2-mreitz@redhat.com Reviewed-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Fam Zheng <famz@redhat.com> Signed-off-by: Max Reitz <mreitz@redhat.com>
-rw-r--r--block.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/block.c b/block.c
index 8104225cd3..d090324c68 100644
--- a/block.c
+++ b/block.c
@@ -2226,9 +2226,23 @@ void bdrv_close_all(void)
static void change_parent_backing_link(BlockDriverState *from,
BlockDriverState *to)
{
- BdrvChild *c, *next;
+ BdrvChild *c, *next, *to_c;
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
+ if (c->role == &child_backing) {
+ /* @from is generally not allowed to be a backing file, except for
+ * when @to is the overlay. In that case, @from may not be replaced
+ * by @to as @to's backing node. */
+ QLIST_FOREACH(to_c, &to->children, next) {
+ if (to_c == c) {
+ break;
+ }
+ }
+ if (to_c) {
+ continue;
+ }
+ }
+
assert(c->role != &child_backing);
bdrv_ref(to);
bdrv_replace_child(c, to);