Block layer patches:
- Introduce real BdrvChildRole - blk/bdrv_make_empty() functions instead of calling callbacks directly - mirror: Make sure that source and target size match - block-copy: Fix uninitialized variable - block/replication: Avoid cancelling the job twice - ahci: Log lost IRQs - iotests: Run pylint and mypy in a testcase - iotests: log messages from notrun() -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAl7CwFwRHGt3b2xmQHJl ZGhhdC5jb20ACgkQfwmycsiPL9Y3HA/+N3FRGl6rszYkRWkMSuK1I38e7pe8tvPy NO4FxYnJN4wWI9ayCURf5DMi5IPglLTEfT8KOYiUM4Br5K3jJnWYzI7pqChm5pJr k2pRLVBKpyI7Et5S3gxAEOY56a3+SkR6a8nem6egrCUceuZpR/0nP3reBEkOaBky DMQvSgR9DDPUWNPX2H1ZfTJ/FaxLULDJR1dtdcj/Ze0u72dHRwW4t9X/XqRqLxAq UnFRXhx6PVmjlsX+zxXYxMpeEI+/GLTEwf0LRGsk0nBrJtBb21WhqzltMV/pbqgy U5b9f8o6lGaIKeDZaE1cdIsc8Q1+k9osHc5Jz6ibYrdIixTceDh/6BJdvg+3UdTr luYbYiDV0QfkRP75yjx9FJFJHVPlYdBhqgeXbLYMD7aHEKhh1IEjr2JBUlJ3N0L3 T3p4s/5t8ljSsafnq1KR83xfFeZOslR0hfWz0TZYXlLZMtNuGHz2biR2NyOQO6jH cqbszoRVU/F8W0fk9s4OV+TNB7Ks7I207lO851sxXlz3rOu5qfCRD+KENaTuocZ2 e7Wf455CFhdBDNZok9kGqCTUzJ2ZDP2wca0qU30zbn4VdhzXH+KcDyLRv/fVk+io r/9Hckd7Sdcd0PtTuCeTXBWzIlz1wQDUKrhdII+OaXWeGMHxgLUKVAQla5WGod/K g+tzRW5kJmM= =JSKK -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches: - Introduce real BdrvChildRole - blk/bdrv_make_empty() functions instead of calling callbacks directly - mirror: Make sure that source and target size match - block-copy: Fix uninitialized variable - block/replication: Avoid cancelling the job twice - ahci: Log lost IRQs - iotests: Run pylint and mypy in a testcase - iotests: log messages from notrun() # gpg: Signature made Mon 18 May 2020 18:05:32 BST # gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6 # gpg: issuer "kwolf@redhat.com" # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: (52 commits) hw: Use QEMU_IS_ALIGNED() on parallel flash block size iotests/030: Reduce run time by unthrottling job earlier hw/ide/ahci: Log lost IRQs iotests: log messages from notrun() block/block-copy: Simplify block_copy_do_copy() block/block-copy: Fix uninitialized variable in block_copy_task_entry block: Drop @child_class from bdrv_child_perm() block: Pass BdrvChildRole in remaining cases block: Drop child_file block: Drop bdrv_format_default_perms() block: Make bdrv_filter_default_perms() static block: Use bdrv_default_perms() tests: Use child_of_bds instead of child_file block: Use child_of_bds in remaining places block: Make filter drivers use child_of_bds block: Make format drivers use child_of_bds block: Drop child_backing block: Make backing files child_of_bds children block: Drop child_format block: Switch child_format users to child_of_bds ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
bffe88d139
591
block.c
591
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,14 +2342,19 @@ 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,
|
||||
/*
|
||||
* 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)
|
||||
@ -2364,42 +2363,25 @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
|
||||
*nshared = (shared & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED;
|
||||
}
|
||||
|
||||
void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
|
||||
const BdrvChildRole *role,
|
||||
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)
|
||||
{
|
||||
bool backing = (role == &child_backing);
|
||||
assert(role == &child_backing || role == &child_file);
|
||||
assert(role & BDRV_CHILD_COW);
|
||||
|
||||
if (!backing) {
|
||||
int 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);
|
||||
|
||||
/* 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. */
|
||||
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. */
|
||||
/*
|
||||
* 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 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 {
|
||||
@ -2408,6 +2390,84 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
|
||||
|
||||
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)
|
||||
{
|
||||
int flags;
|
||||
|
||||
assert(role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA));
|
||||
|
||||
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);
|
||||
|
||||
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.
|
||||
*/
|
||||
if (!(flags & BDRV_O_NO_IO)) {
|
||||
perm |= BLK_PERM_CONSISTENT_READ;
|
||||
}
|
||||
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2746,6 +2831,20 @@ static bool bdrv_inherits_from_recursive(BlockDriverState *child,
|
||||
return child != NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,9 +3262,23 @@ 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,
|
||||
child_class->inherit_options(child_role, parent_is_format,
|
||||
&flags, options,
|
||||
parent->open_flags, parent->options);
|
||||
}
|
||||
|
||||
@ -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,8 +4900,8 @@ 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,
|
||||
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);
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -343,10 +343,8 @@ 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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,13 +496,13 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
if (drv->bdrv_make_empty) {
|
||||
ret = drv->bdrv_make_empty(bs);
|
||||
if (ret < 0) {
|
||||
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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
||||
|
22
block/io.c
22
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
target_length = blk_getlength(s->target);
|
||||
if (target_length < 0) {
|
||||
ret = target_length;
|
||||
goto immediate_exit;
|
||||
}
|
||||
|
||||
if (s->bdev_length > base_length) {
|
||||
/* Active commit must resize the base image if its size differs from the
|
||||
* active layer. */
|
||||
if (s->base == blk_bs(s->target)) {
|
||||
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(
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
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;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
s->offset = offset;
|
||||
s->has_size = has_size;
|
||||
s->size = has_size ? size : real_size - offset;
|
||||
|
||||
end:
|
||||
|
||||
qemu_opts_del(opts);
|
||||
|
||||
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,
|
||||
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,
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
23
block/vmdk.c
23
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,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -95,6 +95,13 @@ struct BlockDriver {
|
||||
* must implement them and return -ENOTSUP.
|
||||
*/
|
||||
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,
|
||||
@ -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,28 +1260,19 @@ 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.
|
||||
|
@ -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
|
||||
|
19
qemu-img.c
19
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;
|
||||
}
|
||||
}
|
||||
|
@ -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', {})
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
..............................................................................................
|
||||
........................................................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 94 tests
|
||||
Ran 104 tests
|
||||
|
||||
OK
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
44
tests/qemu-iotests/297
Executable file
44
tests/qemu-iotests/297
Executable file
@ -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
|
3
tests/qemu-iotests/297.out
Normal file
3
tests/qemu-iotests/297.out
Normal file
@ -0,0 +1,3 @@
|
||||
QA output created by 297
|
||||
Success: no issues found in 1 source file
|
||||
*** done
|
@ -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
|
||||
|
@ -300,3 +300,4 @@
|
||||
289 rw quick
|
||||
290 rw auto quick
|
||||
292 rw auto quick
|
||||
297 meta
|
||||
|
@ -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):
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user