summaryrefslogtreecommitdiffstats
path: root/block.c
diff options
context:
space:
mode:
authorAlberto Garcia2018-10-31 17:16:38 +0100
committerKevin Wolf2018-11-22 19:37:31 +0100
commit6bd858b3117a5aab066f3cf02ca72000eaa10ddb (patch)
treec95dfd113fd866dadd58a3d33c7b2e69ed0b097b /block.c
parentblock: Update BlockDriverState.inherits_from on bdrv_set_backing_hd() (diff)
downloadqemu-6bd858b3117a5aab066f3cf02ca72000eaa10ddb.tar.gz
qemu-6bd858b3117a5aab066f3cf02ca72000eaa10ddb.tar.xz
qemu-6bd858b3117a5aab066f3cf02ca72000eaa10ddb.zip
block: Update BlockDriverState.inherits_from on bdrv_drop_intermediate()
The previous patch fixed the inherits_from pointer after block-stream, and this one does the same for block-commit. When block-commit finishes and the 'top' node is not the topmost one from the backing chain then all nodes above 'base' up to and including 'top' are removed from the chain. The bdrv_drop_intermediate() call converts a chain like this one: base <- intermediate <- top <- active into this one: base <- active In a simple scenario each backing file from the first chain has the inherits_from attribute pointing to its parent. This means that reopening 'active' will recursively reopen all its children, whose options can be changed in the process. However after the 'block-commit' call base.inherits_from is NULL and the chain is broken, so 'base' does not inherit from 'active' and will not be reopened automatically: $ qemu-img create -f qcow2 hd0.qcow2 1M $ qemu-img create -f qcow2 -b hd0.qcow2 hd1.qcow2 $ qemu-img create -f qcow2 -b hd1.qcow2 hd2.qcow2 $ $QEMU -drive if=none,file=hd2.qcow2 { 'execute': 'block-commit', 'arguments': { 'device': 'none0', 'top': 'hd1.qcow2' } } { 'execute': 'human-monitor-command', 'arguments': { 'command-line': 'qemu-io none0 "reopen -o backing.l2-cache-size=2M"' } } { "return": "Cannot change the option 'backing.l2-cache-size'\r\n"} This patch updates base.inherits_from in this scenario, and adds a test case. Signed-off-by: Alberto Garcia <berto@igalia.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block.c')
-rw-r--r--block.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/block.c b/block.c
index fe0cdc7d99..5ba3435f8f 100644
--- a/block.c
+++ b/block.c
@@ -3855,6 +3855,8 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
const char *backing_file_str)
{
+ BlockDriverState *explicit_top = top;
+ bool update_inherits_from;
BdrvChild *c, *next;
Error *local_err = NULL;
int ret = -EIO;
@@ -3870,6 +3872,16 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
goto exit;
}
+ /* If 'base' recursively inherits from 'top' then we should set
+ * base->inherits_from to top->inherits_from after 'top' and all
+ * other intermediate nodes have been dropped.
+ * If 'top' is an implicit node (e.g. "commit_top") we should skip
+ * it because no one inherits from it. We use explicit_top for that. */
+ while (explicit_top && explicit_top->implicit) {
+ explicit_top = backing_bs(explicit_top);
+ }
+ update_inherits_from = bdrv_inherits_from_recursive(base, explicit_top);
+
/* success - we can delete the intermediate states, and link top->base */
/* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once
* we've figured out how they should work. */
@@ -3905,6 +3917,10 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
bdrv_unref(top);
}
+ if (update_inherits_from) {
+ base->inherits_from = explicit_top->inherits_from;
+ }
+
ret = 0;
exit:
bdrv_unref(top);