aboutsummaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'block.c')
-rw-r--r--block.c82
1 files changed, 49 insertions, 33 deletions
diff --git a/block.c b/block.c
index 0dc97281dc..3f456892d0 100644
--- a/block.c
+++ b/block.c
@@ -84,14 +84,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
static void bdrv_replace_child_noperm(BdrvChild *child,
BlockDriverState *new_bs);
-static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
- BlockDriverState *child_bs,
- const char *child_name,
- const BdrvChildClass *child_class,
- BdrvChildRole child_role,
- BdrvChild **child,
- Transaction *tran,
- Error **errp);
static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
Transaction *tran);
@@ -265,7 +257,7 @@ void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
* image is inactivated. */
bool bdrv_is_read_only(BlockDriverState *bs)
{
- return bs->read_only;
+ return !(bs->open_flags & BDRV_O_RDWR);
}
int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
@@ -317,7 +309,6 @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
goto fail;
}
- bs->read_only = true;
bs->open_flags &= ~BDRV_O_RDWR;
return 0;
@@ -1158,7 +1149,7 @@ int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough)
static char *bdrv_child_get_parent_desc(BdrvChild *c)
{
BlockDriverState *parent = c->opaque;
- return g_strdup(bdrv_get_device_or_node_name(parent));
+ return g_strdup_printf("node '%s'", bdrv_get_node_name(parent));
}
static void bdrv_child_cb_drained_begin(BdrvChild *child)
@@ -1412,7 +1403,7 @@ static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
return 0;
}
-static AioContext *bdrv_child_cb_get_parent_aio_context(BdrvChild *c)
+AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c)
{
BlockDriverState *bs = c->opaque;
@@ -1432,7 +1423,7 @@ const BdrvChildClass child_of_bds = {
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
.set_aio_ctx = bdrv_child_cb_set_aio_ctx,
.update_filename = bdrv_child_cb_update_filename,
- .get_parent_aio_context = bdrv_child_cb_get_parent_aio_context,
+ .get_parent_aio_context = child_of_bds_get_parent_aio_context,
};
AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c)
@@ -1549,7 +1540,6 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
}
bs->drv = drv;
- bs->read_only = !(bs->open_flags & BDRV_O_RDWR);
bs->opaque = g_malloc0(drv->instance_size);
if (drv->bdrv_file_open) {
@@ -1720,6 +1710,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
QemuOpts *opts;
BlockDriver *drv;
Error *local_err = NULL;
+ bool ro;
assert(bs->file == NULL);
assert(options != NULL && bs->options != options);
@@ -1770,17 +1761,17 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
trace_bdrv_open_common(bs, filename ?: "", bs->open_flags,
drv->format_name);
- bs->read_only = !(bs->open_flags & BDRV_O_RDWR);
+ ro = bdrv_is_read_only(bs);
- if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
- if (!bs->read_only && bdrv_is_whitelisted(drv, true)) {
+ if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, ro)) {
+ if (!ro && bdrv_is_whitelisted(drv, true)) {
ret = bdrv_apply_auto_read_only(bs, NULL, NULL);
} else {
ret = -ENOTSUP;
}
if (ret < 0) {
error_setg(errp,
- !bs->read_only && bdrv_is_whitelisted(drv, true)
+ !ro && bdrv_is_whitelisted(drv, true)
? "Driver '%s' can only be used for read-only devices"
: "Driver '%s' is not whitelisted",
drv->format_name);
@@ -1792,7 +1783,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
assert(qatomic_read(&bs->copy_on_read) == 0);
if (bs->open_flags & BDRV_O_COPY_ON_READ) {
- if (!bs->read_only) {
+ if (!ro) {
bdrv_enable_copy_on_read(bs);
} else {
error_setg(errp, "Can't use copy-on-read on read-only device");
@@ -2035,27 +2026,38 @@ bool bdrv_is_writable(BlockDriverState *bs)
static char *bdrv_child_user_desc(BdrvChild *c)
{
- if (c->klass->get_parent_desc) {
- return c->klass->get_parent_desc(c);
- }
-
- return g_strdup("another user");
+ return c->klass->get_parent_desc(c);
}
+/*
+ * Check that @a allows everything that @b needs. @a and @b must reference same
+ * child node.
+ */
static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp)
{
- g_autofree char *user = NULL;
- g_autofree char *perm_names = NULL;
+ const char *child_bs_name;
+ g_autofree char *a_user = NULL;
+ g_autofree char *b_user = NULL;
+ g_autofree char *perms = NULL;
+
+ assert(a->bs);
+ assert(a->bs == b->bs);
if ((b->perm & a->shared_perm) == b->perm) {
return true;
}
- perm_names = bdrv_perm_names(b->perm & ~a->shared_perm);
- user = bdrv_child_user_desc(a);
- error_setg(errp, "Conflicts with use by %s as '%s', which does not "
- "allow '%s' on %s",
- user, a->name, perm_names, bdrv_get_node_name(b->bs));
+ child_bs_name = bdrv_get_node_name(b->bs);
+ a_user = bdrv_child_user_desc(a);
+ b_user = bdrv_child_user_desc(b);
+ perms = bdrv_perm_names(b->perm & ~a->shared_perm);
+
+ error_setg(errp, "Permission conflict on node '%s': permissions '%s' are "
+ "both required by %s (uses node '%s' as '%s' child) and "
+ "unshared by %s (uses node '%s' as '%s' child).",
+ child_bs_name, perms,
+ b_user, child_bs_name, b->name,
+ a_user, child_bs_name, a->name);
return false;
}
@@ -2760,6 +2762,12 @@ static TransactionActionDrv bdrv_attach_child_common_drv = {
/*
* Common part of attaching bdrv child to bs or to blk or to job
+ *
+ * Resulting new child is returned through @child.
+ * At start *@child must be NULL.
+ * @child is saved to a new entry of @tran, so that *@child could be reverted to
+ * NULL on abort(). So referenced variable must live at least until transaction
+ * end.
*/
static int bdrv_attach_child_common(BlockDriverState *child_bs,
const char *child_name,
@@ -2775,6 +2783,7 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
assert(child);
assert(*child == NULL);
+ assert(child_class->get_parent_desc);
new_child = g_new(BdrvChild, 1);
*new_child = (BdrvChild) {
@@ -2834,6 +2843,10 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
return 0;
}
+/*
+ * Variable referenced by @child must live at least until transaction end.
+ * (see bdrv_attach_child_common() doc for details)
+ */
static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
const char *child_name,
@@ -2916,7 +2929,6 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
child_role, perm, shared_perm, opaque,
&child, tran, errp);
if (ret < 0) {
- assert(child == NULL);
goto out;
}
@@ -2924,6 +2936,9 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
out:
tran_finalize(tran, ret);
+ /* child is unset on failure by bdrv_attach_child_common_abort() */
+ assert((ret < 0) == !child);
+
bdrv_unref(child_bs);
return child;
}
@@ -2963,6 +2978,8 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
out:
tran_finalize(tran, ret);
+ /* child is unset on failure by bdrv_attach_child_common_abort() */
+ assert((ret < 0) == !child);
bdrv_unref(child_bs);
@@ -4545,7 +4562,6 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
bs->explicit_options = reopen_state->explicit_options;
bs->options = reopen_state->options;
bs->open_flags = reopen_state->flags;
- bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
bs->detect_zeroes = reopen_state->detect_zeroes;
if (reopen_state->replace_backing_bs) {