aboutsummaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2015-09-15 11:58:23 +0200
committerKevin Wolf <kwolf@redhat.com>2015-10-16 15:34:30 +0200
commit3f09bfbc7bee812a44838f4c8b254007a9b86cab (patch)
tree775e62f32f4e2aa77a60a952212044060f11bcdd /block.c
parent8ccb9569a976056c9594bb720ba33d84827648d9 (diff)
block: Add and use bdrv_replace_in_backing_chain()
This cleans up the mess we left behind in the mirror code after the previous patch. Instead of using bdrv_swap(), just change pointers. The interface change of the mirror job that callers must consider is that after job completion, their local BDS pointers still point to the same node now. qemu-img must change its code accordingly (which makes it easier to understand); the other callers stays unchanged because after completion they don't do anything with the BDS, but just with the job, and the job is still owned by the source BDS. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Fam Zheng <famz@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'block.c')
-rw-r--r--block.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/block.c b/block.c
index b4d2313a9b..7c66d3ec26 100644
--- a/block.c
+++ b/block.c
@@ -1095,7 +1095,7 @@ static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
return child;
}
-void bdrv_detach_child(BdrvChild *child)
+static void bdrv_detach_child(BdrvChild *child)
{
QLIST_REMOVE(child, next);
QLIST_REMOVE(child, next_parent);
@@ -2232,6 +2232,36 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
bdrv_unref(bs_new);
}
+void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new)
+{
+ assert(!bdrv_requests_pending(old));
+ assert(!bdrv_requests_pending(new));
+
+ bdrv_ref(old);
+
+ if (old->blk) {
+ /* As long as these fields aren't in BlockBackend, but in the top-level
+ * BlockDriverState, it's not possible for a BDS to have two BBs.
+ *
+ * We really want to copy the fields from old to new, but we go for a
+ * swap instead so that pointers aren't duplicated and cause trouble.
+ * (Also, bdrv_swap() used to do the same.) */
+ assert(!new->blk);
+ swap_feature_fields(old, new);
+ }
+ change_parent_backing_link(old, new);
+
+ /* Change backing files if a previously independent node is added to the
+ * chain. For active commit, we replace top by its own (indirect) backing
+ * file and don't do anything here so we don't build a loop. */
+ if (new->backing == NULL && !bdrv_chain_contains(backing_bs(old), new)) {
+ bdrv_set_backing_hd(new, backing_bs(old));
+ bdrv_set_backing_hd(old, NULL);
+ }
+
+ bdrv_unref(old);
+}
+
static void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->job);