aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block.c66
-rw-r--r--block/block-backend.c8
-rw-r--r--include/block/block_int.h15
3 files changed, 78 insertions, 11 deletions
diff --git a/block.c b/block.c
index 65240facf6..9628c7a3a9 100644
--- a/block.c
+++ b/block.c
@@ -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);