diff --git a/block.c b/block.c index 170002e78eb9bcb84d8246438ffaef826c8a094c..50ba2641430aef9c18b9f1070dd59a1ab3891654 100644 --- a/block.c +++ b/block.c @@ -192,11 +192,20 @@ void path_combine(char *dest, int dest_size, } } +/* Returns whether the image file is opened as read-only. Note that this can + * return false and writing to the image file is still not possible because the + * image is inactivated. */ bool bdrv_is_read_only(BlockDriverState *bs) { return bs->read_only; } +/* Returns whether the image file can be written to right now */ +bool bdrv_is_writable(BlockDriverState *bs) +{ + return !bdrv_is_read_only(bs) && !(bs->open_flags & BDRV_O_INACTIVE); +} + int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp) { /* Do not set read_only if copy_on_read is enabled */ @@ -1510,7 +1519,7 @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, /* Write permissions never work with read-only images */ if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) && - bdrv_is_read_only(bs)) + !bdrv_is_writable(bs)) { error_setg(errp, "Block node is read-only"); return -EPERM; @@ -1795,7 +1804,7 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, bdrv_filter_default_perms(bs, c, role, perm, shared, &perm, &shared); /* Format drivers may touch metadata even if the guest doesn't write */ - if (!bdrv_is_read_only(bs)) { + if (bdrv_is_writable(bs)) { perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; } @@ -1821,6 +1830,10 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, BLK_PERM_WRITE_UNCHANGED; } + if (bs->open_flags & BDRV_O_INACTIVE) { + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + } + *nperm = perm; *nshared = shared; } @@ -3960,6 +3973,7 @@ void bdrv_init_with_whitelist(void) void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) { BdrvChild *child, *parent; + uint64_t perm, shared_perm; Error *local_err = NULL; int ret; @@ -3996,6 +4010,16 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) return; } + /* Update permissions, they may differ for inactive nodes */ + bdrv_get_cumulative_perm(bs, &perm, &shared_perm); + ret = bdrv_check_perm(bs, perm, shared_perm, 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); + QLIST_FOREACH(parent, &bs->parents, next_parent) { if (parent->role->activate) { parent->role->activate(parent, &local_err); @@ -4040,6 +4064,8 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs, } if (setting_flag) { + uint64_t perm, shared_perm; + bs->open_flags |= BDRV_O_INACTIVE; QLIST_FOREACH(parent, &bs->parents, next_parent) { @@ -4051,6 +4077,11 @@ 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, perm, shared_perm, NULL, &error_abort); + bdrv_set_perm(bs, perm, shared_perm); } QLIST_FOREACH(child, &bs->children, next) { diff --git a/include/block/block.h b/include/block/block.h index 80d51d8f123f70f6e9ca3087a793002d75f77951..90932b47095ec67259a2eebcac34da0dd0e9414a 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -435,6 +435,7 @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, int64_t sector_num, int nb_sectors, int *pnum); bool bdrv_is_read_only(BlockDriverState *bs); +bool bdrv_is_writable(BlockDriverState *bs); int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); bool bdrv_is_sg(BlockDriverState *bs);