aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2019-12-17 15:06:38 +0100
committerMichael Roth <mdroth@linux.vnet.ibm.com>2020-05-11 15:24:13 -0500
commit52a02834e0d54d59d9665e2d39c2259345df2335 (patch)
tree79f81a1a56e05b8b1efce76ed45fd7bcb7bd5e87
parentda0948d13ccc4553fec74002c8fc39392a11d5e4 (diff)
block: Activate recursively even for already active nodes
bdrv_invalidate_cache_all() assumes that all nodes in a given subtree are either active or inactive when it starts. Therefore, as soon as it arrives at an already active node, it stops. However, this assumption is wrong. For example, it's possible to take a snapshot of an inactive node, which results in an active overlay over an inactive backing file. The active overlay is probably also the root node of an inactive BlockBackend (blk->disable_perm == true). In this case, bdrv_invalidate_cache_all() does not need to do anything to activate the overlay node, but it still needs to recurse into the children and the parents to make sure that after returning success, really everything is activated. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> (cherry picked from commit 7bb4941ace471fc7dd6ded4749b95b9622baa6ed) Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
-rw-r--r--block.c50
1 files changed, 24 insertions, 26 deletions
diff --git a/block.c b/block.c
index 473eb6eeaa..2e5e8b639a 100644
--- a/block.c
+++ b/block.c
@@ -5335,10 +5335,6 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
return;
}
- if (!(bs->open_flags & BDRV_O_INACTIVE)) {
- return;
- }
-
QLIST_FOREACH(child, &bs->children, next) {
bdrv_co_invalidate_cache(child->bs, &local_err);
if (local_err) {
@@ -5360,34 +5356,36 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
* just keep the extended permissions for the next time that an activation
* of the image is tried.
*/
- bs->open_flags &= ~BDRV_O_INACTIVE;
- bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
- ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, &local_err);
- if (ret < 0) {
- bs->open_flags |= BDRV_O_INACTIVE;
- error_propagate(errp, local_err);
- return;
- }
- bdrv_set_perm(bs, perm, shared_perm);
-
- if (bs->drv->bdrv_co_invalidate_cache) {
- bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
- if (local_err) {
+ if (bs->open_flags & BDRV_O_INACTIVE) {
+ bs->open_flags &= ~BDRV_O_INACTIVE;
+ bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
+ ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, &local_err);
+ if (ret < 0) {
bs->open_flags |= BDRV_O_INACTIVE;
error_propagate(errp, local_err);
return;
}
- }
+ bdrv_set_perm(bs, perm, shared_perm);
- FOR_EACH_DIRTY_BITMAP(bs, bm) {
- bdrv_dirty_bitmap_skip_store(bm, false);
- }
+ if (bs->drv->bdrv_co_invalidate_cache) {
+ bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
+ if (local_err) {
+ bs->open_flags |= BDRV_O_INACTIVE;
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
- ret = refresh_total_sectors(bs, bs->total_sectors);
- if (ret < 0) {
- bs->open_flags |= BDRV_O_INACTIVE;
- error_setg_errno(errp, -ret, "Could not refresh total sector count");
- return;
+ FOR_EACH_DIRTY_BITMAP(bs, bm) {
+ bdrv_dirty_bitmap_skip_store(bm, false);
+ }
+
+ ret = refresh_total_sectors(bs, bs->total_sectors);
+ if (ret < 0) {
+ bs->open_flags |= BDRV_O_INACTIVE;
+ error_setg_errno(errp, -ret, "Could not refresh total sector count");
+ return;
+ }
}
QLIST_FOREACH(parent, &bs->parents, next_parent) {