diff --git a/block.c b/block.c index 1b10a5ce35..c139540f2b 100644 --- a/block.c +++ b/block.c @@ -2121,11 +2121,26 @@ static void bdrv_child_abort_perm_update(BdrvChild *c) int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, Error **errp) { + Error *local_err = NULL; int ret; + bool tighten_restrictions; - ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL, NULL, errp); + ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL, + &tighten_restrictions, &local_err); if (ret < 0) { bdrv_child_abort_perm_update(c); + if (tighten_restrictions) { + error_propagate(errp, local_err); + } else { + /* + * Our caller may intend to only loosen restrictions and + * does not expect this function to fail. Errors are not + * fatal in such a case, so we can just hide them from our + * caller. + */ + error_free(local_err); + ret = 0; + } return ret; } @@ -2308,10 +2323,19 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) /* Update permissions for old node. This is guaranteed to succeed * because we're just taking a parent away, so we're loosening * restrictions. */ + bool tighten_restrictions; + int ret; + bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm); - bdrv_check_perm(old_bs, NULL, perm, shared_perm, NULL, - NULL, &error_abort); - bdrv_set_perm(old_bs, perm, shared_perm); + ret = bdrv_check_perm(old_bs, NULL, perm, shared_perm, NULL, + &tighten_restrictions, NULL); + assert(tighten_restrictions == false); + if (ret < 0) { + /* We only tried to loosen restrictions, so errors are not fatal */ + bdrv_abort_perm_update(old_bs); + } else { + bdrv_set_perm(old_bs, perm, shared_perm); + } /* When the parent requiring a non-default AioContext is removed, the * node moves back to the main AioContext */ @@ -5386,6 +5410,7 @@ static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) static int bdrv_inactivate_recurse(BlockDriverState *bs) { BdrvChild *child, *parent; + bool tighten_restrictions; uint64_t perm, shared_perm; int ret; @@ -5422,8 +5447,15 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs) /* Update permissions, they may differ for inactive nodes */ bdrv_get_cumulative_perm(bs, &perm, &shared_perm); - bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, &error_abort); - bdrv_set_perm(bs, perm, shared_perm); + ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, + &tighten_restrictions, NULL); + assert(tighten_restrictions == false); + if (ret < 0) { + /* We only tried to loosen restrictions, so errors are not fatal */ + bdrv_abort_perm_update(bs); + } else { + bdrv_set_perm(bs, perm, shared_perm); + } /* Recursively inactivate children */