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;
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);
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;
}
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;
}
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) {
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;
};
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);