diff options
-rw-r--r-- | block.c | 66 | ||||
-rw-r--r-- | block/block-backend.c | 8 | ||||
-rw-r--r-- | include/block/block_int.h | 15 |
3 files changed, 78 insertions, 11 deletions
@@ -1326,6 +1326,38 @@ static int bdrv_fill_options(QDict **options, const char *filename, return 0; } +static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, + uint64_t new_shared_perm, + BdrvChild *ignore_child, Error **errp) +{ + BdrvChild *c; + + /* There is no reason why anyone couldn't tolerate write_unchanged */ + assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED); + + QLIST_FOREACH(c, &bs->parents, next_parent) { + if (c == ignore_child) { + continue; + } + + if ((new_used_perm & c->shared_perm) != new_used_perm || + (c->perm & new_shared_perm) != c->perm) + { + const char *user = NULL; + if (c->role->get_name) { + user = c->role->get_name(c); + if (user && !*user) { + user = NULL; + } + } + error_setg(errp, "Conflicts with %s", user ?: "another operation"); + return -EPERM; + } + } + + return 0; +} + static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) { BlockDriverState *old_bs = child->bs; @@ -1350,14 +1382,25 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name, const BdrvChildRole *child_role, - void *opaque) + uint64_t perm, uint64_t shared_perm, + void *opaque, Error **errp) { - BdrvChild *child = g_new(BdrvChild, 1); + BdrvChild *child; + int ret; + + ret = bdrv_check_update_perm(child_bs, perm, shared_perm, NULL, errp); + if (ret < 0) { + return NULL; + } + + child = g_new(BdrvChild, 1); *child = (BdrvChild) { - .bs = NULL, - .name = g_strdup(child_name), - .role = child_role, - .opaque = opaque, + .bs = NULL, + .name = g_strdup(child_name), + .role = child_role, + .perm = perm, + .shared_perm = shared_perm, + .opaque = opaque, }; bdrv_replace_child(child, child_bs); @@ -1371,8 +1414,15 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, const BdrvChildRole *child_role, Error **errp) { - BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role, - parent_bs); + BdrvChild *child; + + /* FIXME Use real permissions */ + child = bdrv_root_attach_child(child_bs, child_name, child_role, + 0, BLK_PERM_ALL, parent_bs, errp); + if (child == NULL) { + return NULL; + } + QLIST_INSERT_HEAD(&parent_bs->children, child, next); return child; } diff --git a/block/block-backend.c b/block/block-backend.c index 492e71e41f..9bb45285ef 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -163,7 +163,9 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, return NULL; } - blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk); + /* FIXME Use real permissions */ + blk->root = bdrv_root_attach_child(bs, "root", &child_root, + 0, BLK_PERM_ALL, blk, &error_abort); return blk; } @@ -498,7 +500,9 @@ void blk_remove_bs(BlockBackend *blk) void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs) { bdrv_ref(bs); - blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk); + /* FIXME Use real permissions */ + blk->root = bdrv_root_attach_child(bs, "root", &child_root, + 0, BLK_PERM_ALL, blk, &error_abort); notifier_list_notify(&blk->insert_bs_notifiers, blk); if (blk->public.throttle_state) { diff --git a/include/block/block_int.h b/include/block/block_int.h index 1670941da9..ed63badcfb 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -419,6 +419,18 @@ struct BdrvChild { char *name; const BdrvChildRole *role; void *opaque; + + /** + * Granted permissions for operating on this BdrvChild (BLK_PERM_* bitmask) + */ + uint64_t perm; + + /** + * Permissions that can still be granted to other users of @bs while this + * BdrvChild is still attached to it. (BLK_PERM_* bitmask) + */ + uint64_t shared_perm; + QLIST_ENTRY(BdrvChild) next; QLIST_ENTRY(BdrvChild) next_parent; }; @@ -796,7 +808,8 @@ void hmp_drive_add_node(Monitor *mon, const char *optstr); BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name, const BdrvChildRole *child_role, - void *opaque); + uint64_t perm, uint64_t shared_perm, + void *opaque, Error **errp); void bdrv_root_unref_child(BdrvChild *child); const char *bdrv_get_parent_name(const BlockDriverState *bs); |