aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block.c601
-rw-r--r--block/backup-top.c11
-rw-r--r--block/blkdebug.c10
-rw-r--r--block/blklogwrites.c16
-rw-r--r--block/blkreplay.c8
-rw-r--r--block/blkverify.c10
-rw-r--r--block/block-backend.c30
-rw-r--r--block/block-copy.c14
-rw-r--r--block/bochs.c7
-rw-r--r--block/cloop.c7
-rw-r--r--block/commit.c20
-rw-r--r--block/copy-on-read.c7
-rw-r--r--block/crypto.c8
-rw-r--r--block/dmg.c7
-rw-r--r--block/filter-compress.c7
-rw-r--r--block/io.c22
-rw-r--r--block/mirror.c25
-rw-r--r--block/parallels.c7
-rw-r--r--block/qcow.c7
-rw-r--r--block/qcow2.c20
-rw-r--r--block/qed.c7
-rw-r--r--block/quorum.c8
-rw-r--r--block/raw-format.c128
-rw-r--r--block/replication.c23
-rw-r--r--block/throttle.c7
-rw-r--r--block/vdi.c7
-rw-r--r--block/vhdx.c7
-rw-r--r--block/vmdk.c23
-rw-r--r--block/vpc.c7
-rw-r--r--block/vvfat.c17
-rw-r--r--blockjob.c7
-rw-r--r--hw/arm/sbsa-ref.c2
-rw-r--r--hw/arm/virt.c2
-rw-r--r--hw/block/pflash_cfi01.c2
-rw-r--r--hw/block/pflash_cfi02.c2
-rw-r--r--hw/i386/pc_sysfw.c2
-rw-r--r--hw/ide/ahci.c1
-rw-r--r--hw/riscv/virt.c2
-rw-r--r--include/block/block.h65
-rw-r--r--include/block/block_int.h57
-rw-r--r--include/sysemu/block-backend.h2
-rw-r--r--qemu-img.c19
-rwxr-xr-xtests/qemu-iotests/0306
-rwxr-xr-xtests/qemu-iotests/04145
-rw-r--r--tests/qemu-iotests/041.out4
-rw-r--r--tests/qemu-iotests/098.out8
-rwxr-xr-xtests/qemu-iotests/10910
-rw-r--r--tests/qemu-iotests/109.out74
-rwxr-xr-xtests/qemu-iotests/22918
-rw-r--r--tests/qemu-iotests/229.out6
-rwxr-xr-xtests/qemu-iotests/29744
-rw-r--r--tests/qemu-iotests/297.out3
-rw-r--r--tests/qemu-iotests/common.filter5
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/qemu-iotests/iotests.py19
-rw-r--r--tests/test-bdrv-drain.c72
-rw-r--r--tests/test-bdrv-graph-mod.c10
-rw-r--r--tests/test-block-iothread.c17
58 files changed, 1003 insertions, 580 deletions
diff --git a/block.c b/block.c
index 0653ccb913..8416376c9b 100644
--- a/block.c
+++ b/block.c
@@ -76,7 +76,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
const char *reference,
QDict *options, int flags,
BlockDriverState *parent,
- const BdrvChildRole *child_role,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
Error **errp);
/* If non-zero, use only whitelisted block drivers */
@@ -1093,18 +1094,6 @@ static void bdrv_child_cb_drained_end(BdrvChild *child,
bdrv_drained_end_no_poll(bs, drained_end_counter);
}
-static void bdrv_child_cb_attach(BdrvChild *child)
-{
- BlockDriverState *bs = child->opaque;
- bdrv_apply_subtree_drain(child, bs);
-}
-
-static void bdrv_child_cb_detach(BdrvChild *child)
-{
- BlockDriverState *bs = child->opaque;
- bdrv_unapply_subtree_drain(child, bs);
-}
-
static int bdrv_child_cb_inactivate(BdrvChild *child)
{
BlockDriverState *bs = child->opaque;
@@ -1149,82 +1138,6 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options,
*child_flags &= ~BDRV_O_NATIVE_AIO;
}
-/*
- * Returns the options and flags that bs->file should get if a protocol driver
- * is expected, based on the given options and flags for the parent BDS
- */
-static void bdrv_inherited_options(int *child_flags, QDict *child_options,
- int parent_flags, QDict *parent_options)
-{
- int flags = parent_flags;
-
- /* Enable protocol handling, disable format probing for bs->file */
- flags |= BDRV_O_PROTOCOL;
-
- /* If the cache mode isn't explicitly set, inherit direct and no-flush from
- * the parent. */
- qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
- qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
- qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE);
-
- /* Inherit the read-only option from the parent if it's not set */
- qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
- qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY);
-
- /* Our block drivers take care to send flushes and respect unmap policy,
- * so we can default to enable both on lower layers regardless of the
- * corresponding parent options. */
- qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap");
-
- /* Clear flags that only apply to the top layer */
- flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ |
- BDRV_O_NO_IO);
-
- *child_flags = flags;
-}
-
-const BdrvChildRole child_file = {
- .parent_is_bds = true,
- .get_parent_desc = bdrv_child_get_parent_desc,
- .inherit_options = bdrv_inherited_options,
- .drained_begin = bdrv_child_cb_drained_begin,
- .drained_poll = bdrv_child_cb_drained_poll,
- .drained_end = bdrv_child_cb_drained_end,
- .attach = bdrv_child_cb_attach,
- .detach = bdrv_child_cb_detach,
- .inactivate = bdrv_child_cb_inactivate,
- .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
- .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
-};
-
-/*
- * Returns the options and flags that bs->file should get if the use of formats
- * (and not only protocols) is permitted for it, based on the given options and
- * flags for the parent BDS
- */
-static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options,
- int parent_flags, QDict *parent_options)
-{
- child_file.inherit_options(child_flags, child_options,
- parent_flags, parent_options);
-
- *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO);
-}
-
-const BdrvChildRole child_format = {
- .parent_is_bds = true,
- .get_parent_desc = bdrv_child_get_parent_desc,
- .inherit_options = bdrv_inherited_fmt_options,
- .drained_begin = bdrv_child_cb_drained_begin,
- .drained_poll = bdrv_child_cb_drained_poll,
- .drained_end = bdrv_child_cb_drained_end,
- .attach = bdrv_child_cb_attach,
- .detach = bdrv_child_cb_detach,
- .inactivate = bdrv_child_cb_inactivate,
- .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
- .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
-};
-
static void bdrv_backing_attach(BdrvChild *c)
{
BlockDriverState *parent = c->opaque;
@@ -1266,8 +1179,6 @@ static void bdrv_backing_attach(BdrvChild *c)
parent->backing_blocker);
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
parent->backing_blocker);
-
- bdrv_child_cb_attach(c);
}
static void bdrv_backing_detach(BdrvChild *c)
@@ -1278,34 +1189,6 @@ static void bdrv_backing_detach(BdrvChild *c)
bdrv_op_unblock_all(c->bs, parent->backing_blocker);
error_free(parent->backing_blocker);
parent->backing_blocker = NULL;
-
- bdrv_child_cb_detach(c);
-}
-
-/*
- * Returns the options and flags that bs->backing should get, based on the
- * given options and flags for the parent BDS
- */
-static void bdrv_backing_options(int *child_flags, QDict *child_options,
- int parent_flags, QDict *parent_options)
-{
- int flags = parent_flags;
-
- /* The cache mode is inherited unmodified for backing files; except WCE,
- * which is only applied on the top level (BlockBackend) */
- qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
- qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
- qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE);
-
- /* backing files always opened read-only */
- qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
- qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
- flags &= ~BDRV_O_COPY_ON_READ;
-
- /* snapshot=on is handled on the top layer */
- flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
-
- *child_flags = flags;
}
static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base,
@@ -1335,19 +1218,130 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base,
return ret;
}
-const BdrvChildRole child_backing = {
+/*
+ * Returns the options and flags that a generic child of a BDS should
+ * get, based on the given options and flags for the parent BDS.
+ */
+static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format,
+ int *child_flags, QDict *child_options,
+ int parent_flags, QDict *parent_options)
+{
+ int flags = parent_flags;
+
+ /*
+ * First, decide whether to set, clear, or leave BDRV_O_PROTOCOL.
+ * Generally, the question to answer is: Should this child be
+ * format-probed by default?
+ */
+
+ /*
+ * Pure and non-filtered data children of non-format nodes should
+ * be probed by default (even when the node itself has BDRV_O_PROTOCOL
+ * set). This only affects a very limited set of drivers (namely
+ * quorum and blkverify when this comment was written).
+ * Force-clear BDRV_O_PROTOCOL then.
+ */
+ if (!parent_is_format &&
+ (role & BDRV_CHILD_DATA) &&
+ !(role & (BDRV_CHILD_METADATA | BDRV_CHILD_FILTERED)))
+ {
+ flags &= ~BDRV_O_PROTOCOL;
+ }
+
+ /*
+ * All children of format nodes (except for COW children) and all
+ * metadata children in general should never be format-probed.
+ * Force-set BDRV_O_PROTOCOL then.
+ */
+ if ((parent_is_format && !(role & BDRV_CHILD_COW)) ||
+ (role & BDRV_CHILD_METADATA))
+ {
+ flags |= BDRV_O_PROTOCOL;
+ }
+
+ /*
+ * If the cache mode isn't explicitly set, inherit direct and no-flush from
+ * the parent.
+ */
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE);
+
+ if (role & BDRV_CHILD_COW) {
+ /* backing files are opened read-only by default */
+ qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
+ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
+ } else {
+ /* Inherit the read-only option from the parent if it's not set */
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
+ qdict_copy_default(child_options, parent_options,
+ BDRV_OPT_AUTO_READ_ONLY);
+ }
+
+ /*
+ * bdrv_co_pdiscard() respects unmap policy for the parent, so we
+ * can default to enable it on lower layers regardless of the
+ * parent option.
+ */
+ qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap");
+
+ /* Clear flags that only apply to the top layer */
+ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
+
+ if (role & BDRV_CHILD_METADATA) {
+ flags &= ~BDRV_O_NO_IO;
+ }
+ if (role & BDRV_CHILD_COW) {
+ flags &= ~BDRV_O_TEMPORARY;
+ }
+
+ *child_flags = flags;
+}
+
+static void bdrv_child_cb_attach(BdrvChild *child)
+{
+ BlockDriverState *bs = child->opaque;
+
+ if (child->role & BDRV_CHILD_COW) {
+ bdrv_backing_attach(child);
+ }
+
+ bdrv_apply_subtree_drain(child, bs);
+}
+
+static void bdrv_child_cb_detach(BdrvChild *child)
+{
+ BlockDriverState *bs = child->opaque;
+
+ if (child->role & BDRV_CHILD_COW) {
+ bdrv_backing_detach(child);
+ }
+
+ bdrv_unapply_subtree_drain(child, bs);
+}
+
+static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
+ const char *filename, Error **errp)
+{
+ if (c->role & BDRV_CHILD_COW) {
+ return bdrv_backing_update_filename(c, base, filename, errp);
+ }
+ return 0;
+}
+
+const BdrvChildClass child_of_bds = {
.parent_is_bds = true,
.get_parent_desc = bdrv_child_get_parent_desc,
- .attach = bdrv_backing_attach,
- .detach = bdrv_backing_detach,
- .inherit_options = bdrv_backing_options,
+ .inherit_options = bdrv_inherited_options,
.drained_begin = bdrv_child_cb_drained_begin,
.drained_poll = bdrv_child_cb_drained_poll,
.drained_end = bdrv_child_cb_drained_end,
+ .attach = bdrv_child_cb_attach,
+ .detach = bdrv_child_cb_detach,
.inactivate = bdrv_child_cb_inactivate,
- .update_filename = bdrv_backing_update_filename,
.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,
};
static int bdrv_open_flags(BlockDriverState *bs, int flags)
@@ -1953,7 +1947,7 @@ bool bdrv_is_writable(BlockDriverState *bs)
}
static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
- BdrvChild *c, const BdrvChildRole *role,
+ BdrvChild *c, BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t parent_perm, uint64_t parent_shared,
uint64_t *nperm, uint64_t *nshared)
@@ -2145,8 +2139,8 @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
static char *bdrv_child_user_desc(BdrvChild *c)
{
- if (c->role->get_parent_desc) {
- return c->role->get_parent_desc(c);
+ if (c->klass->get_parent_desc) {
+ return c->klass->get_parent_desc(c);
}
return g_strdup("another user");
@@ -2348,66 +2342,132 @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp)
uint64_t perms, shared;
bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared);
- bdrv_child_perm(bs, c->bs, c, c->role, NULL, parent_perms, parent_shared,
- &perms, &shared);
+ bdrv_child_perm(bs, c->bs, c, c->role, NULL,
+ parent_perms, parent_shared, &perms, &shared);
return bdrv_child_try_set_perm(c, perms, shared, errp);
}
-void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
- BlockReopenQueue *reopen_queue,
- uint64_t perm, uint64_t shared,
- uint64_t *nperm, uint64_t *nshared)
+/*
+ * Default implementation for .bdrv_child_perm() for block filters:
+ * Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED, and RESIZE to the
+ * filtered child.
+ */
+static void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
+ BdrvChildRole role,
+ BlockReopenQueue *reopen_queue,
+ uint64_t perm, uint64_t shared,
+ uint64_t *nperm, uint64_t *nshared)
{
*nperm = perm & DEFAULT_PERM_PASSTHROUGH;
*nshared = (shared & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED;
}
-void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
- BlockReopenQueue *reopen_queue,
- uint64_t perm, uint64_t shared,
- uint64_t *nperm, uint64_t *nshared)
+static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c,
+ BdrvChildRole role,
+ BlockReopenQueue *reopen_queue,
+ uint64_t perm, uint64_t shared,
+ uint64_t *nperm, uint64_t *nshared)
+{
+ assert(role & BDRV_CHILD_COW);
+
+ /*
+ * We want consistent read from backing files if the parent needs it.
+ * No other operations are performed on backing files.
+ */
+ perm &= BLK_PERM_CONSISTENT_READ;
+
+ /*
+ * If the parent can deal with changing data, we're okay with a
+ * writable and resizable backing file.
+ * TODO Require !(perm & BLK_PERM_CONSISTENT_READ), too?
+ */
+ if (shared & BLK_PERM_WRITE) {
+ shared = BLK_PERM_WRITE | BLK_PERM_RESIZE;
+ } else {
+ shared = 0;
+ }
+
+ shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD |
+ BLK_PERM_WRITE_UNCHANGED;
+
+ if (bs->open_flags & BDRV_O_INACTIVE) {
+ shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
+ }
+
+ *nperm = perm;
+ *nshared = shared;
+}
+
+static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c,
+ BdrvChildRole role,
+ BlockReopenQueue *reopen_queue,
+ uint64_t perm, uint64_t shared,
+ uint64_t *nperm, uint64_t *nshared)
{
- bool backing = (role == &child_backing);
- assert(role == &child_backing || role == &child_file);
+ int flags;
+
+ assert(role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA));
- if (!backing) {
- int flags = bdrv_reopen_get_flags(reopen_queue, bs);
+ flags = bdrv_reopen_get_flags(reopen_queue, bs);
- /* Apart from the modifications below, the same permissions are
- * forwarded and left alone as for filters */
- bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
- &perm, &shared);
+ /*
+ * Apart from the modifications below, the same permissions are
+ * forwarded and left alone as for filters
+ */
+ bdrv_filter_default_perms(bs, c, role, reopen_queue,
+ perm, shared, &perm, &shared);
+ if (role & BDRV_CHILD_METADATA) {
/* Format drivers may touch metadata even if the guest doesn't write */
if (bdrv_is_writable_after_reopen(bs, reopen_queue)) {
perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
}
- /* bs->file always needs to be consistent because of the metadata. We
- * can never allow other users to resize or write to it. */
+ /*
+ * bs->file always needs to be consistent because of the
+ * metadata. We can never allow other users to resize or write
+ * to it.
+ */
if (!(flags & BDRV_O_NO_IO)) {
perm |= BLK_PERM_CONSISTENT_READ;
}
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
- } else {
- /* We want consistent read from backing files if the parent needs it.
- * No other operations are performed on backing files. */
- perm &= BLK_PERM_CONSISTENT_READ;
-
- /* If the parent can deal with changing data, we're okay with a
- * writable and resizable backing file. */
- /* TODO Require !(perm & BLK_PERM_CONSISTENT_READ), too? */
- if (shared & BLK_PERM_WRITE) {
- shared = BLK_PERM_WRITE | BLK_PERM_RESIZE;
- } else {
- shared = 0;
+ }
+
+ if (role & BDRV_CHILD_DATA) {
+ /*
+ * Technically, everything in this block is a subset of the
+ * BDRV_CHILD_METADATA path taken above, and so this could
+ * be an "else if" branch. However, that is not obvious, and
+ * this function is not performance critical, therefore we let
+ * this be an independent "if".
+ */
+
+ /*
+ * We cannot allow other users to resize the file because the
+ * format driver might have some assumptions about the size
+ * (e.g. because it is stored in metadata, or because the file
+ * is split into fixed-size data files).
+ */
+ shared &= ~BLK_PERM_RESIZE;
+
+ /*
+ * WRITE_UNCHANGED often cannot be performed as such on the
+ * data file. For example, the qcow2 driver may still need to
+ * write copied clusters on copy-on-read.
+ */
+ if (perm & BLK_PERM_WRITE_UNCHANGED) {
+ perm |= BLK_PERM_WRITE;
}
- shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD |
- BLK_PERM_WRITE_UNCHANGED;
+ /*
+ * If the data file is written to, the format driver may
+ * expect to be able to resize it by writing beyond the EOF.
+ */
+ if (perm & BLK_PERM_WRITE) {
+ perm |= BLK_PERM_RESIZE;
+ }
}
if (bs->open_flags & BDRV_O_INACTIVE) {
@@ -2418,6 +2478,28 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
*nshared = shared;
}
+void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c,
+ BdrvChildRole role, BlockReopenQueue *reopen_queue,
+ uint64_t perm, uint64_t shared,
+ uint64_t *nperm, uint64_t *nshared)
+{
+ if (role & BDRV_CHILD_FILTERED) {
+ assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA |
+ BDRV_CHILD_COW)));
+ bdrv_filter_default_perms(bs, c, role, reopen_queue,
+ perm, shared, nperm, nshared);
+ } else if (role & BDRV_CHILD_COW) {
+ assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA)));
+ bdrv_default_perms_for_cow(bs, c, role, reopen_queue,
+ perm, shared, nperm, nshared);
+ } else if (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)) {
+ bdrv_default_perms_for_storage(bs, c, role, reopen_queue,
+ perm, shared, nperm, nshared);
+ } else {
+ g_assert_not_reached();
+ }
+}
+
uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
{
static const uint64_t permissions[] = {
@@ -2456,7 +2538,7 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
* If the new child node is drained but the old one was not, flush
* all outstanding requests to the old child node.
*/
- while (drain_saldo > 0 && child->role->drained_begin) {
+ while (drain_saldo > 0 && child->klass->drained_begin) {
bdrv_parent_drained_begin_single(child, true);
drain_saldo--;
}
@@ -2465,8 +2547,8 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
/* Detach first so that the recursive drain sections coming from @child
* are already gone and we only end the drain sections that came from
* elsewhere. */
- if (child->role->detach) {
- child->role->detach(child);
+ if (child->klass->detach) {
+ child->klass->detach(child);
}
QLIST_REMOVE(child, next_parent);
}
@@ -2488,8 +2570,8 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
/* Attach only after starting new drained sections, so that recursive
* drain sections coming from @child don't get an extra .drained_begin
* callback. */
- if (child->role->attach) {
- child->role->attach(child);
+ if (child->klass->attach) {
+ child->klass->attach(child);
}
}
@@ -2497,7 +2579,7 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
* If the old child node was drained but the new one is not, allow
* requests to come in only after the new node has been attached.
*/
- while (drain_saldo < 0 && child->role->drained_end) {
+ while (drain_saldo < 0 && child->klass->drained_end) {
bdrv_parent_drained_end_single(child);
drain_saldo++;
}
@@ -2570,7 +2652,8 @@ 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,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
AioContext *ctx,
uint64_t perm, uint64_t shared_perm,
void *opaque, Error **errp)
@@ -2591,6 +2674,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
*child = (BdrvChild) {
.bs = NULL,
.name = g_strdup(child_name),
+ .klass = child_class,
.role = child_role,
.perm = perm,
.shared_perm = shared_perm,
@@ -2602,15 +2686,15 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
* try moving the parent into the AioContext of child_bs instead. */
if (bdrv_get_aio_context(child_bs) != ctx) {
ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err);
- if (ret < 0 && child_role->can_set_aio_ctx) {
+ if (ret < 0 && child_class->can_set_aio_ctx) {
GSList *ignore = g_slist_prepend(NULL, child);
ctx = bdrv_get_aio_context(child_bs);
- if (child_role->can_set_aio_ctx(child, ctx, &ignore, NULL)) {
+ if (child_class->can_set_aio_ctx(child, ctx, &ignore, NULL)) {
error_free(local_err);
ret = 0;
g_slist_free(ignore);
ignore = g_slist_prepend(NULL, child);
- child_role->set_aio_ctx(child, ctx, &ignore);
+ child_class->set_aio_ctx(child, ctx, &ignore);
}
g_slist_free(ignore);
}
@@ -2643,7 +2727,8 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
const char *child_name,
- const BdrvChildRole *child_role,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
Error **errp)
{
BdrvChild *child;
@@ -2655,8 +2740,8 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
perm, shared_perm, &perm, &shared_perm);
- child = bdrv_root_attach_child(child_bs, child_name, child_role,
- bdrv_get_aio_context(parent_bs),
+ child = bdrv_root_attach_child(child_bs, child_name, child_class,
+ child_role, bdrv_get_aio_context(parent_bs),
perm, shared_perm, parent_bs, errp);
if (child == NULL) {
return NULL;
@@ -2728,8 +2813,8 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load)
{
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
- if (c->role->change_media) {
- c->role->change_media(c, load);
+ if (c->klass->change_media) {
+ c->klass->change_media(c, load);
}
}
}
@@ -2747,6 +2832,20 @@ static bool bdrv_inherits_from_recursive(BlockDriverState *child,
}
/*
+ * Return the BdrvChildRole for @bs's backing child. bs->backing is
+ * mostly used for COW backing children (role = COW), but also for
+ * filtered children (role = FILTERED | PRIMARY).
+ */
+static BdrvChildRole bdrv_backing_role(BlockDriverState *bs)
+{
+ if (bs->drv && bs->drv->is_filter) {
+ return BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY;
+ } else {
+ return BDRV_CHILD_COW;
+ }
+}
+
+/*
* Sets the backing file link of a BDS. A new reference is created; callers
* which don't need their own reference any more must call bdrv_unref().
*/
@@ -2773,8 +2872,8 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
goto out;
}
- bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing,
- errp);
+ bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_of_bds,
+ bdrv_backing_role(bs), errp);
/* If backing_hd was already part of bs's backing chain, and
* inherits_from pointed recursively to bs then let's update it to
* point directly to bs (else it will become NULL). */
@@ -2871,7 +2970,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
}
backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
- &child_backing, errp);
+ &child_of_bds, bdrv_backing_role(bs), errp);
if (!backing_hd) {
bs->open_flags |= BDRV_O_NO_BACKING;
error_prepend(errp, "Could not open backing file: ");
@@ -2905,15 +3004,15 @@ free_exit:
static BlockDriverState *
bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
- BlockDriverState *parent, const BdrvChildRole *child_role,
- bool allow_none, Error **errp)
+ BlockDriverState *parent, const BdrvChildClass *child_class,
+ BdrvChildRole child_role, bool allow_none, Error **errp)
{
BlockDriverState *bs = NULL;
QDict *image_options;
char *bdref_key_dot;
const char *reference;
- assert(child_role != NULL);
+ assert(child_class != NULL);
bdref_key_dot = g_strdup_printf("%s.", bdref_key);
qdict_extract_subqdict(options, &image_options, bdref_key_dot);
@@ -2937,7 +3036,7 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
}
bs = bdrv_open_inherit(filename, reference, image_options, 0,
- parent, child_role, errp);
+ parent, child_class, child_role, errp);
if (!bs) {
goto done;
}
@@ -2964,22 +3063,26 @@ done:
BdrvChild *bdrv_open_child(const char *filename,
QDict *options, const char *bdref_key,
BlockDriverState *parent,
- const BdrvChildRole *child_role,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
bool allow_none, Error **errp)
{
BlockDriverState *bs;
- bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_role,
- allow_none, errp);
+ bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
+ child_role, allow_none, errp);
if (bs == NULL) {
return NULL;
}
- return bdrv_attach_child(parent, bs, bdref_key, child_role, errp);
+ return bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
+ errp);
}
-/* TODO Future callers may need to specify parent/child_role in order for
- * option inheritance to work. Existing callers use it for the root node. */
+/*
+ * TODO Future callers may need to specify parent/child_class in order for
+ * option inheritance to work. Existing callers use it for the root node.
+ */
BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
{
BlockDriverState *bs = NULL;
@@ -3011,7 +3114,7 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
}
- bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
+ bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, errp);
obj = NULL;
qobject_unref(obj);
visit_free(v);
@@ -3107,7 +3210,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
const char *reference,
QDict *options, int flags,
BlockDriverState *parent,
- const BdrvChildRole *child_role,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
Error **errp)
{
int ret;
@@ -3121,8 +3225,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
QDict *snapshot_options = NULL;
int snapshot_flags = 0;
- assert(!child_role || !flags);
- assert(!child_role == !parent);
+ assert(!child_class || !flags);
+ assert(!child_class == !parent);
if (reference) {
bool options_non_empty = options ? qdict_size(options) : false;
@@ -3158,10 +3262,24 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
bs->explicit_options = qdict_clone_shallow(options);
- if (child_role) {
+ if (child_class) {
+ bool parent_is_format;
+
+ if (parent->drv) {
+ parent_is_format = parent->drv->is_format;
+ } else {
+ /*
+ * parent->drv is not set yet because this node is opened for
+ * (potential) format probing. That means that @parent is going
+ * to be a format node.
+ */
+ parent_is_format = true;
+ }
+
bs->inherits_from = parent;
- child_role->inherit_options(&flags, options,
- parent->open_flags, parent->options);
+ child_class->inherit_options(child_role, parent_is_format,
+ &flags, options,
+ parent->open_flags, parent->options);
}
ret = bdrv_fill_options(&options, filename, &flags, &local_err);
@@ -3189,7 +3307,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
flags, options);
/* Let bdrv_backing_options() override "read-only" */
qdict_del(options, BDRV_OPT_READ_ONLY);
- bdrv_backing_options(&flags, options, flags, options);
+ bdrv_inherited_options(BDRV_CHILD_COW, true,
+ &flags, options, flags, options);
}
bs->open_flags = flags;
@@ -3231,7 +3350,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
BlockDriverState *file_bs;
file_bs = bdrv_open_child_bs(filename, options, "file", bs,
- &child_file, true, &local_err);
+ &child_of_bds, BDRV_CHILD_IMAGE,
+ true, &local_err);
if (local_err) {
goto fail;
}
@@ -3376,7 +3496,7 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
QDict *options, int flags, Error **errp)
{
return bdrv_open_inherit(filename, reference, options, flags, NULL,
- NULL, errp);
+ NULL, 0, errp);
}
/* Return true if the NULL-terminated @list contains @str */
@@ -3472,7 +3592,9 @@ static bool bdrv_recurse_has_child(BlockDriverState *bs,
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
BlockDriverState *bs,
QDict *options,
- const BdrvChildRole *role,
+ const BdrvChildClass *klass,
+ BdrvChildRole role,
+ bool parent_is_format,
QDict *parent_options,
int parent_flags,
bool keep_old_opts)
@@ -3528,7 +3650,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
/* Inherit from parent node */
if (parent_options) {
flags = 0;
- role->inherit_options(&flags, options, parent_flags, parent_options);
+ klass->inherit_options(role, parent_is_format, &flags, options,
+ parent_flags, parent_options);
} else {
flags = bdrv_get_flags(bs);
}
@@ -3619,7 +3742,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
}
bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options,
- child->role, options, flags, child_keep_old);
+ child->klass, child->role, bs->drv->is_format,
+ options, flags, child_keep_old);
}
return bs_queue;
@@ -3629,8 +3753,8 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
BlockDriverState *bs,
QDict *options, bool keep_old_opts)
{
- return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, NULL, 0,
- keep_old_opts);
+ return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, false,
+ NULL, 0, keep_old_opts);
}
/*
@@ -3676,8 +3800,8 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
if (state->replace_backing_bs && state->new_backing_bs) {
uint64_t nperm, nshared;
bdrv_child_perm(state->bs, state->new_backing_bs,
- NULL, &child_backing, bs_queue,
- state->perm, state->shared_perm,
+ NULL, bdrv_backing_role(state->bs),
+ bs_queue, state->perm, state->shared_perm,
&nperm, &nshared);
ret = bdrv_check_update_perm(state->new_backing_bs, NULL,
nperm, nshared, NULL, NULL, errp);
@@ -4305,7 +4429,7 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
GHashTable *found;
bool ret;
- if (c->role->stay_at_node) {
+ if (c->klass->stay_at_node) {
return false;
}
@@ -4776,9 +4900,9 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
}
/* If so, update the backing file path in the image file */
- if (c->role->update_filename) {
- ret = c->role->update_filename(c, base, backing_file_str,
- &local_err);
+ if (c->klass->update_filename) {
+ ret = c->klass->update_filename(c, base, backing_file_str,
+ &local_err);
if (ret < 0) {
bdrv_abort_perm_update(base);
error_report_err(local_err);
@@ -5226,8 +5350,8 @@ const char *bdrv_get_parent_name(const BlockDriverState *bs)
/* If multiple parents have a name, just pick the first one. */
QLIST_FOREACH(c, &bs->parents, next_parent) {
- if (c->role->get_name) {
- name = c->role->get_name(c);
+ if (c->klass->get_name) {
+ name = c->klass->get_name(c);
if (name && *name) {
return name;
}
@@ -5586,8 +5710,8 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
}
QLIST_FOREACH(parent, &bs->parents, next_parent) {
- if (parent->role->activate) {
- parent->role->activate(parent, &local_err);
+ if (parent->klass->activate) {
+ parent->klass->activate(parent, &local_err);
if (local_err) {
bs->open_flags |= BDRV_O_INACTIVE;
error_propagate(errp, local_err);
@@ -5655,7 +5779,7 @@ static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
BdrvChild *parent;
QLIST_FOREACH(parent, &bs->parents, next_parent) {
- if (parent->role->parent_is_bds) {
+ if (parent->klass->parent_is_bds) {
BlockDriverState *parent_bs = parent->opaque;
if (!only_active || !(parent_bs->open_flags & BDRV_O_INACTIVE)) {
return true;
@@ -5694,8 +5818,8 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
}
QLIST_FOREACH(parent, &bs->parents, next_parent) {
- if (parent->role->inactivate) {
- ret = parent->role->inactivate(parent);
+ if (parent->klass->inactivate) {
+ ret = parent->klass->inactivate(parent);
if (ret < 0) {
return ret;
}
@@ -6195,9 +6319,9 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs,
if (g_slist_find(*ignore, child)) {
continue;
}
- assert(child->role->set_aio_ctx);
+ assert(child->klass->set_aio_ctx);
*ignore = g_slist_prepend(*ignore, child);
- child->role->set_aio_ctx(child, new_context, ignore);
+ child->klass->set_aio_ctx(child, new_context, ignore);
}
bdrv_detach_aio_context(bs);
@@ -6237,15 +6361,17 @@ static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
}
*ignore = g_slist_prepend(*ignore, c);
- /* A BdrvChildRole that doesn't handle AioContext changes cannot
- * tolerate any AioContext changes */
- if (!c->role->can_set_aio_ctx) {
+ /*
+ * A BdrvChildClass that doesn't handle AioContext changes cannot
+ * tolerate any AioContext changes
+ */
+ if (!c->klass->can_set_aio_ctx) {
char *user = bdrv_child_user_desc(c);
error_setg(errp, "Changing iothreads is not supported by %s", user);
g_free(user);
return false;
}
- if (!c->role->can_set_aio_ctx(c, ctx, ignore, errp)) {
+ if (!c->klass->can_set_aio_ctx(c, ctx, ignore, errp)) {
assert(!errp || *errp);
return false;
}
@@ -6631,7 +6757,7 @@ void bdrv_refresh_filename(BlockDriverState *bs)
drv->bdrv_gather_child_options(bs, opts, backing_overridden);
} else {
QLIST_FOREACH(child, &bs->children, next) {
- if (child->role == &child_backing && !backing_overridden) {
+ if (child == bs->backing && !backing_overridden) {
/* We can skip the backing BDS if it has not been overridden */
continue;
}
@@ -6764,3 +6890,26 @@ void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp)
parent_bs->drv->bdrv_del_child(parent_bs, child, errp);
}
+
+int bdrv_make_empty(BdrvChild *c, Error **errp)
+{
+ BlockDriver *drv = c->bs->drv;
+ int ret;
+
+ assert(c->perm & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED));
+
+ if (!drv->bdrv_make_empty) {
+ error_setg(errp, "%s does not support emptying nodes",
+ drv->format_name);
+ return -ENOTSUP;
+ }
+
+ ret = drv->bdrv_make_empty(c->bs);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to empty %s",
+ c->bs->filename);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/block/backup-top.c b/block/backup-top.c
index 79b268e6dc..af2f20f346 100644
--- a/block/backup-top.c
+++ b/block/backup-top.c
@@ -122,7 +122,7 @@ static void backup_top_refresh_filename(BlockDriverState *bs)
}
static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
@@ -142,7 +142,7 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
return;
}
- if (role == &child_file) {
+ if (!(role & BDRV_CHILD_FILTERED)) {
/*
* Target child
*
@@ -155,8 +155,8 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
*nperm = BLK_PERM_WRITE;
} else {
/* Source child */
- bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
- nperm, nshared);
+ bdrv_default_perms(bs, c, role, reopen_queue,
+ perm, shared, nperm, nshared);
if (perm & BLK_PERM_WRITE) {
*nperm = *nperm | BLK_PERM_CONSISTENT_READ;
@@ -214,7 +214,8 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
source->supported_zero_flags);
bdrv_ref(target);
- state->target = bdrv_attach_child(top, target, "target", &child_file, errp);
+ state->target = bdrv_attach_child(top, target, "target", &child_of_bds,
+ BDRV_CHILD_DATA, errp);
if (!state->target) {
bdrv_unref(target);
bdrv_unref(top);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index af44aa973f..7194bc7f06 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -497,7 +497,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
/* Open the image file */
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
- bs, &child_file, false, &local_err);
+ bs, &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+ false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@@ -993,15 +995,15 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
}
static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
BDRVBlkdebugState *s = bs->opaque;
- bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
- nperm, nshared);
+ bdrv_default_perms(bs, c, role, reopen_queue,
+ perm, shared, nperm, nshared);
*nperm |= s->take_child_perms;
*nshared &= ~s->unshare_child_perms;
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
index 04d8b33607..6753bd9a3e 100644
--- a/block/blklogwrites.c
+++ b/block/blklogwrites.c
@@ -157,7 +157,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
}
/* Open the file */
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false,
&local_err);
if (local_err) {
ret = -EINVAL;
@@ -166,8 +167,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
}
/* Open the log file */
- s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false,
- &local_err);
+ s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_of_bds,
+ BDRV_CHILD_METADATA, false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@@ -282,7 +283,7 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs)
}
static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *ro_q,
uint64_t perm, uint64_t shrd,
uint64_t *nperm, uint64_t *nshrd)
@@ -293,11 +294,8 @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
return;
}
- if (!strcmp(c->name, "log")) {
- bdrv_format_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
- } else {
- bdrv_filter_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
- }
+ bdrv_default_perms(bs, c, role, ro_q, perm, shrd,
+ nperm, nshrd);
}
static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)
diff --git a/block/blkreplay.c b/block/blkreplay.c
index c96ac8f4bc..30a0f5d57a 100644
--- a/block/blkreplay.c
+++ b/block/blkreplay.c
@@ -27,8 +27,9 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
int ret;
/* Open the image file */
- bs->file = bdrv_open_child(NULL, options, "image",
- bs, &child_file, false, &local_err);
+ bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+ false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@@ -135,9 +136,10 @@ static int blkreplay_snapshot_goto(BlockDriverState *bs,
static BlockDriver bdrv_blkreplay = {
.format_name = "blkreplay",
.instance_size = 0,
+ .is_filter = true,
.bdrv_open = blkreplay_open,
- .bdrv_child_perm = bdrv_filter_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_getlength = blkreplay_getlength,
.bdrv_co_preadv = blkreplay_co_preadv,
diff --git a/block/blkverify.c b/block/blkverify.c
index ba6b1853ae..2f261de24b 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -125,7 +125,9 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
/* Open the raw file */
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw",
- bs, &child_file, false, &local_err);
+ bs, &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+ false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@@ -134,8 +136,8 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
/* Open the test file */
s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options,
- "test", bs, &child_format, false,
- &local_err);
+ "test", bs, &child_of_bds, BDRV_CHILD_DATA,
+ false, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@@ -317,7 +319,7 @@ static BlockDriver bdrv_blkverify = {
.bdrv_parse_filename = blkverify_parse_filename,
.bdrv_file_open = blkverify_open,
.bdrv_close = blkverify_close,
- .bdrv_child_perm = bdrv_filter_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_getlength = blkverify_getlength,
.bdrv_refresh_filename = blkverify_refresh_filename,
.bdrv_dirname = blkverify_dirname,
diff --git a/block/block-backend.c b/block/block-backend.c
index f4944861fa..6936b25c83 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -120,7 +120,8 @@ static QTAILQ_HEAD(, BlockBackend) block_backends =
static QTAILQ_HEAD(, BlockBackend) monitor_block_backends =
QTAILQ_HEAD_INITIALIZER(monitor_block_backends);
-static void blk_root_inherit_options(int *child_flags, QDict *child_options,
+static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format,
+ int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
{
/* We're not supposed to call this function for root nodes */
@@ -297,7 +298,7 @@ static void blk_root_detach(BdrvChild *child)
}
}
-static const BdrvChildRole child_root = {
+static const BdrvChildClass child_root = {
.inherit_options = blk_root_inherit_options,
.change_media = blk_root_change_media,
@@ -423,8 +424,9 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
return NULL;
}
- blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
- perm, BLK_PERM_ALL, blk, errp);
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+ blk->ctx, perm, BLK_PERM_ALL, blk, errp);
if (!blk->root) {
blk_unref(blk);
return NULL;
@@ -716,7 +718,7 @@ static BlockBackend *bdrv_first_blk(BlockDriverState *bs)
{
BdrvChild *child;
QLIST_FOREACH(child, &bs->parents, next_parent) {
- if (child->role == &child_root) {
+ if (child->klass == &child_root) {
return child->opaque;
}
}
@@ -740,7 +742,7 @@ bool bdrv_is_root_node(BlockDriverState *bs)
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
- if (c->role != &child_root) {
+ if (c->klass != &child_root) {
return false;
}
}
@@ -834,8 +836,10 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
{
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
bdrv_ref(bs);
- blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
- blk->perm, blk->shared_perm, blk, errp);
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+ blk->ctx, blk->perm, blk->shared_perm,
+ blk, errp);
if (blk->root == NULL) {
return -EPERM;
}
@@ -2402,3 +2406,13 @@ const BdrvChild *blk_root(BlockBackend *blk)
{
return blk->root;
}
+
+int blk_make_empty(BlockBackend *blk, Error **errp)
+{
+ if (!blk_is_available(blk)) {
+ error_setg(errp, "No medium inserted");
+ return -ENOMEDIUM;
+ }
+
+ return bdrv_make_empty(blk->root, errp);
+}
diff --git a/block/block-copy.c b/block/block-copy.c
index 4713c8f2a3..bb8d0569f2 100644
--- a/block/block-copy.c
+++ b/block/block-copy.c
@@ -343,9 +343,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
~BDRV_REQ_WRITE_COMPRESSED);
if (ret < 0) {
trace_block_copy_write_zeroes_fail(s, offset, ret);
- if (error_is_read) {
- *error_is_read = false;
- }
+ *error_is_read = false;
}
return ret;
}
@@ -393,9 +391,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
ret = bdrv_co_pread(s->source, offset, nbytes, bounce_buffer, 0);
if (ret < 0) {
trace_block_copy_read_fail(s, offset, ret);
- if (error_is_read) {
- *error_is_read = true;
- }
+ *error_is_read = true;
goto out;
}
@@ -403,9 +399,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
s->write_flags);
if (ret < 0) {
trace_block_copy_write_fail(s, offset, ret);
- if (error_is_read) {
- *error_is_read = false;
- }
+ *error_is_read = false;
goto out;
}
@@ -418,7 +412,7 @@ out:
static coroutine_fn int block_copy_task_entry(AioTask *task)
{
BlockCopyTask *t = container_of(task, BlockCopyTask, task);
- bool error_is_read;
+ bool error_is_read = false;
int ret;
ret = block_copy_do_copy(t->s, t->offset, t->bytes, t->zeroes,
diff --git a/block/bochs.c b/block/bochs.c
index 32bb83b268..2f010ab40a 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -110,8 +110,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
return ret;
}
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -297,10 +297,11 @@ static BlockDriver bdrv_bochs = {
.instance_size = sizeof(BDRVBochsState),
.bdrv_probe = bochs_probe,
.bdrv_open = bochs_open,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_refresh_limits = bochs_refresh_limits,
.bdrv_co_preadv = bochs_co_preadv,
.bdrv_close = bochs_close,
+ .is_format = true,
};
static void bdrv_bochs_init(void)
diff --git a/block/cloop.c b/block/cloop.c
index 4de94876d4..c99192a57f 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -71,8 +71,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
return ret;
}
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -293,10 +293,11 @@ static BlockDriver bdrv_cloop = {
.instance_size = sizeof(BDRVCloopState),
.bdrv_probe = cloop_probe,
.bdrv_open = cloop_open,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_refresh_limits = cloop_refresh_limits,
.bdrv_co_preadv = cloop_co_preadv,
.bdrv_close = cloop_close,
+ .is_format = true,
};
static void bdrv_cloop_init(void)
diff --git a/block/commit.c b/block/commit.c
index 87f6096d90..7732d02dfe 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -223,7 +223,7 @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs)
}
static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
@@ -240,6 +240,8 @@ static BlockDriver bdrv_commit_top = {
.bdrv_co_block_status = bdrv_co_block_status_from_backing,
.bdrv_refresh_filename = bdrv_commit_top_refresh_filename,
.bdrv_child_perm = bdrv_commit_top_child_perm,
+
+ .is_filter = true,
};
void commit_start(const char *job_id, BlockDriverState *bs,
@@ -414,7 +416,9 @@ int bdrv_commit(BlockDriverState *bs)
}
ctx = bdrv_get_aio_context(bs);
- src = blk_new(ctx, BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
+ /* WRITE_UNCHANGED is required for bdrv_make_empty() */
+ src = blk_new(ctx, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED,
+ BLK_PERM_ALL);
backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(src, bs, &local_err);
@@ -492,14 +496,14 @@ int bdrv_commit(BlockDriverState *bs)
}
}
- if (drv->bdrv_make_empty) {
- ret = drv->bdrv_make_empty(bs);
- if (ret < 0) {
- goto ro_cleanup;
- }
- blk_flush(src);
+ ret = blk_make_empty(src, NULL);
+ /* Ignore -ENOTSUP */
+ if (ret < 0 && ret != -ENOTSUP) {
+ goto ro_cleanup;
}
+ blk_flush(src);
+
/*
* Make sure all data we wrote to the backing device is actually
* stable on disk.
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
index 242d3ff055..a6e3c74a68 100644
--- a/block/copy-on-read.c
+++ b/block/copy-on-read.c
@@ -28,8 +28,9 @@
static int cor_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
- errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+ false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -51,7 +52,7 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
#define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH)
static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
diff --git a/block/crypto.c b/block/crypto.c
index 6b21d6bf6c..b216e12c31 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -218,8 +218,8 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
unsigned int cflags = 0;
QDict *cryptoopts = NULL;
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -756,7 +756,7 @@ static BlockDriver bdrv_crypto_luks = {
.bdrv_close = block_crypto_close,
/* This driver doesn't modify LUKS metadata except when creating image.
* Allow share-rw=on as a special case. */
- .bdrv_child_perm = bdrv_filter_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_create = block_crypto_co_create_luks,
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
.bdrv_co_truncate = block_crypto_co_truncate,
@@ -771,6 +771,8 @@ static BlockDriver bdrv_crypto_luks = {
.bdrv_get_info = block_crypto_get_info_luks,
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
+ .is_format = true,
+
.strong_runtime_opts = block_crypto_strong_runtime_opts,
};
diff --git a/block/dmg.c b/block/dmg.c
index 4a045f2b3e..0d6c317296 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -439,8 +439,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
return ret;
}
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -750,9 +750,10 @@ static BlockDriver bdrv_dmg = {
.bdrv_probe = dmg_probe,
.bdrv_open = dmg_open,
.bdrv_refresh_limits = dmg_refresh_limits,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_preadv = dmg_co_preadv,
.bdrv_close = dmg_close,
+ .is_format = true,
};
static void bdrv_dmg_init(void)
diff --git a/block/filter-compress.c b/block/filter-compress.c
index 82c315b298..8ec1991c1f 100644
--- a/block/filter-compress.c
+++ b/block/filter-compress.c
@@ -30,8 +30,9 @@
static int compress_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
- errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+ false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -132,7 +133,7 @@ static BlockDriver bdrv_compress = {
.format_name = "compress",
.bdrv_open = compress_open,
- .bdrv_child_perm = bdrv_filter_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_getlength = compress_getlength,
diff --git a/block/io.c b/block/io.c
index 7d30e61edc..121ce17a49 100644
--- a/block/io.c
+++ b/block/io.c
@@ -50,7 +50,7 @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
BdrvChild *c, *next;
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
- if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
+ if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
continue;
}
bdrv_parent_drained_begin_single(c, false);
@@ -62,8 +62,8 @@ static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c,
{
assert(c->parent_quiesce_counter > 0);
c->parent_quiesce_counter--;
- if (c->role->drained_end) {
- c->role->drained_end(c, drained_end_counter);
+ if (c->klass->drained_end) {
+ c->klass->drained_end(c, drained_end_counter);
}
}
@@ -81,7 +81,7 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
- if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
+ if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
continue;
}
bdrv_parent_drained_end_single_no_poll(c, drained_end_counter);
@@ -90,8 +90,8 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
static bool bdrv_parent_drained_poll_single(BdrvChild *c)
{
- if (c->role->drained_poll) {
- return c->role->drained_poll(c);
+ if (c->klass->drained_poll) {
+ return c->klass->drained_poll(c);
}
return false;
}
@@ -103,7 +103,7 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
bool busy = false;
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
- if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
+ if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
continue;
}
busy |= bdrv_parent_drained_poll_single(c);
@@ -115,8 +115,8 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
{
c->parent_quiesce_counter++;
- if (c->role->drained_begin) {
- c->role->drained_begin(c);
+ if (c->klass->drained_begin) {
+ c->klass->drained_begin(c);
}
if (poll) {
BDRV_POLL_WHILE(c->bs, bdrv_parent_drained_poll_single(c));
@@ -3326,8 +3326,8 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
{
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
- if (c->role->resize) {
- c->role->resize(c);
+ if (c->klass->resize) {
+ c->klass->resize(c);
}
}
}
diff --git a/block/mirror.c b/block/mirror.c
index aca95c9bc9..e8e8844afc 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -872,6 +872,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
BlockDriverState *target_bs = blk_bs(s->target);
bool need_drain = true;
int64_t length;
+ int64_t target_length;
BlockDriverInfo bdi;
char backing_filename[2]; /* we only need 2 characters because we are only
checking for a NULL string */
@@ -887,24 +888,26 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
goto immediate_exit;
}
+ target_length = blk_getlength(s->target);
+ if (target_length < 0) {
+ ret = target_length;
+ goto immediate_exit;
+ }
+
/* Active commit must resize the base image if its size differs from the
* active layer. */
if (s->base == blk_bs(s->target)) {
- int64_t base_length;
-
- base_length = blk_getlength(s->target);
- if (base_length < 0) {
- ret = base_length;
- goto immediate_exit;
- }
-
- if (s->bdev_length > base_length) {
+ if (s->bdev_length > target_length) {
ret = blk_truncate(s->target, s->bdev_length, false,
PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) {
goto immediate_exit;
}
}
+ } else if (s->bdev_length != target_length) {
+ error_setg(errp, "Source and target image have different sizes");
+ ret = -EINVAL;
+ goto immediate_exit;
}
if (s->bdev_length == 0) {
@@ -1489,7 +1492,7 @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs)
}
static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
@@ -1527,6 +1530,8 @@ static BlockDriver bdrv_mirror_top = {
.bdrv_co_block_status = bdrv_co_block_status_from_backing,
.bdrv_refresh_filename = bdrv_mirror_top_refresh_filename,
.bdrv_child_perm = bdrv_mirror_top_child_perm,
+
+ .is_filter = true,
};
static BlockJob *mirror_start_job(
diff --git a/block/parallels.c b/block/parallels.c
index e7717c508e..63a1cde8af 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -739,8 +739,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
Error *local_err = NULL;
char *buf;
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -912,12 +912,13 @@ static BlockDriver bdrv_parallels = {
.bdrv_probe = parallels_probe,
.bdrv_open = parallels_open,
.bdrv_close = parallels_close,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_block_status = parallels_co_block_status,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_flush_to_os = parallels_co_flush_to_os,
.bdrv_co_readv = parallels_co_readv,
.bdrv_co_writev = parallels_co_writev,
+ .is_format = true,
.supports_backing = true,
.bdrv_co_create = parallels_co_create,
.bdrv_co_create_opts = parallels_co_create_opts,
diff --git a/block/qcow.c b/block/qcow.c
index b0475b73a5..ee5d35fe20 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -130,8 +130,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
qdict_extract_subqdict(options, &encryptopts, "encrypt.");
encryptfmt = qdict_get_try_str(encryptopts, "format");
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
ret = -EINVAL;
goto fail;
@@ -1180,11 +1180,12 @@ static BlockDriver bdrv_qcow = {
.bdrv_probe = qcow_probe,
.bdrv_open = qcow_open,
.bdrv_close = qcow_close,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_reopen_prepare = qcow_reopen_prepare,
.bdrv_co_create = qcow_co_create,
.bdrv_co_create_opts = qcow_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
+ .is_format = true,
.supports_backing = true,
.bdrv_refresh_limits = qcow_refresh_limits,
diff --git a/block/qcow2.c b/block/qcow2.c
index ad9ab4fafa..fe0ce39799 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1590,7 +1590,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
}
/* Open external data file */
- s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file,
+ s->data_file = bdrv_open_child(NULL, options, "data-file", bs,
+ &child_of_bds, BDRV_CHILD_DATA,
true, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1601,8 +1602,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
if (!s->data_file && s->image_data_file) {
s->data_file = bdrv_open_child(s->image_data_file, options,
- "data-file", bs, &child_file,
- false, errp);
+ "data-file", bs, &child_of_bds,
+ BDRV_CHILD_DATA, false, errp);
if (!s->data_file) {
ret = -EINVAL;
goto fail;
@@ -1613,6 +1614,12 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
ret = -EINVAL;
goto fail;
}
+
+ /* No data here */
+ bs->file->role &= ~BDRV_CHILD_DATA;
+
+ /* Must succeed because we have given up permissions if anything */
+ bdrv_child_refresh_perms(bs, bs->file, &error_abort);
} else {
if (s->data_file) {
error_setg(errp, "'data-file' can only be set for images with an "
@@ -1863,8 +1870,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
.ret = -EINPROGRESS
};
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -5737,7 +5744,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_reopen_commit_post = qcow2_reopen_commit_post,
.bdrv_reopen_abort = qcow2_reopen_abort,
.bdrv_join_options = qcow2_join_options,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_create_opts = qcow2_co_create_opts,
.bdrv_co_create = qcow2_co_create,
.bdrv_has_zero_init = qcow2_has_zero_init,
@@ -5767,6 +5774,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_save_vmstate = qcow2_save_vmstate,
.bdrv_load_vmstate = qcow2_load_vmstate,
+ .is_format = true,
.supports_backing = true,
.bdrv_change_backing_file = qcow2_change_backing_file,
diff --git a/block/qed.c b/block/qed.c
index 5da9726518..c0c65015c7 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -547,8 +547,8 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
.ret = -EINPROGRESS
};
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -1665,13 +1665,14 @@ static BlockDriver bdrv_qed = {
.format_name = "qed",
.instance_size = sizeof(BDRVQEDState),
.create_opts = &qed_create_opts,
+ .is_format = true,
.supports_backing = true,
.bdrv_probe = bdrv_qed_probe,
.bdrv_open = bdrv_qed_open,
.bdrv_close = bdrv_qed_close,
.bdrv_reopen_prepare = bdrv_qed_reopen_prepare,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_create = bdrv_qed_co_create,
.bdrv_co_create_opts = bdrv_qed_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
diff --git a/block/quorum.c b/block/quorum.c
index 6d7a56bd93..7cf7ab1546 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -977,7 +977,8 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
assert(ret < 32);
s->children[i] = bdrv_open_child(NULL, options, indexstr, bs,
- &child_format, false, &local_err);
+ &child_of_bds, BDRV_CHILD_DATA, false,
+ &local_err);
if (local_err) {
ret = -EINVAL;
goto close_exit;
@@ -1053,7 +1054,8 @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
/* We can safely add the child now */
bdrv_ref(child_bs);
- child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, errp);
+ child = bdrv_attach_child(bs, child_bs, indexstr, &child_of_bds,
+ BDRV_CHILD_DATA, errp);
if (child == NULL) {
s->next_child_index--;
goto out;
@@ -1151,7 +1153,7 @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp)
}
static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
diff --git a/block/raw-format.c b/block/raw-format.c
index 9108e43696..018441bddf 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -71,20 +71,13 @@ static QemuOptsList raw_create_opts = {
}
};
-static int raw_read_options(QDict *options, BlockDriverState *bs,
- BDRVRawState *s, Error **errp)
+static int raw_read_options(QDict *options, uint64_t *offset, bool *has_size,
+ uint64_t *size, Error **errp)
{
Error *local_err = NULL;
QemuOpts *opts = NULL;
- int64_t real_size = 0;
int ret;
- real_size = bdrv_getlength(bs->file->bs);
- if (real_size < 0) {
- error_setg_errno(errp, -real_size, "Could not get image size");
- return real_size;
- }
-
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
@@ -93,64 +86,84 @@ static int raw_read_options(QDict *options, BlockDriverState *bs,
goto end;
}
- s->offset = qemu_opt_get_size(opts, "offset", 0);
- if (s->offset > real_size) {
- error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than "
- "size of the containing file (%" PRId64 ")",
- s->offset, real_size);
- ret = -EINVAL;
- goto end;
- }
+ *offset = qemu_opt_get_size(opts, "offset", 0);
+ *has_size = qemu_opt_find(opts, "size");
+ *size = qemu_opt_get_size(opts, "size", 0);
- if (qemu_opt_find(opts, "size") != NULL) {
- s->size = qemu_opt_get_size(opts, "size", 0);
- s->has_size = true;
- } else {
- s->has_size = false;
- s->size = real_size - s->offset;
+ ret = 0;
+end:
+ qemu_opts_del(opts);
+ return ret;
+}
+
+static int raw_apply_options(BlockDriverState *bs, BDRVRawState *s,
+ uint64_t offset, bool has_size, uint64_t size,
+ Error **errp)
+{
+ int64_t real_size = 0;
+
+ real_size = bdrv_getlength(bs->file->bs);
+ if (real_size < 0) {
+ error_setg_errno(errp, -real_size, "Could not get image size");
+ return real_size;
}
/* Check size and offset */
- if ((real_size - s->offset) < s->size) {
+ if (offset > real_size) {
+ error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than "
+ "size of the containing file (%" PRId64 ")",
+ s->offset, real_size);
+ return -EINVAL;
+ }
+
+ if (has_size && (real_size - offset) < size) {
error_setg(errp, "The sum of offset (%" PRIu64 ") and size "
- "(%" PRIu64 ") has to be smaller or equal to the "
- " actual size of the containing file (%" PRId64 ")",
- s->offset, s->size, real_size);
- ret = -EINVAL;
- goto end;
+ "(%" PRIu64 ") has to be smaller or equal to the "
+ " actual size of the containing file (%" PRId64 ")",
+ s->offset, s->size, real_size);
+ return -EINVAL;
}
/* Make sure size is multiple of BDRV_SECTOR_SIZE to prevent rounding
* up and leaking out of the specified area. */
- if (s->has_size && !QEMU_IS_ALIGNED(s->size, BDRV_SECTOR_SIZE)) {
+ if (has_size && !QEMU_IS_ALIGNED(size, BDRV_SECTOR_SIZE)) {
error_setg(errp, "Specified size is not multiple of %llu",
- BDRV_SECTOR_SIZE);
- ret = -EINVAL;
- goto end;
+ BDRV_SECTOR_SIZE);
+ return -EINVAL;
}
- ret = 0;
-
-end:
-
- qemu_opts_del(opts);
+ s->offset = offset;
+ s->has_size = has_size;
+ s->size = has_size ? size : real_size - offset;
- return ret;
+ return 0;
}
static int raw_reopen_prepare(BDRVReopenState *reopen_state,
BlockReopenQueue *queue, Error **errp)
{
+ bool has_size;
+ uint64_t offset, size;
+ int ret;
+
assert(reopen_state != NULL);
assert(reopen_state->bs != NULL);
reopen_state->opaque = g_new0(BDRVRawState, 1);
- return raw_read_options(
- reopen_state->options,
- reopen_state->bs,
- reopen_state->opaque,
- errp);
+ ret = raw_read_options(reopen_state->options, &offset, &has_size, &size,
+ errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = raw_apply_options(reopen_state->bs, reopen_state->opaque,
+ offset, has_size, size, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
}
static void raw_reopen_commit(BDRVReopenState *state)
@@ -426,10 +439,28 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVRawState *s = bs->opaque;
+ bool has_size;
+ uint64_t offset, size;
+ BdrvChildRole file_role;
int ret;
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ ret = raw_read_options(options, &offset, &has_size, &size, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /*
+ * Without offset and a size limit, this driver behaves very much
+ * like a filter. With any such limit, it does not.
+ */
+ if (offset || has_size) {
+ file_role = BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY;
+ } else {
+ file_role = BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY;
+ }
+
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ file_role, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -455,7 +486,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
bs->file->bs->filename);
}
- ret = raw_read_options(options, bs, s, errp);
+ ret = raw_apply_options(bs, s, offset, has_size, size, errp);
if (ret < 0) {
return ret;
}
@@ -555,7 +586,7 @@ BlockDriver bdrv_raw = {
.bdrv_reopen_commit = &raw_reopen_commit,
.bdrv_reopen_abort = &raw_reopen_abort,
.bdrv_open = &raw_open,
- .bdrv_child_perm = bdrv_filter_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_create_opts = &raw_co_create_opts,
.bdrv_co_preadv = &raw_co_preadv,
.bdrv_co_pwritev = &raw_co_pwritev,
@@ -566,6 +597,7 @@ BlockDriver bdrv_raw = {
.bdrv_co_copy_range_to = &raw_co_copy_range_to,
.bdrv_co_truncate = &raw_co_truncate,
.bdrv_getlength = &raw_getlength,
+ .is_format = true,
.has_variable_length = true,
.bdrv_measure = &raw_measure,
.bdrv_get_info = &raw_get_info,
diff --git a/block/replication.c b/block/replication.c
index 971f0fe266..ccf7b78160 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -90,7 +90,8 @@ static int replication_open(BlockDriverState *bs, QDict *options,
const char *mode;
const char *top_id;
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
false, errp);
if (!bs->file) {
return -EINVAL;
@@ -163,7 +164,7 @@ static void replication_close(BlockDriverState *bs)
}
static void replication_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
@@ -331,9 +332,8 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
return;
}
- ret = s->active_disk->bs->drv->bdrv_make_empty(s->active_disk->bs);
+ ret = bdrv_make_empty(s->active_disk, errp);
if (ret < 0) {
- error_setg(errp, "Cannot make active disk empty");
return;
}
@@ -343,9 +343,18 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
return;
}
- ret = s->hidden_disk->bs->drv->bdrv_make_empty(s->hidden_disk->bs);
+ BlockBackend *blk = blk_new(qemu_get_current_aio_context(),
+ BLK_PERM_WRITE, BLK_PERM_ALL);
+ blk_insert_bs(blk, s->hidden_disk->bs, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ blk_unref(blk);
+ return;
+ }
+
+ ret = blk_make_empty(blk, errp);
+ blk_unref(blk);
if (ret < 0) {
- error_setg(errp, "Cannot make hidden disk empty");
return;
}
}
@@ -398,6 +407,8 @@ static void backup_job_cleanup(BlockDriverState *bs)
BDRVReplicationState *s = bs->opaque;
BlockDriverState *top_bs;
+ s->backup_job = NULL;
+
top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL);
if (!top_bs) {
return;
diff --git a/block/throttle.c b/block/throttle.c
index 71f4bb0ad1..0ebbad0743 100644
--- a/block/throttle.c
+++ b/block/throttle.c
@@ -81,8 +81,9 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
char *group;
int ret;
- bs->file = bdrv_open_child(NULL, options, "file", bs,
- &child_file, false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
+ false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -236,7 +237,7 @@ static BlockDriver bdrv_throttle = {
.bdrv_close = throttle_close,
.bdrv_co_flush = throttle_co_flush,
- .bdrv_child_perm = bdrv_filter_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_getlength = throttle_getlength,
diff --git a/block/vdi.c b/block/vdi.c
index 2d28046615..2f506a01ba 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -378,8 +378,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
Error *local_err = NULL;
QemuUUID uuid_link, uuid_parent;
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -1039,7 +1039,7 @@ static BlockDriver bdrv_vdi = {
.bdrv_open = vdi_open,
.bdrv_close = vdi_close,
.bdrv_reopen_prepare = vdi_reopen_prepare,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_create = vdi_co_create,
.bdrv_co_create_opts = vdi_co_create_opts,
.bdrv_has_zero_init = vdi_has_zero_init,
@@ -1053,6 +1053,7 @@ static BlockDriver bdrv_vdi = {
.bdrv_get_info = vdi_get_info,
+ .is_format = true,
.create_opts = &vdi_create_opts,
.bdrv_co_check = vdi_co_check,
};
diff --git a/block/vhdx.c b/block/vhdx.c
index 53e756438a..fa9e544a5e 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -996,8 +996,8 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
uint64_t signature;
Error *local_err = NULL;
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -2245,7 +2245,7 @@ static BlockDriver bdrv_vhdx = {
.bdrv_open = vhdx_open,
.bdrv_close = vhdx_close,
.bdrv_reopen_prepare = vhdx_reopen_prepare,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_readv = vhdx_co_readv,
.bdrv_co_writev = vhdx_co_writev,
.bdrv_co_create = vhdx_co_create,
@@ -2254,6 +2254,7 @@ static BlockDriver bdrv_vhdx = {
.bdrv_co_check = vhdx_co_check,
.bdrv_has_zero_init = vhdx_has_zero_init,
+ .is_format = true,
.create_opts = &vhdx_create_opts,
};
diff --git a/block/vmdk.c b/block/vmdk.c
index b18f128816..62da465126 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1089,6 +1089,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
char *desc_file_dir = NULL;
char *extent_path;
BdrvChild *extent_file;
+ BdrvChildRole extent_role;
BDRVVmdkState *s = bs->opaque;
VmdkExtent *extent;
char extent_opt_prefix[32];
@@ -1151,8 +1152,15 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
assert(ret < 32);
+ extent_role = BDRV_CHILD_DATA;
+ if (strcmp(type, "FLAT") != 0 && strcmp(type, "VMFS") != 0) {
+ /* non-flat extents have metadata */
+ extent_role |= BDRV_CHILD_METADATA;
+ }
+
extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix,
- bs, &child_file, false, &local_err);
+ bs, &child_of_bds, extent_role, false,
+ &local_err);
g_free(extent_path);
if (local_err) {
error_propagate(errp, local_err);
@@ -1257,8 +1265,8 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
uint32_t magic;
Error *local_err = NULL;
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -1277,6 +1285,12 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
s->desc_offset = 0x200;
break;
default:
+ /* No data in the descriptor file */
+ bs->file->role &= ~BDRV_CHILD_DATA;
+
+ /* Must succeed because we have given up permissions if anything */
+ bdrv_child_refresh_perms(bs, bs->file, &error_abort);
+
ret = vmdk_open_desc_file(bs, flags, buf, options, errp);
break;
}
@@ -3053,7 +3067,7 @@ static BlockDriver bdrv_vmdk = {
.bdrv_open = vmdk_open,
.bdrv_co_check = vmdk_co_check,
.bdrv_reopen_prepare = vmdk_reopen_prepare,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_preadv = vmdk_co_preadv,
.bdrv_co_pwritev = vmdk_co_pwritev,
.bdrv_co_pwritev_compressed = vmdk_co_pwritev_compressed,
@@ -3070,6 +3084,7 @@ static BlockDriver bdrv_vmdk = {
.bdrv_get_info = vmdk_get_info,
.bdrv_gather_child_options = vmdk_gather_child_options,
+ .is_format = true,
.supports_backing = true,
.create_opts = &vmdk_create_opts,
};
diff --git a/block/vpc.c b/block/vpc.c
index 5e31dd1e47..c055591641 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -228,8 +228,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
int ret;
int64_t bs_size;
- bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
- false, errp);
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
+ BDRV_CHILD_IMAGE, false, errp);
if (!bs->file) {
return -EINVAL;
}
@@ -1240,7 +1240,7 @@ static BlockDriver bdrv_vpc = {
.bdrv_open = vpc_open,
.bdrv_close = vpc_close,
.bdrv_reopen_prepare = vpc_reopen_prepare,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_create = vpc_co_create,
.bdrv_co_create_opts = vpc_co_create_opts,
@@ -1250,6 +1250,7 @@ static BlockDriver bdrv_vpc = {
.bdrv_get_info = vpc_get_info,
+ .is_format = true,
.create_opts = &vpc_create_opts,
.bdrv_has_zero_init = vpc_has_zero_init,
.strong_runtime_opts = vpc_strong_runtime_opts,
diff --git a/block/vvfat.c b/block/vvfat.c
index 6d5c090dec..c65a98e3ee 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -2960,9 +2960,7 @@ static int do_commit(BDRVVVFATState* s)
return ret;
}
- if (s->qcow->bs->drv && s->qcow->bs->drv->bdrv_make_empty) {
- s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
- }
+ bdrv_make_empty(s->qcow, NULL);
memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
@@ -3130,7 +3128,8 @@ static BlockDriver vvfat_write_target = {
.bdrv_co_pwritev = write_target_commit,
};
-static void vvfat_qcow_options(int *child_flags, QDict *child_options,
+static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format,
+ int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
{
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
@@ -3138,7 +3137,7 @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options,
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
}
-static const BdrvChildRole child_vvfat_qcow = {
+static const BdrvChildClass child_vvfat_qcow = {
.parent_is_bds = true,
.inherit_options = vvfat_qcow_options,
};
@@ -3185,7 +3184,9 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
options = qdict_new();
qdict_put_str(options, "write-target.driver", "qcow");
s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
- &child_vvfat_qcow, false, errp);
+ &child_vvfat_qcow,
+ BDRV_CHILD_DATA | BDRV_CHILD_METADATA,
+ false, errp);
qobject_unref(options);
if (!s->qcow) {
ret = -EINVAL;
@@ -3212,14 +3213,14 @@ err:
}
static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
BDRVVVFATState *s = bs->opaque;
- assert(c == s->qcow || role == &child_backing);
+ assert(c == s->qcow || (role & BDRV_CHILD_COW));
if (c == s->qcow) {
/* This is a private node, nobody should try to attach to it */
diff --git a/blockjob.c b/blockjob.c
index 2affa1844d..470facfd47 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -163,7 +163,7 @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
job->job.aio_context = ctx;
}
-static const BdrvChildRole child_job = {
+static const BdrvChildClass child_job = {
.get_parent_desc = child_job_get_parent_desc,
.drained_begin = child_job_drained_begin,
.drained_poll = child_job_drained_poll,
@@ -217,8 +217,9 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
if (job->job.aio_context != qemu_get_aio_context()) {
aio_context_release(job->job.aio_context);
}
- c = bdrv_root_attach_child(bs, name, &child_job, job->job.aio_context,
- perm, shared_perm, job, errp);
+ c = bdrv_root_attach_child(bs, name, &child_job, 0,
+ job->job.aio_context, perm, shared_perm, job,
+ errp);
if (job->job.aio_context != qemu_get_aio_context()) {
aio_context_acquire(job->job.aio_context);
}
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index a6cdb4fb7b..6a0221a681 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -240,7 +240,7 @@ static void sbsa_flash_map1(PFlashCFI01 *flash,
{
DeviceState *dev = DEVICE(flash);
- assert(size % SBSA_FLASH_SECTOR_SIZE == 0);
+ assert(QEMU_IS_ALIGNED(size, SBSA_FLASH_SECTOR_SIZE));
assert(size / SBSA_FLASH_SECTOR_SIZE <= UINT32_MAX);
qdev_prop_set_uint32(dev, "num-blocks", size / SBSA_FLASH_SECTOR_SIZE);
qdev_init_nofail(dev);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index c41d5f9778..37462a6f78 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -977,7 +977,7 @@ static void virt_flash_map1(PFlashCFI01 *flash,
{
DeviceState *dev = DEVICE(flash);
- assert(size % VIRT_FLASH_SECTOR_SIZE == 0);
+ assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE));
assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
qdev_init_nofail(dev);
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 24f3bce7ef..8e8887253d 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -965,7 +965,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base,
if (blk) {
qdev_prop_set_drive(dev, "drive", blk, &error_abort);
}
- assert(size % sector_len == 0);
+ assert(QEMU_IS_ALIGNED(size, sector_len));
qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
qdev_prop_set_uint64(dev, "sector-length", sector_len);
qdev_prop_set_uint8(dev, "width", bank_width);
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index f0579ecb17..c277b0309d 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -997,7 +997,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base,
if (blk) {
qdev_prop_set_drive(dev, "drive", blk, &error_abort);
}
- assert(size % sector_len == 0);
+ assert(QEMU_IS_ALIGNED(size, sector_len));
qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
qdev_prop_set_uint32(dev, "sector-length", sector_len);
qdev_prop_set_uint8(dev, "width", width);
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 2abab3a27c..b8d8ef59eb 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -167,7 +167,7 @@ static void pc_system_flash_map(PCMachineState *pcms,
blk_name(blk), strerror(-size));
exit(1);
}
- if (size == 0 || size % FLASH_SECTOR_SIZE != 0) {
+ if (size == 0 || !QEMU_IS_ALIGNED(size, FLASH_SECTOR_SIZE)) {
error_report("system firmware block device %s has invalid size "
"%" PRId64,
blk_name(blk), size);
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 13d91e109a..fc82cbd5f1 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1509,6 +1509,7 @@ static void ahci_cmd_done(IDEDMA *dma)
static void ahci_irq_set(void *opaque, int n, int level)
{
+ qemu_log_mask(LOG_UNIMP, "ahci: IRQ#%d level:%d\n", n, level);
}
static const IDEDMAOps ahci_dma_ops = {
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index c695a44979..7ce28895bc 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -111,7 +111,7 @@ static void virt_flash_map1(PFlashCFI01 *flash,
{
DeviceState *dev = DEVICE(flash);
- assert(size % VIRT_FLASH_SECTOR_SIZE == 0);
+ assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE));
assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
qdev_init_nofail(dev);
diff --git a/include/block/block.h b/include/block/block.h
index 4de8d8f8a6..25e299605e 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -13,7 +13,7 @@
/* block.c */
typedef struct BlockDriver BlockDriver;
typedef struct BdrvChild BdrvChild;
-typedef struct BdrvChildRole BdrvChildRole;
+typedef struct BdrvChildClass BdrvChildClass;
typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
@@ -268,6 +268,62 @@ enum {
DEFAULT_PERM_UNCHANGED = BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH,
};
+/*
+ * Flags that parent nodes assign to child nodes to specify what kind of
+ * role(s) they take.
+ *
+ * At least one of DATA, METADATA, FILTERED, or COW must be set for
+ * every child.
+ */
+enum BdrvChildRoleBits {
+ /*
+ * This child stores data.
+ * Any node may have an arbitrary number of such children.
+ */
+ BDRV_CHILD_DATA = (1 << 0),
+
+ /*
+ * This child stores metadata.
+ * Any node may have an arbitrary number of metadata-storing
+ * children.
+ */
+ BDRV_CHILD_METADATA = (1 << 1),
+
+ /*
+ * A child that always presents exactly the same visible data as
+ * the parent, e.g. by virtue of the parent forwarding all reads
+ * and writes.
+ * This flag is mutually exclusive with DATA, METADATA, and COW.
+ * Any node may have at most one filtered child at a time.
+ */
+ BDRV_CHILD_FILTERED = (1 << 2),
+
+ /*
+ * Child from which to read all data that isn’t allocated in the
+ * parent (i.e., the backing child); such data is copied to the
+ * parent through COW (and optionally COR).
+ * This field is mutually exclusive with DATA, METADATA, and
+ * FILTERED.
+ * Any node may have at most one such backing child at a time.
+ */
+ BDRV_CHILD_COW = (1 << 3),
+
+ /*
+ * The primary child. For most drivers, this is the child whose
+ * filename applies best to the parent node.
+ * Any node may have at most one primary child at a time.
+ */
+ BDRV_CHILD_PRIMARY = (1 << 4),
+
+ /* Useful combination of flags */
+ BDRV_CHILD_IMAGE = BDRV_CHILD_DATA
+ | BDRV_CHILD_METADATA
+ | BDRV_CHILD_PRIMARY,
+};
+
+/* Mask of BdrvChildRoleBits values */
+typedef unsigned int BdrvChildRole;
+
char *bdrv_perm_names(uint64_t perm);
uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm);
@@ -296,7 +352,8 @@ int bdrv_parse_discard_flags(const char *mode, int *flags);
BdrvChild *bdrv_open_child(const char *filename,
QDict *options, const char *bdref_key,
BlockDriverState* parent,
- const BdrvChildRole *child_role,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
bool allow_none, Error **errp);
BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
@@ -352,6 +409,7 @@ BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
void bdrv_refresh_limits(BlockDriverState *bs, Error **errp);
int bdrv_commit(BlockDriverState *bs);
+int bdrv_make_empty(BdrvChild *c, Error **errp);
int bdrv_change_backing_file(BlockDriverState *bs,
const char *backing_file, const char *backing_fmt);
void bdrv_register(BlockDriver *bdrv);
@@ -540,7 +598,8 @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
const char *child_name,
- const BdrvChildRole *child_role,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
Error **errp);
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 7ba8c89036..5e4f4c348c 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -96,6 +96,13 @@ struct BlockDriver {
*/
bool is_filter;
/*
+ * Set to true if the BlockDriver is a format driver. Format nodes
+ * generally do not expect their children to be other format nodes
+ * (except for backing files), and so format probing is disabled
+ * on those children.
+ */
+ bool is_format;
+ /*
* Return true if @to_replace can be replaced by a BDS with the
* same data as @bs without it affecting @bs's behavior (that is,
* without it being visible to @bs's parents).
@@ -549,14 +556,14 @@ struct BlockDriver {
* the parents in @parent_perm and @parent_shared.
*
* If @c is NULL, return the permissions for attaching a new child for the
- * given @role.
+ * given @child_class and @role.
*
* If @reopen_queue is non-NULL, don't return the currently needed
* permissions, but those that will be needed after applying the
* @reopen_queue.
*/
void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t parent_perm, uint64_t parent_shared,
uint64_t *nperm, uint64_t *nshared);
@@ -658,7 +665,7 @@ typedef struct BdrvAioNotifier {
QLIST_ENTRY(BdrvAioNotifier) list;
} BdrvAioNotifier;
-struct BdrvChildRole {
+struct BdrvChildClass {
/* If true, bdrv_replace_node() doesn't change the node this BdrvChild
* points to. */
bool stay_at_node;
@@ -669,7 +676,8 @@ struct BdrvChildRole {
* non-BDS parents. */
bool parent_is_bds;
- void (*inherit_options)(int *child_flags, QDict *child_options,
+ void (*inherit_options)(BdrvChildRole role, bool parent_is_format,
+ int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options);
void (*change_media)(BdrvChild *child, bool load);
@@ -731,14 +739,13 @@ struct BdrvChildRole {
void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore);
};
-extern const BdrvChildRole child_file;
-extern const BdrvChildRole child_format;
-extern const BdrvChildRole child_backing;
+extern const BdrvChildClass child_of_bds;
struct BdrvChild {
BlockDriverState *bs;
char *name;
- const BdrvChildRole *role;
+ const BdrvChildClass *klass;
+ BdrvChildRole role;
void *opaque;
/**
@@ -765,7 +772,7 @@ struct BdrvChild {
/*
* How many times the parent of this child has been drained
- * (through role->drained_*).
+ * (through klass->drained_*).
* Usually, this is equal to bs->quiesce_counter (potentially
* reduced by bdrv_drain_all_count). It may differ while the
* child is entering or leaving a drained section.
@@ -1225,7 +1232,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
const char *child_name,
- const BdrvChildRole *child_role,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
AioContext *ctx,
uint64_t perm, uint64_t shared_perm,
void *opaque, Error **errp);
@@ -1252,29 +1260,20 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
*/
int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp);
-/* Default implementation for BlockDriver.bdrv_child_perm() that can be used by
- * block filters: Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED and RESIZE to
- * all children */
-void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
- BlockReopenQueue *reopen_queue,
- uint64_t perm, uint64_t shared,
- uint64_t *nperm, uint64_t *nshared);
-
-/* Default implementation for BlockDriver.bdrv_child_perm() that can be used by
- * (non-raw) image formats: Like above for bs->backing, but for bs->file it
- * requires WRITE | RESIZE for read-write images, always requires
- * CONSISTENT_READ and doesn't share WRITE. */
-void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
- BlockReopenQueue *reopen_queue,
- uint64_t perm, uint64_t shared,
- uint64_t *nperm, uint64_t *nshared);
-
bool bdrv_recurse_can_replace(BlockDriverState *bs,
BlockDriverState *to_replace);
/*
+ * Default implementation for BlockDriver.bdrv_child_perm() that can
+ * be used by block filters and image formats, as long as they use the
+ * child_of_bds child class and set an appropriate BdrvChildRole.
+ */
+void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c,
+ BdrvChildRole role, BlockReopenQueue *reopen_queue,
+ uint64_t perm, uint64_t shared,
+ uint64_t *nperm, uint64_t *nshared);
+
+/*
* Default implementation for drivers to pass bdrv_co_block_status() to
* their file.
*/
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 0917663d89..8203d7f6f9 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -266,4 +266,6 @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
const BdrvChild *blk_root(BlockBackend *blk);
+int blk_make_empty(BlockBackend *blk, Error **errp);
+
#endif
diff --git a/qemu-img.c b/qemu-img.c
index 947bf8b34b..2a9186139d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1108,11 +1108,20 @@ static int img_commit(int argc, char **argv)
goto unref_backing;
}
- if (!drop && bs->drv->bdrv_make_empty) {
- ret = bs->drv->bdrv_make_empty(bs);
- if (ret) {
- error_setg_errno(&local_err, -ret, "Could not empty %s",
- filename);
+ if (!drop) {
+ BlockBackend *old_backing_blk;
+
+ old_backing_blk = blk_new_with_bs(bs, BLK_PERM_WRITE, BLK_PERM_ALL,
+ &local_err);
+ if (!old_backing_blk) {
+ goto unref_backing;
+ }
+ ret = blk_make_empty(old_backing_blk, &local_err);
+ blk_unref(old_backing_blk);
+ if (ret == -ENOTSUP) {
+ error_free(local_err);
+ local_err = NULL;
+ } else if (ret < 0) {
goto unref_backing;
}
}
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 104e3cee1b..1cdd7e2999 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -354,14 +354,14 @@ class TestParallelOps(iotests.QMPTestCase):
self.assert_qmp(result, 'error/desc',
"Node 'node5' is busy: block device is in use by block job: commit")
+ result = self.vm.qmp('block-job-set-speed', device='commit-drive0', speed=0)
+ self.assert_qmp(result, 'return', {})
+
event = self.vm.event_wait(name='BLOCK_JOB_READY')
self.assert_qmp(event, 'data/device', 'commit-drive0')
self.assert_qmp(event, 'data/type', 'commit')
self.assert_qmp_absent(event, 'data/error')
- result = self.vm.qmp('block-job-set-speed', device='commit-drive0', speed=0)
- self.assert_qmp(result, 'return', {})
-
result = self.vm.qmp('block-job-complete', device='commit-drive0')
self.assert_qmp(result, 'return', {})
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index 1812dd8479..601c756117 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -240,6 +240,49 @@ class TestSingleBlockdev(TestSingleDrive):
target=self.qmp_target)
self.assert_qmp(result, 'error/class', 'GenericError')
+ def do_test_resize(self, device, node):
+ def pre_finalize():
+ if device:
+ result = self.vm.qmp('block_resize', device=device, size=65536)
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ result = self.vm.qmp('block_resize', node_name=node, size=65536)
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ result = self.vm.qmp(self.qmp_cmd, job_id='job0', device='drive0',
+ sync='full', target=self.qmp_target,
+ auto_finalize=False, auto_dismiss=False)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.run_job('job0', auto_finalize=False,
+ pre_finalize=pre_finalize)
+ self.assertEqual(result, None)
+
+ def test_source_resize(self):
+ self.do_test_resize('drive0', 'top')
+
+ def test_target_resize(self):
+ self.do_test_resize(None, self.qmp_target)
+
+ def do_test_target_size(self, size):
+ result = self.vm.qmp('block_resize', node_name=self.qmp_target,
+ size=size)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp(self.qmp_cmd, job_id='job0',
+ device='drive0', sync='full', auto_dismiss=False,
+ target=self.qmp_target)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.run_job('job0')
+ self.assertEqual(result, 'Source and target image have different sizes')
+
+ def test_small_target(self):
+ self.do_test_target_size(self.image_len // 2)
+
+ def test_large_target(self):
+ self.do_test_target_size(self.image_len * 2)
+
test_large_cluster = None
test_image_not_found = None
test_small_buffer2 = None
@@ -251,6 +294,8 @@ class TestSingleDriveZeroLength(TestSingleDrive):
class TestSingleBlockdevZeroLength(TestSingleBlockdev):
image_len = 0
+ test_small_target = None
+ test_large_target = None
class TestSingleDriveUnalignedLength(TestSingleDrive):
image_len = 1025 * 1024
diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
index 877b76fd31..53abe11d73 100644
--- a/tests/qemu-iotests/041.out
+++ b/tests/qemu-iotests/041.out
@@ -1,5 +1,5 @@
-..............................................................................................
+........................................................................................................
----------------------------------------------------------------------
-Ran 94 tests
+Ran 104 tests
OK
diff --git a/tests/qemu-iotests/098.out b/tests/qemu-iotests/098.out
index 7634d0e8b0..23cf371f53 100644
--- a/tests/qemu-iotests/098.out
+++ b/tests/qemu-iotests/098.out
@@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
+qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
No errors were found on the image.
=== empty_image_prepare ===
@@ -15,7 +15,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
+qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
Leaked cluster 4 refcount=1 reference=0
Leaked cluster 5 refcount=1 reference=0
Repairing cluster 4 refcount=1 reference=0
@@ -28,7 +28,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
+qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
ERROR cluster 0 refcount=0 reference=1
ERROR cluster 1 refcount=0 reference=1
ERROR cluster 3 refcount=0 reference=1
@@ -42,7 +42,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
+qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
ERROR cluster 0 refcount=0 reference=1
ERROR cluster 1 refcount=0 reference=1
ERROR cluster 3 refcount=0 reference=1
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
index 5bc2e9b001..3ffeaf3c55 100755
--- a/tests/qemu-iotests/109
+++ b/tests/qemu-iotests/109
@@ -77,14 +77,14 @@ for fmt in qcow qcow2 qed vdi vmdk vpc; do
echo "=== Writing a $fmt header into raw ==="
echo
- _make_test_img 64M
TEST_IMG="$TEST_IMG.src" IMGFMT=$fmt _make_test_img 64M
+ _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size
# This first test should fail: The image format was probed, we may not
# write an image header at the start of the image
run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" |
_filter_block_job_len
- $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io
+ $QEMU_IO -c 'read -P 0 0 512' "$TEST_IMG" | _filter_qemu_io
# When raw was explicitly specified, the same must succeed
@@ -103,12 +103,12 @@ for sample_img in empty.bochs iotest-dirtylog-10G-4M.vhdx parallels-v1 \
# Can't use _use_sample_img because that isn't designed to be used multiple
# times and it overwrites $TEST_IMG (both breaks cleanup)
- _make_test_img 64M
bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src"
+ _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size
run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" |
_filter_block_job_offset | _filter_block_job_len
- $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io
+ $QEMU_IO -c 'read -P 0 0 512' "$TEST_IMG" | _filter_qemu_io
run_qemu "$TEST_IMG" "$TEST_IMG.src" "'format': 'raw'," "BLOCK_JOB_READY"
$QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src"
@@ -119,8 +119,8 @@ echo "=== Write legitimate MBR into raw ==="
echo
for sample_img in grub_mbr.raw; do
- _make_test_img 64M
bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src"
+ _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size
run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_READY"
$QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src"
diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out
index 884f65f18d..ad739df46c 100644
--- a/tests/qemu-iotests/109.out
+++ b/tests/qemu-iotests/109.out
@@ -2,8 +2,8 @@ QA output created by 109
=== Writing a qcow header into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -23,8 +23,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -43,13 +43,12 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Writing a qcow2 header into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -69,8 +68,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -89,13 +88,12 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Writing a qed header into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -115,8 +113,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -135,13 +133,12 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Writing a vdi header into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -161,8 +158,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -181,13 +178,12 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Writing a vmdk header into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -207,8 +203,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -227,13 +223,12 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Writing a vpc header into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -253,8 +248,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -273,12 +268,11 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Copying sample image empty.bochs into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -298,8 +292,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -318,12 +312,11 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Copying sample image iotest-dirtylog-10G-4M.vhdx into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -343,8 +336,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -363,12 +356,11 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Copying sample image parallels-v1 into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -388,8 +380,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -408,12 +400,11 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Copying sample image simple-pattern.cloop into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -433,8 +424,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
-read 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -453,12 +444,11 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
=== Write legitimate MBR into raw ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}}
@@ -480,7 +470,6 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
{ 'execute': 'qmp_capabilities' }
{"return": {}}
@@ -500,6 +489,5 @@ Images are identical.
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
-Warning: Image size mismatch!
Images are identical.
*** done
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
index 866168b236..99acb55ebb 100755
--- a/tests/qemu-iotests/229
+++ b/tests/qemu-iotests/229
@@ -33,6 +33,7 @@ _cleanup()
_cleanup_test_img
_rm_test_img "$TEST_IMG"
_rm_test_img "$DEST_IMG"
+ rm -f "$TEST_DIR/blkdebug.conf"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -49,11 +50,10 @@ _supported_os Linux
DEST_IMG="$TEST_DIR/d.$IMGFMT"
TEST_IMG="$TEST_DIR/b.$IMGFMT"
+BLKDEBUG_CONF="$TEST_DIR/blkdebug.conf"
_make_test_img 2M
-
-# destination for mirror will be too small, causing error
-TEST_IMG=$DEST_IMG _make_test_img 1M
+TEST_IMG=$DEST_IMG _make_test_img 2M
$QEMU_IO -c 'write 0 2M' "$TEST_IMG" | _filter_qemu_io
@@ -67,11 +67,18 @@ echo
echo '=== Starting drive-mirror, causing error & stop ==='
echo
+cat > "$BLKDEBUG_CONF" <<EOF
+[inject-error]
+event = "write_aio"
+errno = "5"
+once = "on"
+EOF
+
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'drive-mirror',
'arguments': {'device': 'testdisk',
'format': '$IMGFMT',
- 'target': '$DEST_IMG',
+ 'target': 'blkdebug:$BLKDEBUG_CONF:$DEST_IMG',
'sync': 'full',
'mode': 'existing',
'on-source-error': 'stop',
@@ -90,7 +97,8 @@ success_or_failure="y" _send_qemu_cmd $QEMU_HANDLE \
'arguments': { 'device': 'testdisk',
'force': true}}" \
"BLOCK_JOB_CANCELLED" "Assertion" \
- | grep -v '"BLOCK_JOB_ERROR"'
+ | grep -v '"BLOCK_JOB_ERROR"' \
+ | _filter_block_job_offset
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/229.out b/tests/qemu-iotests/229.out
index 22350d75d7..4de6dfaa28 100644
--- a/tests/qemu-iotests/229.out
+++ b/tests/qemu-iotests/229.out
@@ -1,6 +1,6 @@
QA output created by 229
Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=2097152
-Formatting 'TEST_DIR/d.IMGFMT', fmt=IMGFMT size=1048576
+Formatting 'TEST_DIR/d.IMGFMT', fmt=IMGFMT size=2097152
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{'execute': 'qmp_capabilities'}
@@ -8,7 +8,7 @@ wrote 2097152/2097152 bytes at offset 0
=== Starting drive-mirror, causing error & stop ===
-{'execute': 'drive-mirror', 'arguments': {'device': 'testdisk', 'format': 'IMGFMT', 'target': 'TEST_DIR/d.IMGFMT', 'sync': 'full', 'mode': 'existing', 'on-source-error': 'stop', 'on-target-error': 'stop' }}
+{'execute': 'drive-mirror', 'arguments': {'device': 'testdisk', 'format': 'IMGFMT', 'target': 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/d.IMGFMT', 'sync': 'full', 'mode': 'existing', 'on-source-error': 'stop', 'on-target-error': 'stop' }}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "testdisk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}}
{"return": {}}
@@ -21,5 +21,5 @@ wrote 2097152/2097152 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "testdisk"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": 1048576, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": OFFSET, "speed": 0, "type": "mirror"}}
*** done
diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297
new file mode 100755
index 0000000000..5c5420712b
--- /dev/null
+++ b/tests/qemu-iotests/297
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+#
+# Copyright (C) 2020 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+seq=$(basename $0)
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+# get standard environment
+. ./common.rc
+
+if ! type -p "pylint-3" > /dev/null; then
+ _notrun "pylint-3 not found"
+fi
+if ! type -p "mypy" > /dev/null; then
+ _notrun "mypy not found"
+fi
+
+pylint-3 --score=n iotests.py
+
+MYPYPATH=../../python/ mypy --warn-unused-configs --disallow-subclassing-any \
+ --disallow-any-generics --disallow-incomplete-defs \
+ --disallow-untyped-decorators --no-implicit-optional \
+ --warn-redundant-casts --warn-unused-ignores \
+ --no-implicit-reexport iotests.py
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/297.out b/tests/qemu-iotests/297.out
new file mode 100644
index 0000000000..6acc843649
--- /dev/null
+++ b/tests/qemu-iotests/297.out
@@ -0,0 +1,3 @@
+QA output created by 297
+Success: no issues found in 1 source file
+*** done
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 279e0bbb0d..03e4f71808 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -156,6 +156,11 @@ _filter_img_create()
-e "s# compression_type=[a-zA-Z0-9]\\+##g"
}
+_filter_img_create_size()
+{
+ $SED -e "s# size=[0-9]\\+# size=SIZE#g"
+}
+
_filter_img_info()
{
if [[ "$1" == "--format-specific" ]]; then
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 34175fd437..445c26f8d2 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -300,3 +300,4 @@
289 rw quick
290 rw auto quick
292 rw auto quick
+297 meta
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 6c0e781af7..f20d90f969 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -1040,7 +1040,7 @@ def _verify_cache_mode(supported_cache_modes: Sequence[str] = ()) -> None:
if supported_cache_modes and (cachemode not in supported_cache_modes):
notrun('not suitable for this cache mode: %s' % cachemode)
-def _verify_aio_mode(supported_aio_modes: Sequence[str] = ()):
+def _verify_aio_mode(supported_aio_modes: Sequence[str] = ()) -> None:
if supported_aio_modes and (aiomode not in supported_aio_modes):
notrun('not suitable for this aio mode: %s' % aiomode)
@@ -1087,7 +1087,8 @@ def skip_if_unsupported(required_formats=(), read_only=False):
'''Skip Test Decorator
Runs the test if all the required formats are whitelisted'''
def skip_test_decorator(func):
- def func_wrapper(test_case: QMPTestCase, *args, **kwargs):
+ def func_wrapper(test_case: QMPTestCase, *args: List[Any],
+ **kwargs: Dict[str, Any]) -> None:
if callable(required_formats):
fmts = required_formats(test_case)
else:
@@ -1097,9 +1098,8 @@ def skip_if_unsupported(required_formats=(), read_only=False):
if usf_list:
msg = f'{test_case}: formats {usf_list} are not whitelisted'
test_case.case_skip(msg)
- return None
else:
- return func(test_case, *args, **kwargs)
+ func(test_case, *args, **kwargs)
return func_wrapper
return skip_test_decorator
@@ -1168,18 +1168,17 @@ def execute_setup_common(supported_fmts: Sequence[str] = (),
sys.stderr.write('Please run this test via the "check" script\n')
sys.exit(os.EX_USAGE)
+ debug = '-d' in sys.argv
+ if debug:
+ sys.argv.remove('-d')
+ logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN))
+
_verify_image_format(supported_fmts, unsupported_fmts)
_verify_protocol(supported_protocols, unsupported_protocols)
_verify_platform(supported=supported_platforms)
_verify_cache_mode(supported_cache_modes)
_verify_aio_mode(supported_aio_modes)
- debug = '-d' in sys.argv
- if debug:
- sys.argv.remove('-d')
- logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN))
- logger.debug("iotests debugging messages active")
-
return debug
def execute_test(*args, test_function=None, **kwargs):
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
index fa0e6a648b..1107271840 100644
--- a/tests/test-bdrv-drain.c
+++ b/tests/test-bdrv-drain.c
@@ -85,22 +85,6 @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
return 0;
}
-static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
- BlockReopenQueue *reopen_queue,
- uint64_t perm, uint64_t shared,
- uint64_t *nperm, uint64_t *nshared)
-{
- /* bdrv_format_default_perms() accepts only these two, so disguise
- * detach_by_driver_cb_role as one of them. */
- if (role != &child_file && role != &child_backing) {
- role = &child_file;
- }
-
- bdrv_format_default_perms(bs, c, role, reopen_queue, perm, shared,
- nperm, nshared);
-}
-
static int bdrv_test_change_backing_file(BlockDriverState *bs,
const char *backing_file,
const char *backing_fmt)
@@ -118,7 +102,7 @@ static BlockDriver bdrv_test = {
.bdrv_co_drain_begin = bdrv_test_co_drain_begin,
.bdrv_co_drain_end = bdrv_test_co_drain_end,
- .bdrv_child_perm = bdrv_test_child_perm,
+ .bdrv_child_perm = bdrv_default_perms,
.bdrv_change_backing_file = bdrv_test_change_backing_file,
};
@@ -1134,7 +1118,7 @@ static BlockDriver bdrv_test_top_driver = {
.bdrv_close = bdrv_test_top_close,
.bdrv_co_preadv = bdrv_test_top_co_preadv,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
};
typedef struct TestCoDeleteByDrainData {
@@ -1200,7 +1184,8 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
&error_abort);
- bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort);
+ bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds,
+ BDRV_CHILD_DATA, &error_abort);
/* This child will be the one to pass to requests through to, and
* it will stall until a drain occurs */
@@ -1208,14 +1193,17 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
&error_abort);
child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS;
/* Takes our reference to child_bs */
- tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", &child_file,
+ tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child",
+ &child_of_bds,
+ BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
&error_abort);
/* This child is just there to be deleted
* (for detach_instead_of_delete == true) */
null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
&error_abort);
- bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort);
+ bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA,
+ &error_abort);
blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
blk_insert_bs(blk, bs, &error_abort);
@@ -1312,7 +1300,8 @@ static void detach_indirect_bh(void *opaque)
bdrv_ref(data->c);
data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C",
- &child_file, &error_abort);
+ &child_of_bds, BDRV_CHILD_DATA,
+ &error_abort);
}
static void detach_by_parent_aio_cb(void *opaque, int ret)
@@ -1329,10 +1318,10 @@ static void detach_by_driver_cb_drained_begin(BdrvChild *child)
{
aio_bh_schedule_oneshot(qemu_get_current_aio_context(),
detach_indirect_bh, &detach_by_parent_data);
- child_file.drained_begin(child);
+ child_of_bds.drained_begin(child);
}
-static BdrvChildRole detach_by_driver_cb_role;
+static BdrvChildClass detach_by_driver_cb_class;
/*
* Initial graph:
@@ -1349,7 +1338,7 @@ static BdrvChildRole detach_by_driver_cb_role;
*
* by_parent_cb == false: Test that bdrv_drain_invoke() doesn't poll
*
- * PA's BdrvChildRole has a .drained_begin callback that schedules a BH
+ * PA's BdrvChildClass has a .drained_begin callback that schedules a BH
* that does the same graph change. If bdrv_drain_invoke() calls it, the
* state is messed up, but if it is only polled in the single
* BDRV_POLL_WHILE() at the end of the drain, this should work fine.
@@ -1364,8 +1353,8 @@ static void test_detach_indirect(bool by_parent_cb)
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0);
if (!by_parent_cb) {
- detach_by_driver_cb_role = child_file;
- detach_by_driver_cb_role.drained_begin =
+ detach_by_driver_cb_class = child_of_bds;
+ detach_by_driver_cb_class.drained_begin =
detach_by_driver_cb_drained_begin;
}
@@ -1394,13 +1383,15 @@ static void test_detach_indirect(bool by_parent_cb)
/* Set child relationships */
bdrv_ref(b);
bdrv_ref(a);
- child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, &error_abort);
- child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, &error_abort);
+ child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds,
+ BDRV_CHILD_DATA, &error_abort);
+ child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds,
+ BDRV_CHILD_COW, &error_abort);
bdrv_ref(a);
bdrv_attach_child(parent_a, a, "PA-A",
- by_parent_cb ? &child_file : &detach_by_driver_cb_role,
- &error_abort);
+ by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class,
+ BDRV_CHILD_DATA, &error_abort);
g_assert_cmpint(parent_a->refcnt, ==, 1);
g_assert_cmpint(parent_b->refcnt, ==, 1);
@@ -1735,7 +1726,7 @@ static int drop_intermediate_poll_update_filename(BdrvChild *child,
/**
* Test a poll in the midst of bdrv_drop_intermediate().
*
- * bdrv_drop_intermediate() calls BdrvChildRole.update_filename(),
+ * bdrv_drop_intermediate() calls BdrvChildClass.update_filename(),
* which can yield or poll. This may lead to graph changes, unless
* the whole subtree in question is drained.
*
@@ -1772,7 +1763,7 @@ static int drop_intermediate_poll_update_filename(BdrvChild *child,
*
* The solution is for bdrv_drop_intermediate() to drain top's
* subtree. This prevents graph changes from happening just because
- * BdrvChildRole.update_filename() yields or polls. Thus, the block
+ * BdrvChildClass.update_filename() yields or polls. Thus, the block
* job is paused during that drained section and must finish before or
* after.
*
@@ -1780,7 +1771,7 @@ static int drop_intermediate_poll_update_filename(BdrvChild *child,
*/
static void test_drop_intermediate_poll(void)
{
- static BdrvChildRole chain_child_role;
+ static BdrvChildClass chain_child_class;
BlockDriverState *chain[3];
TestSimpleBlockJob *job;
BlockDriverState *job_node;
@@ -1788,8 +1779,8 @@ static void test_drop_intermediate_poll(void)
int i;
int ret;
- chain_child_role = child_backing;
- chain_child_role.update_filename = drop_intermediate_poll_update_filename;
+ chain_child_class = child_of_bds;
+ chain_child_class.update_filename = drop_intermediate_poll_update_filename;
for (i = 0; i < 3; i++) {
char name[32];
@@ -1810,8 +1801,8 @@ static void test_drop_intermediate_poll(void)
if (i) {
/* Takes the reference to chain[i - 1] */
chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1],
- "chain", &chain_child_role,
- &error_abort);
+ "chain", &chain_child_class,
+ BDRV_CHILD_COW, &error_abort);
}
}
@@ -1956,7 +1947,7 @@ static BlockDriver bdrv_replace_test = {
.bdrv_co_drain_begin = bdrv_replace_test_co_drain_begin,
.bdrv_co_drain_end = bdrv_replace_test_co_drain_end,
- .bdrv_child_perm = bdrv_format_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
};
static void coroutine_fn test_replace_child_mid_drain_read_co(void *opaque)
@@ -2029,7 +2020,8 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
bdrv_ref(old_child_bs);
parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child",
- &child_backing, &error_abort);
+ &child_of_bds, BDRV_CHILD_COW,
+ &error_abort);
for (i = 0; i < old_drain_count; i++) {
bdrv_drained_begin(old_child_bs);
diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
index a007754d9e..f93f3168b0 100644
--- a/tests/test-bdrv-graph-mod.c
+++ b/tests/test-bdrv-graph-mod.c
@@ -26,11 +26,11 @@
static BlockDriver bdrv_pass_through = {
.format_name = "pass-through",
- .bdrv_child_perm = bdrv_filter_default_perms,
+ .bdrv_child_perm = bdrv_default_perms,
};
static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c,
- const BdrvChildRole *role,
+ BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
@@ -111,7 +111,8 @@ static void test_update_perm_tree(void)
blk_insert_bs(root, bs, &error_abort);
- bdrv_attach_child(filter, bs, "child", &child_file, &error_abort);
+ bdrv_attach_child(filter, bs, "child", &child_of_bds,
+ BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort);
bdrv_append(filter, bs, &local_err);
@@ -177,7 +178,8 @@ static void test_should_update_child(void)
bdrv_set_backing_hd(target, bs, &error_abort);
g_assert(target->backing->bs == bs);
- bdrv_attach_child(filter, target, "target", &child_file, &error_abort);
+ bdrv_attach_child(filter, target, "target", &child_of_bds,
+ BDRV_CHILD_DATA, &error_abort);
bdrv_append(filter, bs, &error_abort);
g_assert(target->backing->bs == bs);
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
index 71e9bce3b1..a953794be2 100644
--- a/tests/test-block-iothread.c
+++ b/tests/test-block-iothread.c
@@ -482,8 +482,13 @@ static void test_propagate_basic(void)
BlockDriverState *bs_a, *bs_b, *bs_verify;
QDict *options;
- /* Create bs_a and its BlockBackend */
- blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
+ /*
+ * Create bs_a and its BlockBackend. We cannot take the RESIZE
+ * permission because blkverify will not share it on the test
+ * image.
+ */
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE,
+ BLK_PERM_ALL);
bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
blk_insert_bs(blk, bs_a, &error_abort);
@@ -566,7 +571,13 @@ static void test_propagate_diamond(void)
qdict_put_str(options, "raw", "bs_c");
bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
- blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
+ /*
+ * Do not take the RESIZE permission: This would require the same
+ * from bs_c and thus from bs_a; however, blkverify will not share
+ * it on bs_b, and thus it will not be available for bs_a.
+ */
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE,
+ BLK_PERM_ALL);
blk_insert_bs(blk, bs_verify, &error_abort);
/* Switch the AioContext */