Block layer patches

- Cleanup bs->backing and bs->file handling
 - Refactor bdrv_try_set_aio_context using transactions
 - Changes for improved coroutine_fn consistency
 - vhost-user-blk: fix the resize crash
 - io_uring: Use of io_uring_register_ring_fd() led to breakage, revert
 - vvfat: Fix some problems with r/w mode
 - Code cleanup
 - MAINTAINERS: Fold "Block QAPI, monitor, ..." into "Block layer core"
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmNazhIRHGt3b2xmQHJl
 ZGhhdC5jb20ACgkQfwmycsiPL9ZyTw/8Dfck/SuxfyeLlnQItkjaV4cnqWOU8vHs
 9x0KhlptCs+HXdF/3iicpA0lHojn7mNnbdFGjPRY4E0LriQv91TQ5ycdEmrseFPf
 sgeQlgdKCVU/pHjZ2wYarm2pE43Cx85a5xuufmw+7w49dNNZn14l4t+DgviuClVM
 nuVaogfZFbYyetre+Qd2TgLl+gJ+0d4o7Zs5lSWLrT8t0L9AGkcWPA7Nrbl6loIE
 dOautV4G7jLjuMiCeJZOGcnuRVe3gCQ5rCGBFzzH4DUtz4BmiYx4hd3LMEsP0PMM
 CrsfDZS04Ztybl9M7TmJuwkAm1gx1JDMOuJuh18lbJocIOBvhkKKxY2wI5LIdZVI
 ZntmU36RowkX+GGu/PYpYyMjBDClJppZCl7vnjyLYsVt6r0Vu6SmlHpJhcRYabhe
 96Kv1LXH9A6+ogKPU3Layw6JGjg01GNr1ALuT7PO3pGto/JshmOuBEJJDucoF84M
 5AfxFCohMROVldwblA6M0eKnlQBgtr5BvtgbV54BBo88VlFJgDJFQn7R09cTFUEo
 UwaJoS+nIaiZ0bQQVZhZloVppUaTdVJojzfVRCZZctga96/tu1HSFnGLnbEFpUN3
 KOf+XnVNS6Ro+nPSDf9bMjbIom2JicGFfV+6yMgIoxY/d5UA2dTZfefil4TAlSod
 6PsTgg+jrm8=
 =/Fw0
 -----END PGP SIGNATURE-----

Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging

Block layer patches

- Cleanup bs->backing and bs->file handling
- Refactor bdrv_try_set_aio_context using transactions
- Changes for improved coroutine_fn consistency
- vhost-user-blk: fix the resize crash
- io_uring: Use of io_uring_register_ring_fd() led to breakage, revert
- vvfat: Fix some problems with r/w mode
- Code cleanup
- MAINTAINERS: Fold "Block QAPI, monitor, ..." into "Block layer core"

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmNazhIRHGt3b2xmQHJl
# ZGhhdC5jb20ACgkQfwmycsiPL9ZyTw/8Dfck/SuxfyeLlnQItkjaV4cnqWOU8vHs
# 9x0KhlptCs+HXdF/3iicpA0lHojn7mNnbdFGjPRY4E0LriQv91TQ5ycdEmrseFPf
# sgeQlgdKCVU/pHjZ2wYarm2pE43Cx85a5xuufmw+7w49dNNZn14l4t+DgviuClVM
# nuVaogfZFbYyetre+Qd2TgLl+gJ+0d4o7Zs5lSWLrT8t0L9AGkcWPA7Nrbl6loIE
# dOautV4G7jLjuMiCeJZOGcnuRVe3gCQ5rCGBFzzH4DUtz4BmiYx4hd3LMEsP0PMM
# CrsfDZS04Ztybl9M7TmJuwkAm1gx1JDMOuJuh18lbJocIOBvhkKKxY2wI5LIdZVI
# ZntmU36RowkX+GGu/PYpYyMjBDClJppZCl7vnjyLYsVt6r0Vu6SmlHpJhcRYabhe
# 96Kv1LXH9A6+ogKPU3Layw6JGjg01GNr1ALuT7PO3pGto/JshmOuBEJJDucoF84M
# 5AfxFCohMROVldwblA6M0eKnlQBgtr5BvtgbV54BBo88VlFJgDJFQn7R09cTFUEo
# UwaJoS+nIaiZ0bQQVZhZloVppUaTdVJojzfVRCZZctga96/tu1HSFnGLnbEFpUN3
# KOf+XnVNS6Ro+nPSDf9bMjbIom2JicGFfV+6yMgIoxY/d5UA2dTZfefil4TAlSod
# 6PsTgg+jrm8=
# =/Fw0
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 27 Oct 2022 14:29:38 EDT
# 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

* tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (58 commits)
  block/block-backend: blk_set_enable_write_cache is IO_CODE
  monitor: switch to *_co_* functions
  vmdk: switch to *_co_* functions
  vhdx: switch to *_co_* functions
  vdi: switch to *_co_* functions
  qed: switch to *_co_* functions
  qcow2: switch to *_co_* functions
  qcow: switch to *_co_* functions
  parallels: switch to *_co_* functions
  mirror: switch to *_co_* functions
  block: switch to *_co_* functions
  commit: switch to *_co_* functions
  vmdk: manually add more coroutine_fn annotations
  qcow2: manually add more coroutine_fn annotations
  qcow: manually add more coroutine_fn annotations
  blkdebug: add missing coroutine_fn annotation for indirect-called functions
  qcow2: add coroutine_fn annotation for indirect-called functions
  block: add missing coroutine_fn annotation to BlockDriverState callbacks
  coroutine-io: add missing coroutine_fn annotation to prototypes
  coroutine-lock: add missing coroutine_fn annotation to prototypes
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2022-10-30 15:15:12 -04:00
commit d5ab9490cd
63 changed files with 1002 additions and 1001 deletions

View file

@ -2509,6 +2509,8 @@ S: Supported
F: block* F: block*
F: block/ F: block/
F: hw/block/ F: hw/block/
F: qapi/block*.json
F: qapi/transaction.json
F: include/block/ F: include/block/
F: include/sysemu/block-*.h F: include/sysemu/block-*.h
F: qemu-img* F: qemu-img*
@ -2583,16 +2585,6 @@ F: include/qemu/co-shared-resource.h
T: git https://gitlab.com/jsnow/qemu.git jobs T: git https://gitlab.com/jsnow/qemu.git jobs
T: git https://gitlab.com/vsementsov/qemu.git block T: git https://gitlab.com/vsementsov/qemu.git block
Block QAPI, monitor, command line
M: Markus Armbruster <armbru@redhat.com>
S: Supported
F: blockdev.c
F: blockdev-hmp-cmds.c
F: block/qapi.c
F: qapi/block*.json
F: qapi/transaction.json
T: git https://repo.or.cz/qemu/armbru.git block-next
Compute Express Link Compute Express Link
M: Ben Widawsky <ben.widawsky@intel.com> M: Ben Widawsky <ben.widawsky@intel.com>
M: Jonathan Cameron <jonathan.cameron@huawei.com> M: Jonathan Cameron <jonathan.cameron@huawei.com>

883
block.c

File diff suppressed because it is too large Load diff

View file

@ -309,7 +309,7 @@ static void coroutine_fn backup_pause(Job *job)
} }
} }
static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed) static void backup_set_speed(BlockJob *job, int64_t speed)
{ {
BackupBlockJob *s = container_of(job, BackupBlockJob, common); BackupBlockJob *s = container_of(job, BackupBlockJob, common);

View file

@ -503,12 +503,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Open the image file */ /* Open the image file */
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", ret = bdrv_open_file_child(qemu_opt_get(opts, "x-image"), options, "image",
bs, &child_of_bds, bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp);
if (!bs->file) {
ret = -EINVAL;
goto out; goto out;
} }
@ -672,7 +669,7 @@ blkdebug_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
} }
static int blkdebug_co_flush(BlockDriverState *bs) static int coroutine_fn blkdebug_co_flush(BlockDriverState *bs)
{ {
int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH); int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH);

View file

@ -155,11 +155,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Open the file */ /* Open the file */
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false, if (ret < 0) {
errp);
if (!bs->file) {
ret = -EINVAL;
goto fail; goto fail;
} }
@ -257,10 +254,6 @@ fail_log:
s->log_file = NULL; s->log_file = NULL;
} }
fail: fail:
if (ret < 0) {
bdrv_unref_child(bs, bs->file);
bs->file = NULL;
}
qemu_opts_del(opts); qemu_opts_del(opts);
return ret; return ret;
} }

View file

@ -26,11 +26,8 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
/* Open the image file */ /* Open the image file */
bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "image", bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp);
if (!bs->file) {
ret = -EINVAL;
goto fail; goto fail;
} }

View file

@ -122,12 +122,9 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Open the raw file */ /* Open the raw file */
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw", ret = bdrv_open_file_child(qemu_opt_get(opts, "x-raw"), options, "raw",
bs, &child_of_bds, bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp);
if (!bs->file) {
ret = -EINVAL;
goto fail; goto fail;
} }

View file

@ -134,10 +134,9 @@ static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter);
static void blk_root_change_media(BdrvChild *child, bool load); static void blk_root_change_media(BdrvChild *child, bool load);
static void blk_root_resize(BdrvChild *child); static void blk_root_resize(BdrvChild *child);
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx, static bool blk_root_change_aio_ctx(BdrvChild *child, AioContext *ctx,
GSList **ignore, Error **errp); GHashTable *visited, Transaction *tran,
static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx, Error **errp);
GSList **ignore);
static char *blk_root_get_parent_desc(BdrvChild *child) static char *blk_root_get_parent_desc(BdrvChild *child)
{ {
@ -334,8 +333,7 @@ static const BdrvChildClass child_root = {
.attach = blk_root_attach, .attach = blk_root_attach,
.detach = blk_root_detach, .detach = blk_root_detach,
.can_set_aio_ctx = blk_root_can_set_aio_ctx, .change_aio_ctx = blk_root_change_aio_ctx,
.set_aio_ctx = blk_root_set_aio_ctx,
.get_parent_aio_context = blk_root_get_parent_aio_context, .get_parent_aio_context = blk_root_get_parent_aio_context,
}; };
@ -1946,7 +1944,7 @@ bool blk_enable_write_cache(BlockBackend *blk)
void blk_set_enable_write_cache(BlockBackend *blk, bool wce) void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
{ {
GLOBAL_STATE_CODE(); IO_CODE();
blk->enable_write_cache = wce; blk->enable_write_cache = wce;
} }
@ -2149,8 +2147,11 @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
bdrv_ref(bs); bdrv_ref(bs);
if (update_root_node) { if (update_root_node) {
ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root, /*
errp); * update_root_node MUST be false for blk_root_set_aio_ctx_commit(),
* as we are already in the commit function of a transaction.
*/
ret = bdrv_try_change_aio_context(bs, new_context, blk->root, errp);
if (ret < 0) { if (ret < 0) {
bdrv_unref(bs); bdrv_unref(bs);
return ret; return ret;
@ -2177,31 +2178,52 @@ int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
return blk_do_set_aio_context(blk, new_context, true, errp); return blk_do_set_aio_context(blk, new_context, true, errp);
} }
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx, typedef struct BdrvStateBlkRootContext {
GSList **ignore, Error **errp) AioContext *new_ctx;
BlockBackend *blk;
} BdrvStateBlkRootContext;
static void blk_root_set_aio_ctx_commit(void *opaque)
{ {
BlockBackend *blk = child->opaque; BdrvStateBlkRootContext *s = opaque;
BlockBackend *blk = s->blk;
if (blk->allow_aio_context_change) { blk_do_set_aio_context(blk, s->new_ctx, false, &error_abort);
return true;
}
/* Only manually created BlockBackends that are not attached to anything
* can change their AioContext without updating their user. */
if (!blk->name || blk->dev) {
/* TODO Add BB name/QOM path */
error_setg(errp, "Cannot change iothread of active block backend");
return false;
}
return true;
} }
static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx, static TransactionActionDrv set_blk_root_context = {
GSList **ignore) .commit = blk_root_set_aio_ctx_commit,
.clean = g_free,
};
static bool blk_root_change_aio_ctx(BdrvChild *child, AioContext *ctx,
GHashTable *visited, Transaction *tran,
Error **errp)
{ {
BlockBackend *blk = child->opaque; BlockBackend *blk = child->opaque;
blk_do_set_aio_context(blk, ctx, false, &error_abort); BdrvStateBlkRootContext *s;
if (!blk->allow_aio_context_change) {
/*
* Manually created BlockBackends (those with a name) that are not
* attached to anything can change their AioContext without updating
* their user; return an error for others.
*/
if (!blk->name || blk->dev) {
/* TODO Add BB name/QOM path */
error_setg(errp, "Cannot change iothread of active block backend");
return false;
}
}
s = g_new(BdrvStateBlkRootContext, 1);
*s = (BdrvStateBlkRootContext) {
.new_ctx = ctx,
.blk = blk,
};
tran_add(tran, &set_blk_root_context, s);
return true;
} }
void blk_add_aio_context_notifier(BlockBackend *blk, void blk_add_aio_context_notifier(BlockBackend *blk,

View file

@ -110,10 +110,9 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0); ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0);

View file

@ -71,10 +71,9 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
/* read header */ /* read header */

View file

@ -135,7 +135,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
} }
if (base_len < len) { if (base_len < len) {
ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL); ret = blk_co_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
if (ret) { if (ret) {
return ret; return ret;
} }
@ -238,6 +238,7 @@ static BlockDriver bdrv_commit_top = {
.bdrv_child_perm = bdrv_commit_top_child_perm, .bdrv_child_perm = bdrv_commit_top_child_perm,
.is_filter = true, .is_filter = true,
.filtered_child_is_backing = true,
}; };
void commit_start(const char *job_id, BlockDriverState *bs, void commit_start(const char *job_id, BlockDriverState *bs,

View file

@ -412,6 +412,7 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
int64_t cluster_size; int64_t cluster_size;
g_autoptr(BlockdevOptions) full_opts = NULL; g_autoptr(BlockdevOptions) full_opts = NULL;
BlockdevOptionsCbw *opts; BlockdevOptionsCbw *opts;
int ret;
full_opts = cbw_parse_options(options, errp); full_opts = cbw_parse_options(options, errp);
if (!full_opts) { if (!full_opts) {
@ -420,11 +421,9 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
assert(full_opts->driver == BLOCKDEV_DRIVER_COPY_BEFORE_WRITE); assert(full_opts->driver == BLOCKDEV_DRIVER_COPY_BEFORE_WRITE);
opts = &full_opts->u.copy_before_write; opts = &full_opts->u.copy_before_write;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp); return ret;
if (!bs->file) {
return -EINVAL;
} }
s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds, s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds,

View file

@ -41,12 +41,11 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
BDRVStateCOR *state = bs->opaque; BDRVStateCOR *state = bs->opaque;
/* Find a bottom node name, if any */ /* Find a bottom node name, if any */
const char *bottom_node = qdict_get_try_str(options, "bottom"); const char *bottom_node = qdict_get_try_str(options, "bottom");
int ret;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp); return ret;
if (!bs->file) {
return -EINVAL;
} }
bs->supported_read_flags = BDRV_REQ_PREFETCH; bs->supported_read_flags = BDRV_REQ_PREFETCH;

View file

@ -261,15 +261,14 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
{ {
BlockCrypto *crypto = bs->opaque; BlockCrypto *crypto = bs->opaque;
QemuOpts *opts = NULL; QemuOpts *opts = NULL;
int ret = -EINVAL; int ret;
QCryptoBlockOpenOptions *open_opts = NULL; QCryptoBlockOpenOptions *open_opts = NULL;
unsigned int cflags = 0; unsigned int cflags = 0;
QDict *cryptoopts = NULL; QDict *cryptoopts = NULL;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
bs->supported_write_flags = BDRV_REQ_FUA & bs->supported_write_flags = BDRV_REQ_FUA &
@ -277,6 +276,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort); opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
if (!qemu_opts_absorb_qdict(opts, options, errp)) { if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL;
goto cleanup; goto cleanup;
} }
@ -285,6 +285,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
open_opts = block_crypto_open_opts_init(cryptoopts, errp); open_opts = block_crypto_open_opts_init(cryptoopts, errp);
if (!open_opts) { if (!open_opts) {
ret = -EINVAL;
goto cleanup; goto cleanup;
} }

View file

@ -440,10 +440,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
block_module_load_one("dmg-bz2"); block_module_load_one("dmg-bz2");

View file

@ -129,7 +129,7 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
/* Ignore errors with fixed-iothread=false */ /* Ignore errors with fixed-iothread=false */
set_context_errp = fixed_iothread ? errp : NULL; set_context_errp = fixed_iothread ? errp : NULL;
ret = bdrv_try_set_aio_context(bs, new_ctx, set_context_errp); ret = bdrv_try_change_aio_context(bs, new_ctx, NULL, set_context_errp);
if (ret == 0) { if (ret == 0) {
aio_context_release(ctx); aio_context_release(ctx);
aio_context_acquire(new_ctx); aio_context_acquire(new_ctx);

View file

@ -30,11 +30,9 @@
static int compress_open(BlockDriverState *bs, QDict *options, int flags, static int compress_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp) Error **errp)
{ {
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, int ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp); return ret;
if (!bs->file) {
return -EINVAL;
} }
if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) { if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {

View file

@ -2744,8 +2744,8 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
return 1; return 1;
} }
ret = bdrv_common_block_status_above(bs, NULL, false, false, offset, ret = bdrv_co_common_block_status_above(bs, NULL, false, false, offset,
bytes, &pnum, NULL, NULL, NULL); bytes, &pnum, NULL, NULL, NULL);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -2754,8 +2754,8 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
return (pnum == bytes) && (ret & BDRV_BLOCK_ZERO); return (pnum == bytes) && (ret & BDRV_BLOCK_ZERO);
} }
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t bytes, int64_t *pnum) int64_t *pnum)
{ {
int ret; int ret;
int64_t dummy; int64_t dummy;

View file

@ -11,7 +11,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include <liburing.h> #include <liburing.h>
#include "block/aio.h" #include "block/aio.h"
#include "qemu/error-report.h"
#include "qemu/queue.h" #include "qemu/queue.h"
#include "block/block.h" #include "block/block.h"
#include "block/raw-aio.h" #include "block/raw-aio.h"
@ -19,7 +18,6 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "trace.h" #include "trace.h"
/* io_uring ring size */ /* io_uring ring size */
#define MAX_ENTRIES 128 #define MAX_ENTRIES 128
@ -432,17 +430,8 @@ LuringState *luring_init(Error **errp)
} }
ioq_init(&s->io_q); ioq_init(&s->io_q);
#ifdef CONFIG_LIBURING_REGISTER_RING_FD
if (io_uring_register_ring_fd(&s->ring) < 0) {
/*
* Only warn about this error: we will fallback to the non-optimized
* io_uring operations.
*/
warn_report("failed to register linux io_uring ring file descriptor");
}
#endif
return s; return s;
} }
void luring_cleanup(LuringState *s) void luring_cleanup(LuringState *s)

View file

@ -922,8 +922,8 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
* active layer. */ * active layer. */
if (s->base == blk_bs(s->target)) { if (s->base == blk_bs(s->target)) {
if (s->bdev_length > target_length) { if (s->bdev_length > target_length) {
ret = blk_truncate(s->target, s->bdev_length, false, ret = blk_co_truncate(s->target, s->bdev_length, false,
PREALLOC_MODE_OFF, 0, NULL); PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) { if (ret < 0) {
goto immediate_exit; goto immediate_exit;
} }
@ -1589,6 +1589,7 @@ static BlockDriver bdrv_mirror_top = {
.bdrv_child_perm = bdrv_mirror_top_child_perm, .bdrv_child_perm = bdrv_mirror_top_child_perm,
.is_filter = true, .is_filter = true,
.filtered_child_is_backing = true,
}; };
static BlockJob *mirror_start_job( static BlockJob *mirror_start_job(

View file

@ -489,7 +489,7 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, err); hmp_handle_error(mon, err);
} }
void hmp_block_resize(Monitor *mon, const QDict *qdict) void coroutine_fn hmp_block_resize(Monitor *mon, const QDict *qdict)
{ {
const char *device = qdict_get_str(qdict, "device"); const char *device = qdict_get_str(qdict, "device");
int64_t size = qdict_get_int(qdict, "size"); int64_t size = qdict_get_int(qdict, "size");

View file

@ -418,7 +418,11 @@ static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts,
int flags, int open_flags, Error **errp) int flags, int open_flags, Error **errp)
{ {
int64_t ret = -EINVAL; int64_t ret = -EINVAL;
#ifdef _WIN32
struct __stat64 st;
#else
struct stat st; struct stat st;
#endif
char *file = NULL, *strp = NULL; char *file = NULL, *strp = NULL;
qemu_mutex_init(&client->mutex); qemu_mutex_init(&client->mutex);
@ -781,7 +785,11 @@ static int nfs_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp) BlockReopenQueue *queue, Error **errp)
{ {
NFSClient *client = state->bs->opaque; NFSClient *client = state->bs->opaque;
#ifdef _WIN32
struct __stat64 st;
#else
struct stat st; struct stat st;
#endif
int ret = 0; int ret = 0;
if (state->flags & BDRV_O_RDWR && bdrv_is_read_only(state->bs)) { if (state->flags & BDRV_O_RDWR && bdrv_is_read_only(state->bs)) {

View file

@ -205,18 +205,18 @@ static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs,
* force the safer-but-slower fallocate. * force the safer-but-slower fallocate.
*/ */
if (s->prealloc_mode == PRL_PREALLOC_MODE_TRUNCATE) { if (s->prealloc_mode == PRL_PREALLOC_MODE_TRUNCATE) {
ret = bdrv_truncate(bs->file, ret = bdrv_co_truncate(bs->file,
(s->data_end + space) << BDRV_SECTOR_BITS, (s->data_end + space) << BDRV_SECTOR_BITS,
false, PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, false, PREALLOC_MODE_OFF,
NULL); BDRV_REQ_ZERO_WRITE, NULL);
if (ret == -ENOTSUP) { if (ret == -ENOTSUP) {
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE; s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
} }
} }
if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) { if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
ret = bdrv_pwrite_zeroes(bs->file, ret = bdrv_co_pwrite_zeroes(bs->file,
s->data_end << BDRV_SECTOR_BITS, s->data_end << BDRV_SECTOR_BITS,
space << BDRV_SECTOR_BITS, 0); space << BDRV_SECTOR_BITS, 0);
} }
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -278,8 +278,8 @@ static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
if (off + to_write > s->header_size) { if (off + to_write > s->header_size) {
to_write = s->header_size - off; to_write = s->header_size - off;
} }
ret = bdrv_pwrite(bs->file, off, to_write, (uint8_t *)s->header + off, ret = bdrv_co_pwrite(bs->file, off, to_write,
0); (uint8_t *)s->header + off, 0);
if (ret < 0) { if (ret < 0) {
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
return ret; return ret;
@ -503,8 +503,8 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
* In order to really repair the image, we must shrink it. * In order to really repair the image, we must shrink it.
* That means we have to pass exact=true. * That means we have to pass exact=true.
*/ */
ret = bdrv_truncate(bs->file, res->image_end_offset, true, ret = bdrv_co_truncate(bs->file, res->image_end_offset, true,
PREALLOC_MODE_OFF, 0, &local_err); PREALLOC_MODE_OFF, 0, &local_err);
if (ret < 0) { if (ret < 0) {
error_report_err(local_err); error_report_err(local_err);
res->check_errors++; res->check_errors++;
@ -599,12 +599,12 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
memset(tmp, 0, sizeof(tmp)); memset(tmp, 0, sizeof(tmp));
memcpy(tmp, &header, sizeof(header)); memcpy(tmp, &header, sizeof(header));
ret = blk_pwrite(blk, 0, BDRV_SECTOR_SIZE, tmp, 0); ret = blk_co_pwrite(blk, 0, BDRV_SECTOR_SIZE, tmp, 0);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }
ret = blk_pwrite_zeroes(blk, BDRV_SECTOR_SIZE, ret = blk_co_pwrite_zeroes(blk, BDRV_SECTOR_SIZE,
(bat_sectors - 1) << BDRV_SECTOR_BITS, 0); (bat_sectors - 1) << BDRV_SECTOR_BITS, 0);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }
@ -736,10 +736,9 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
Error *local_err = NULL; Error *local_err = NULL;
char *buf; char *buf;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
ret = bdrv_pread(bs->file, 0, sizeof(ph), &ph, 0); ret = bdrv_pread(bs->file, 0, sizeof(ph), &ph, 0);

View file

@ -134,6 +134,7 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp) Error **errp)
{ {
BDRVPreallocateState *s = bs->opaque; BDRVPreallocateState *s = bs->opaque;
int ret;
/* /*
* s->data_end and friends should be initialized on permission update. * s->data_end and friends should be initialized on permission update.
@ -141,11 +142,9 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
*/ */
s->file_end = s->zero_start = s->data_end = -EINVAL; s->file_end = s->zero_start = s->data_end = -EINVAL;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp); return ret;
if (!bs->file) {
return -EINVAL;
} }
if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) { if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) {

View file

@ -92,7 +92,8 @@ typedef struct BDRVQcowState {
static QemuOptsList qcow_create_opts; static QemuOptsList qcow_create_opts;
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); static int coroutine_fn decompress_cluster(BlockDriverState *bs,
uint64_t cluster_offset);
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
{ {
@ -121,10 +122,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
qdict_extract_subqdict(options, &encryptopts, "encrypt."); qdict_extract_subqdict(options, &encryptopts, "encrypt.");
encryptfmt = qdict_get_try_str(encryptopts, "format"); encryptfmt = qdict_get_try_str(encryptopts, "format");
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) {
ret = -EINVAL;
goto fail; goto fail;
} }
@ -351,10 +350,11 @@ static int qcow_reopen_prepare(BDRVReopenState *state,
* return 0 if not allocated, 1 if *result is assigned, and negative * return 0 if not allocated, 1 if *result is assigned, and negative
* errno on failure. * errno on failure.
*/ */
static int get_cluster_offset(BlockDriverState *bs, static int coroutine_fn get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate, uint64_t offset, int allocate,
int compressed_size, int compressed_size,
int n_start, int n_end, uint64_t *result) int n_start, int n_end,
uint64_t *result)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
int min_index, i, j, l1_index, l2_index, ret; int min_index, i, j, l1_index, l2_index, ret;
@ -381,9 +381,9 @@ static int get_cluster_offset(BlockDriverState *bs,
s->l1_table[l1_index] = l2_offset; s->l1_table[l1_index] = l2_offset;
tmp = cpu_to_be64(l2_offset); tmp = cpu_to_be64(l2_offset);
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE); BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
ret = bdrv_pwrite_sync(bs->file, ret = bdrv_co_pwrite_sync(bs->file,
s->l1_table_offset + l1_index * sizeof(tmp), s->l1_table_offset + l1_index * sizeof(tmp),
sizeof(tmp), &tmp, 0); sizeof(tmp), &tmp, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -414,14 +414,14 @@ static int get_cluster_offset(BlockDriverState *bs,
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD); BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
if (new_l2_table) { if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
ret = bdrv_pwrite_sync(bs->file, l2_offset, ret = bdrv_co_pwrite_sync(bs->file, l2_offset,
s->l2_size * sizeof(uint64_t), l2_table, 0); s->l2_size * sizeof(uint64_t), l2_table, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
} else { } else {
ret = bdrv_pread(bs->file, l2_offset, s->l2_size * sizeof(uint64_t), ret = bdrv_co_pread(bs->file, l2_offset,
l2_table, 0); s->l2_size * sizeof(uint64_t), l2_table, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -453,8 +453,8 @@ static int get_cluster_offset(BlockDriverState *bs,
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size); cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
/* write the cluster content */ /* write the cluster content */
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_size, ret = bdrv_co_pwrite(bs->file, cluster_offset, s->cluster_size,
s->cluster_cache, 0); s->cluster_cache, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -469,8 +469,9 @@ static int get_cluster_offset(BlockDriverState *bs,
if (cluster_offset + s->cluster_size > INT64_MAX) { if (cluster_offset + s->cluster_size > INT64_MAX) {
return -E2BIG; return -E2BIG;
} }
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size, ret = bdrv_co_truncate(bs->file,
false, PREALLOC_MODE_OFF, 0, NULL); cluster_offset + s->cluster_size,
false, PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -492,9 +493,9 @@ static int get_cluster_offset(BlockDriverState *bs,
return -EIO; return -EIO;
} }
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_pwrite(bs->file, cluster_offset + i, ret = bdrv_co_pwrite(bs->file, cluster_offset + i,
BDRV_SECTOR_SIZE, BDRV_SECTOR_SIZE,
s->cluster_data, 0); s->cluster_data, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -514,8 +515,8 @@ static int get_cluster_offset(BlockDriverState *bs,
} else { } else {
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE); BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
} }
ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp), ret = bdrv_co_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
sizeof(tmp), &tmp, 0); sizeof(tmp), &tmp, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -585,7 +586,8 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
return 0; return 0;
} }
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) static int coroutine_fn decompress_cluster(BlockDriverState *bs,
uint64_t cluster_offset)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
int ret, csize; int ret, csize;
@ -596,7 +598,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
csize = cluster_offset >> (63 - s->cluster_bits); csize = cluster_offset >> (63 - s->cluster_bits);
csize &= (s->cluster_size - 1); csize &= (s->cluster_size - 1);
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED); BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_pread(bs->file, coffset, csize, s->cluster_data, 0); ret = bdrv_co_pread(bs->file, coffset, csize, s->cluster_data, 0);
if (ret < 0) if (ret < 0)
return -1; return -1;
if (decompress_buffer(s->cluster_cache, s->cluster_size, if (decompress_buffer(s->cluster_cache, s->cluster_size,
@ -888,14 +890,14 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
} }
/* write all the data */ /* write all the data */
ret = blk_pwrite(qcow_blk, 0, sizeof(header), &header, 0); ret = blk_co_pwrite(qcow_blk, 0, sizeof(header), &header, 0);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }
if (qcow_opts->has_backing_file) { if (qcow_opts->has_backing_file) {
ret = blk_pwrite(qcow_blk, sizeof(header), backing_filename_len, ret = blk_co_pwrite(qcow_blk, sizeof(header), backing_filename_len,
qcow_opts->backing_file, 0); qcow_opts->backing_file, 0);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }
@ -904,8 +906,8 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
tmp = g_malloc0(BDRV_SECTOR_SIZE); tmp = g_malloc0(BDRV_SECTOR_SIZE);
for (i = 0; i < DIV_ROUND_UP(sizeof(uint64_t) * l1_size, BDRV_SECTOR_SIZE); for (i = 0; i < DIV_ROUND_UP(sizeof(uint64_t) * l1_size, BDRV_SECTOR_SIZE);
i++) { i++) {
ret = blk_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i, ret = blk_co_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i,
BDRV_SECTOR_SIZE, tmp, 0); BDRV_SECTOR_SIZE, tmp, 0);
if (ret < 0) { if (ret < 0) {
g_free(tmp); g_free(tmp);
goto exit; goto exit;

View file

@ -955,8 +955,8 @@ static void set_readonly_helper(gpointer bitmap, gpointer value)
* If header_updated is not NULL then it is set appropriately regardless of * If header_updated is not NULL then it is set appropriately regardless of
* the return value. * the return value.
*/ */
bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
Error **errp) bool *header_updated, Error **errp)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
Qcow2BitmapList *bm_list; Qcow2BitmapList *bm_list;

View file

@ -31,7 +31,8 @@
#include "qemu/memalign.h" #include "qemu/memalign.h"
#include "trace.h" #include "trace.h"
int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size) int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs,
uint64_t exact_size)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int new_l1_size, i, ret; int new_l1_size, i, ret;
@ -47,14 +48,14 @@ int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size)
#endif #endif
BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE); BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE);
ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset + ret = bdrv_co_pwrite_zeroes(bs->file,
new_l1_size * L1E_SIZE, s->l1_table_offset + new_l1_size * L1E_SIZE,
(s->l1_size - new_l1_size) * L1E_SIZE, 0); (s->l1_size - new_l1_size) * L1E_SIZE, 0);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
ret = bdrv_flush(bs->file->bs); ret = bdrv_co_flush(bs->file->bs);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -823,10 +824,10 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
* *
* Return 0 on success and -errno in error cases * Return 0 on success and -errno in error cases
*/ */
int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset, uint64_t offset,
int compressed_size, int compressed_size,
uint64_t *host_offset) uint64_t *host_offset)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int l2_index, ret; int l2_index, ret;
@ -1488,8 +1489,9 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,
* *
* -errno: in error cases * -errno: in error cases
*/ */
static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, static int coroutine_fn handle_copied(BlockDriverState *bs,
uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m) uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes,
QCowL2Meta **m)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int l2_index; int l2_index;
@ -1653,8 +1655,9 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
* *
* -errno: in error cases * -errno: in error cases
*/ */
static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, static int coroutine_fn handle_alloc(BlockDriverState *bs,
uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m) uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes,
QCowL2Meta **m)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int l2_index; int l2_index;

View file

@ -97,7 +97,7 @@ static void update_max_refcount_table_index(BDRVQcow2State *s)
s->max_refcount_table_index = i; s->max_refcount_table_index = i;
} }
int qcow2_refcount_init(BlockDriverState *bs) int coroutine_fn qcow2_refcount_init(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
unsigned int refcount_table_size2, i; unsigned int refcount_table_size2, i;
@ -118,8 +118,8 @@ int qcow2_refcount_init(BlockDriverState *bs)
goto fail; goto fail;
} }
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD); BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
ret = bdrv_pread(bs->file, s->refcount_table_offset, ret = bdrv_co_pread(bs->file, s->refcount_table_offset,
refcount_table_size2, s->refcount_table, 0); refcount_table_size2, s->refcount_table, 0);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -3559,8 +3559,8 @@ static int64_t get_refblock_offset(BlockDriverState *bs, uint64_t offset)
return covering_refblock_offset; return covering_refblock_offset;
} }
static int qcow2_discard_refcount_block(BlockDriverState *bs, static int coroutine_fn
uint64_t discard_block_offs) qcow2_discard_refcount_block(BlockDriverState *bs, uint64_t discard_block_offs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t refblock_offs; int64_t refblock_offs;
@ -3616,7 +3616,7 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
return 0; return 0;
} }
int qcow2_shrink_reftable(BlockDriverState *bs) int coroutine_fn qcow2_shrink_reftable(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t *reftable_tmp = uint64_t *reftable_tmp =
@ -3657,9 +3657,9 @@ int qcow2_shrink_reftable(BlockDriverState *bs)
reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]); reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]);
} }
ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset, ret = bdrv_co_pwrite_sync(bs->file, s->refcount_table_offset,
s->refcount_table_size * REFTABLE_ENTRY_SIZE, s->refcount_table_size * REFTABLE_ENTRY_SIZE,
reftable_tmp, 0); reftable_tmp, 0);
/* /*
* If the write in the reftable failed the image may contain a partially * If the write in the reftable failed the image may contain a partially
* overwritten reftable. In this case it would be better to clear the * overwritten reftable. In this case it would be better to clear the

View file

@ -441,9 +441,9 @@ int coroutine_fn qcow2_check_read_snapshot_table(BlockDriverState *bs,
} QEMU_PACKED snapshot_table_pointer; } QEMU_PACKED snapshot_table_pointer;
/* qcow2_do_open() discards this information in check mode */ /* qcow2_do_open() discards this information in check mode */
ret = bdrv_pread(bs->file, offsetof(QCowHeader, nb_snapshots), ret = bdrv_co_pread(bs->file, offsetof(QCowHeader, nb_snapshots),
sizeof(snapshot_table_pointer), &snapshot_table_pointer, sizeof(snapshot_table_pointer), &snapshot_table_pointer,
0); 0);
if (ret < 0) { if (ret < 0) {
result->check_errors++; result->check_errors++;
fprintf(stderr, "ERROR failed to read the snapshot table pointer from " fprintf(stderr, "ERROR failed to read the snapshot table pointer from "

View file

@ -1306,7 +1306,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
uint64_t l1_vm_state_index; uint64_t l1_vm_state_index;
bool update_header = false; bool update_header = false;
ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0); ret = bdrv_co_pread(bs->file, 0, sizeof(header), &header, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read qcow2 header"); error_setg_errno(errp, -ret, "Could not read qcow2 header");
goto fail; goto fail;
@ -1382,9 +1382,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
if (header.header_length > sizeof(header)) { if (header.header_length > sizeof(header)) {
s->unknown_header_fields_size = header.header_length - sizeof(header); s->unknown_header_fields_size = header.header_length - sizeof(header);
s->unknown_header_fields = g_malloc(s->unknown_header_fields_size); s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
ret = bdrv_pread(bs->file, sizeof(header), ret = bdrv_co_pread(bs->file, sizeof(header),
s->unknown_header_fields_size, s->unknown_header_fields_size,
s->unknown_header_fields, 0); s->unknown_header_fields, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read unknown qcow2 header " error_setg_errno(errp, -ret, "Could not read unknown qcow2 header "
"fields"); "fields");
@ -1579,8 +1579,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_size * L1E_SIZE, ret = bdrv_co_pread(bs->file, s->l1_table_offset, s->l1_size * L1E_SIZE,
s->l1_table, 0); s->l1_table, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read L1 table"); error_setg_errno(errp, -ret, "Could not read L1 table");
goto fail; goto fail;
@ -1699,8 +1699,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
} }
s->image_backing_file = g_malloc(len + 1); s->image_backing_file = g_malloc(len + 1);
ret = bdrv_pread(bs->file, header.backing_file_offset, len, ret = bdrv_co_pread(bs->file, header.backing_file_offset, len,
s->image_backing_file, 0); s->image_backing_file, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read backing file name"); error_setg_errno(errp, -ret, "Could not read backing file name");
goto fail; goto fail;
@ -1905,11 +1905,11 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
.errp = errp, .errp = errp,
.ret = -EINPROGRESS .ret = -EINPROGRESS
}; };
int ret;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
/* Initialise locks */ /* Initialise locks */
@ -3679,7 +3679,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
cpu_to_be64(QCOW2_INCOMPAT_EXTL2); cpu_to_be64(QCOW2_INCOMPAT_EXTL2);
} }
ret = blk_pwrite(blk, 0, cluster_size, header, 0); ret = blk_co_pwrite(blk, 0, cluster_size, header, 0);
g_free(header); g_free(header);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write qcow2 header"); error_setg_errno(errp, -ret, "Could not write qcow2 header");
@ -3689,7 +3689,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
/* Write a refcount table with one refcount block */ /* Write a refcount table with one refcount block */
refcount_table = g_malloc0(2 * cluster_size); refcount_table = g_malloc0(2 * cluster_size);
refcount_table[0] = cpu_to_be64(2 * cluster_size); refcount_table[0] = cpu_to_be64(2 * cluster_size);
ret = blk_pwrite(blk, cluster_size, 2 * cluster_size, refcount_table, 0); ret = blk_co_pwrite(blk, cluster_size, 2 * cluster_size, refcount_table, 0);
g_free(refcount_table); g_free(refcount_table);
if (ret < 0) { if (ret < 0) {
@ -3744,8 +3744,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
} }
/* Okay, now that we have a valid image, let's give it the right size */ /* Okay, now that we have a valid image, let's give it the right size */
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation, ret = blk_co_truncate(blk, qcow2_opts->size, false,
0, errp); qcow2_opts->preallocation, 0, errp);
if (ret < 0) { if (ret < 0) {
error_prepend(errp, "Could not resize image: "); error_prepend(errp, "Could not resize image: ");
goto out; goto out;
@ -5287,8 +5287,8 @@ static int64_t qcow2_check_vmstate_request(BlockDriverState *bs,
return pos; return pos;
} }
static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, static coroutine_fn int qcow2_save_vmstate(BlockDriverState *bs,
int64_t pos) QEMUIOVector *qiov, int64_t pos)
{ {
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos);
if (offset < 0) { if (offset < 0) {
@ -5299,8 +5299,8 @@ static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0); return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0);
} }
static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, static coroutine_fn int qcow2_load_vmstate(BlockDriverState *bs,
int64_t pos) QEMUIOVector *qiov, int64_t pos)
{ {
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos);
if (offset < 0) { if (offset < 0) {

View file

@ -846,7 +846,7 @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
Error **errp); Error **errp);
/* qcow2-refcount.c functions */ /* qcow2-refcount.c functions */
int qcow2_refcount_init(BlockDriverState *bs); int coroutine_fn qcow2_refcount_init(BlockDriverState *bs);
void qcow2_refcount_close(BlockDriverState *bs); void qcow2_refcount_close(BlockDriverState *bs);
int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index, int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
@ -893,14 +893,14 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
BlockDriverAmendStatusCB *status_cb, BlockDriverAmendStatusCB *status_cb,
void *cb_opaque, Error **errp); void *cb_opaque, Error **errp);
int qcow2_shrink_reftable(BlockDriverState *bs); int coroutine_fn qcow2_shrink_reftable(BlockDriverState *bs);
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs); int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs);
/* qcow2-cluster.c functions */ /* qcow2-cluster.c functions */
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
bool exact_size); bool exact_size);
int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size);
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
uint8_t *buf, int nb_sectors, bool enc, Error **errp); uint8_t *buf, int nb_sectors, bool enc, Error **errp);
@ -911,10 +911,10 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, unsigned int *bytes,
uint64_t *host_offset, QCowL2Meta **m); uint64_t *host_offset, QCowL2Meta **m);
int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset, uint64_t offset,
int compressed_size, int compressed_size,
uint64_t *host_offset); uint64_t *host_offset);
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry, void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
uint64_t *coffset, int *csize); uint64_t *coffset, int *csize);
@ -982,8 +982,8 @@ void qcow2_cache_discard(Qcow2Cache *c, void *table);
int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table, void **refcount_table,
int64_t *refcount_table_size); int64_t *refcount_table_size);
bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
Error **errp); bool *header_updated, Error **errp);
bool qcow2_get_bitmap_info_list(BlockDriverState *bs, bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
Qcow2BitmapInfoList **info_list, Error **errp); Qcow2BitmapInfoList **info_list, Error **errp);
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
@ -991,13 +991,13 @@ int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs,
bool release_stored, Error **errp); bool release_stored, Error **errp);
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
bool qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
const char *name, const char *name,
uint32_t granularity, uint32_t granularity,
Error **errp); Error **errp);
int qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
const char *name, const char *name,
Error **errp); Error **errp);
bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs); bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs);
uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs,
uint32_t cluster_size); uint32_t cluster_size);

View file

@ -100,7 +100,7 @@ static int coroutine_fn qed_write_table(BDRVQEDState *s, uint64_t offset,
} }
if (flush) { if (flush) {
ret = bdrv_flush(s->bs); ret = bdrv_co_flush(s->bs);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }

View file

@ -387,7 +387,7 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
int64_t file_size; int64_t file_size;
int ret; int ret;
ret = bdrv_pread(bs->file, 0, sizeof(le_header), &le_header, 0); ret = bdrv_co_pread(bs->file, 0, sizeof(le_header), &le_header, 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Failed to read QED header"); error_setg(errp, "Failed to read QED header");
return ret; return ret;
@ -492,7 +492,7 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
} }
/* From here on only known autoclear feature bits are valid */ /* From here on only known autoclear feature bits are valid */
bdrv_flush(bs->file->bs); bdrv_co_flush(bs->file->bs);
} }
s->l1_table = qed_alloc_table(s); s->l1_table = qed_alloc_table(s);
@ -561,11 +561,11 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
.errp = errp, .errp = errp,
.ret = -EINPROGRESS .ret = -EINPROGRESS
}; };
int ret;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
bdrv_qed_init_state(bs); bdrv_qed_init_state(bs);
@ -693,7 +693,7 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
* The QED format associates file length with allocation status, * The QED format associates file length with allocation status,
* so a new file (which is empty) must have a length of 0. * so a new file (which is empty) must have a length of 0.
*/ */
ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp); ret = blk_co_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
@ -712,18 +712,18 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
} }
qed_header_cpu_to_le(&header, &le_header); qed_header_cpu_to_le(&header, &le_header);
ret = blk_pwrite(blk, 0, sizeof(le_header), &le_header, 0); ret = blk_co_pwrite(blk, 0, sizeof(le_header), &le_header, 0);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
ret = blk_pwrite(blk, sizeof(le_header), header.backing_filename_size, ret = blk_co_pwrite(blk, sizeof(le_header), header.backing_filename_size,
qed_opts->backing_file, 0); qed_opts->backing_file, 0);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
l1_table = g_malloc0(l1_size); l1_table = g_malloc0(l1_size);
ret = blk_pwrite(blk, header.l1_table_offset, l1_size, l1_table, 0); ret = blk_co_pwrite(blk, header.l1_table_offset, l1_size, l1_table, 0);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }

View file

@ -460,8 +460,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
file_role = BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY; file_role = BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY;
} }
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
file_role, false, errp); file_role, false, errp);
if (!bs->file) { if (!bs->file) {
return -EINVAL; return -EINVAL;
} }

View file

@ -88,11 +88,9 @@ static int replication_open(BlockDriverState *bs, QDict *options,
const char *mode; const char *mode;
const char *top_id; const char *top_id;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp); return ret;
if (!bs->file) {
return -EINVAL;
} }
ret = -EINVAL; ret = -EINVAL;

View file

@ -82,9 +82,9 @@ static void snapshot_access_refresh_filename(BlockDriverState *bs)
static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags, static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp) Error **errp)
{ {
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
false, errp); false, errp);
if (!bs->file) { if (!bs->file) {
return -EINVAL; return -EINVAL;
} }

View file

@ -151,41 +151,29 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
} }
/** /**
* Return a pointer to the child BDS pointer to which we can fall * Return a pointer to child of given BDS to which we can fall
* back if the given BDS does not support snapshots. * back if the given BDS does not support snapshots.
* Return NULL if there is no BDS to (safely) fall back to. * Return NULL if there is no BDS to (safely) fall back to.
*
* We need to return an indirect pointer because bdrv_snapshot_goto()
* has to modify the BdrvChild pointer.
*/ */
static BdrvChild **bdrv_snapshot_fallback_ptr(BlockDriverState *bs) static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs)
{ {
BdrvChild **fallback; BdrvChild *fallback = bdrv_primary_child(bs);
BdrvChild *child; BdrvChild *child;
/* /* We allow fallback only to primary child */
* The only BdrvChild pointers that are safe to modify (and which if (!fallback) {
* we can thus return a reference to) are bs->file and
* bs->backing.
*/
fallback = &bs->file;
if (!*fallback && bs->drv && bs->drv->is_filter) {
fallback = &bs->backing;
}
if (!*fallback) {
return NULL; return NULL;
} }
/* /*
* Check that there are no other children that would need to be * Check that there are no other children that would need to be
* snapshotted. If there are, it is not safe to fall back to * snapshotted. If there are, it is not safe to fall back to
* *fallback. * fallback.
*/ */
QLIST_FOREACH(child, &bs->children, next) { QLIST_FOREACH(child, &bs->children, next) {
if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA |
BDRV_CHILD_FILTERED) && BDRV_CHILD_FILTERED) &&
child != *fallback) child != fallback)
{ {
return NULL; return NULL;
} }
@ -196,8 +184,7 @@ static BdrvChild **bdrv_snapshot_fallback_ptr(BlockDriverState *bs)
static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs) static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs)
{ {
BdrvChild **child_ptr = bdrv_snapshot_fallback_ptr(bs); return child_bs(bdrv_snapshot_fallback_child(bs));
return child_ptr ? (*child_ptr)->bs : NULL;
} }
int bdrv_can_snapshot(BlockDriverState *bs) int bdrv_can_snapshot(BlockDriverState *bs)
@ -244,7 +231,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
Error **errp) Error **errp)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BdrvChild **fallback_ptr; BdrvChild *fallback;
int ret, open_ret; int ret, open_ret;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
@ -267,13 +254,13 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
return ret; return ret;
} }
fallback_ptr = bdrv_snapshot_fallback_ptr(bs); fallback = bdrv_snapshot_fallback_child(bs);
if (fallback_ptr) { if (fallback) {
QDict *options; QDict *options;
QDict *file_options; QDict *file_options;
Error *local_err = NULL; Error *local_err = NULL;
BlockDriverState *fallback_bs = (*fallback_ptr)->bs; BlockDriverState *fallback_bs = fallback->bs;
char *subqdict_prefix = g_strdup_printf("%s.", (*fallback_ptr)->name); char *subqdict_prefix = g_strdup_printf("%s.", fallback->name);
options = qdict_clone_shallow(bs->options); options = qdict_clone_shallow(bs->options);
@ -284,8 +271,8 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
qobject_unref(file_options); qobject_unref(file_options);
g_free(subqdict_prefix); g_free(subqdict_prefix);
/* Force .bdrv_open() below to re-attach fallback_bs on *fallback_ptr */ /* Force .bdrv_open() below to re-attach fallback_bs on fallback */
qdict_put_str(options, (*fallback_ptr)->name, qdict_put_str(options, fallback->name,
bdrv_get_node_name(fallback_bs)); bdrv_get_node_name(fallback_bs));
/* Now close bs, apply the snapshot on fallback_bs, and re-open bs */ /* Now close bs, apply the snapshot on fallback_bs, and re-open bs */
@ -294,8 +281,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
} }
/* .bdrv_open() will re-attach it */ /* .bdrv_open() will re-attach it */
bdrv_unref_child(bs, *fallback_ptr); bdrv_unref_child(bs, fallback);
*fallback_ptr = NULL;
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp); ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err); open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
@ -309,15 +295,12 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
} }
/* /*
* fallback_ptr is &bs->file or &bs->backing. *fallback_ptr * fallback was a primary child. It was closed above and set to NULL,
* was closed above and set to NULL, but the .bdrv_open() call * but the .bdrv_open() call has opened it again, because we set the
* has opened it again, because we set the respective option * respective option (with the qdict_put_str() call above).
* (with the qdict_put_str() call above). * Assert that .bdrv_open() has attached the right BDS as primary child.
* Assert that .bdrv_open() has attached some child on
* *fallback_ptr, and that it has attached the one we wanted
* it to (i.e., fallback_bs).
*/ */
assert(*fallback_ptr && fallback_bs == (*fallback_ptr)->bs); assert(bdrv_primary_bs(bs) == fallback_bs);
bdrv_unref(fallback_bs); bdrv_unref(fallback_bs);
return ret; return ret;
} }

View file

@ -1129,9 +1129,9 @@ static coroutine_fn int ssh_co_readv(BlockDriverState *bs,
return ret; return ret;
} }
static int ssh_write(BDRVSSHState *s, BlockDriverState *bs, static coroutine_fn int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
int64_t offset, size_t size, int64_t offset, size_t size,
QEMUIOVector *qiov) QEMUIOVector *qiov)
{ {
ssize_t r; ssize_t r;
size_t written; size_t written;

View file

@ -78,11 +78,9 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
char *group; char *group;
int ret; int ret;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, if (ret < 0) {
false, errp); return ret;
if (!bs->file) {
return -EINVAL;
} }
bs->supported_write_flags = bs->file->bs->supported_write_flags | bs->supported_write_flags = bs->file->bs->supported_write_flags |
BDRV_REQ_WRITE_UNCHANGED; BDRV_REQ_WRITE_UNCHANGED;

View file

@ -377,10 +377,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
QemuUUID uuid_link, uuid_parent; QemuUUID uuid_link, uuid_parent;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
logout("\n"); logout("\n");
@ -664,7 +663,8 @@ vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
* so this full-cluster write does not overlap a partial write * so this full-cluster write does not overlap a partial write
* of the same cluster, issued from the "else" branch. * of the same cluster, issued from the "else" branch.
*/ */
ret = bdrv_pwrite(bs->file, data_offset, s->block_size, block, 0); ret = bdrv_co_pwrite(bs->file, data_offset, s->block_size, block,
0);
qemu_co_rwlock_unlock(&s->bmap_lock); qemu_co_rwlock_unlock(&s->bmap_lock);
} else { } else {
nonallocating_write: nonallocating_write:
@ -709,7 +709,7 @@ nonallocating_write:
assert(VDI_IS_ALLOCATED(bmap_first)); assert(VDI_IS_ALLOCATED(bmap_first));
*header = s->header; *header = s->header;
vdi_header_to_le(header); vdi_header_to_le(header);
ret = bdrv_pwrite(bs->file, 0, sizeof(*header), header, 0); ret = bdrv_co_pwrite(bs->file, 0, sizeof(*header), header, 0);
g_free(header); g_free(header);
if (ret < 0) { if (ret < 0) {
@ -726,8 +726,8 @@ nonallocating_write:
base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE; base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
logout("will write %u block map sectors starting from entry %u\n", logout("will write %u block map sectors starting from entry %u\n",
n_sectors, bmap_first); n_sectors, bmap_first);
ret = bdrv_pwrite(bs->file, offset * SECTOR_SIZE, ret = bdrv_co_pwrite(bs->file, offset * SECTOR_SIZE,
n_sectors * SECTOR_SIZE, base, 0); n_sectors * SECTOR_SIZE, base, 0);
} }
return ret; return ret;
@ -845,7 +845,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
vdi_header_print(&header); vdi_header_print(&header);
} }
vdi_header_to_le(&header); vdi_header_to_le(&header);
ret = blk_pwrite(blk, offset, sizeof(header), &header, 0); ret = blk_co_pwrite(blk, offset, sizeof(header), &header, 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Error writing header"); error_setg(errp, "Error writing header");
goto exit; goto exit;
@ -866,7 +866,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
bmap[i] = VDI_UNALLOCATED; bmap[i] = VDI_UNALLOCATED;
} }
} }
ret = blk_pwrite(blk, offset, bmap_size, bmap, 0); ret = blk_co_pwrite(blk, offset, bmap_size, bmap, 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Error writing bmap"); error_setg(errp, "Error writing bmap");
goto exit; goto exit;
@ -875,8 +875,8 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
} }
if (image_type == VDI_TYPE_STATIC) { if (image_type == VDI_TYPE_STATIC) {
ret = blk_truncate(blk, offset + blocks * block_size, false, ret = blk_co_truncate(blk, offset + blocks * block_size, false,
PREALLOC_MODE_OFF, 0, errp); PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
error_prepend(errp, "Failed to statically allocate file"); error_prepend(errp, "Failed to statically allocate file");
goto exit; goto exit;

View file

@ -1001,10 +1001,9 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
uint64_t signature; uint64_t signature;
Error *local_err = NULL; Error *local_err = NULL;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
s->bat = NULL; s->bat = NULL;
@ -2011,15 +2010,15 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL, creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL,
&creator_items, NULL); &creator_items, NULL);
signature = cpu_to_le64(VHDX_FILE_SIGNATURE); signature = cpu_to_le64(VHDX_FILE_SIGNATURE);
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET, sizeof(signature), &signature, ret = blk_co_pwrite(blk, VHDX_FILE_ID_OFFSET, sizeof(signature), &signature,
0); 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to write file signature"); error_setg_errno(errp, -ret, "Failed to write file signature");
goto delete_and_exit; goto delete_and_exit;
} }
if (creator) { if (creator) {
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature), ret = blk_co_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature),
creator_items * sizeof(gunichar2), creator, 0); creator_items * sizeof(gunichar2), creator, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to write creator field"); error_setg_errno(errp, -ret, "Failed to write creator field");
goto delete_and_exit; goto delete_and_exit;

View file

@ -1308,10 +1308,9 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
uint32_t magic; uint32_t magic;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
buf = vmdk_read_desc(bs->file, 0, errp); buf = vmdk_read_desc(bs->file, 0, errp);
@ -1404,13 +1403,13 @@ static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp)
* [@skip_start_sector, @skip_end_sector) is not copied or written, and leave * [@skip_start_sector, @skip_end_sector) is not copied or written, and leave
* it for call to write user data in the request. * it for call to write user data in the request.
*/ */
static int get_whole_cluster(BlockDriverState *bs, static int coroutine_fn get_whole_cluster(BlockDriverState *bs,
VmdkExtent *extent, VmdkExtent *extent,
uint64_t cluster_offset, uint64_t cluster_offset,
uint64_t offset, uint64_t offset,
uint64_t skip_start_bytes, uint64_t skip_start_bytes,
uint64_t skip_end_bytes, uint64_t skip_end_bytes,
bool zeroed) bool zeroed)
{ {
int ret = VMDK_OK; int ret = VMDK_OK;
int64_t cluster_bytes; int64_t cluster_bytes;
@ -1441,16 +1440,16 @@ static int get_whole_cluster(BlockDriverState *bs,
if (copy_from_backing) { if (copy_from_backing) {
/* qcow2 emits this on bs->file instead of bs->backing */ /* qcow2 emits this on bs->file instead of bs->backing */
BLKDBG_EVENT(extent->file, BLKDBG_COW_READ); BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
ret = bdrv_pread(bs->backing, offset, skip_start_bytes, ret = bdrv_co_pread(bs->backing, offset, skip_start_bytes,
whole_grain, 0); whole_grain, 0);
if (ret < 0) { if (ret < 0) {
ret = VMDK_ERROR; ret = VMDK_ERROR;
goto exit; goto exit;
} }
} }
BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE); BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
ret = bdrv_pwrite(extent->file, cluster_offset, skip_start_bytes, ret = bdrv_co_pwrite(extent->file, cluster_offset, skip_start_bytes,
whole_grain, 0); whole_grain, 0);
if (ret < 0) { if (ret < 0) {
ret = VMDK_ERROR; ret = VMDK_ERROR;
goto exit; goto exit;
@ -1461,18 +1460,18 @@ static int get_whole_cluster(BlockDriverState *bs,
if (copy_from_backing) { if (copy_from_backing) {
/* qcow2 emits this on bs->file instead of bs->backing */ /* qcow2 emits this on bs->file instead of bs->backing */
BLKDBG_EVENT(extent->file, BLKDBG_COW_READ); BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
ret = bdrv_pread(bs->backing, offset + skip_end_bytes, ret = bdrv_co_pread(bs->backing, offset + skip_end_bytes,
cluster_bytes - skip_end_bytes, cluster_bytes - skip_end_bytes,
whole_grain + skip_end_bytes, 0); whole_grain + skip_end_bytes, 0);
if (ret < 0) { if (ret < 0) {
ret = VMDK_ERROR; ret = VMDK_ERROR;
goto exit; goto exit;
} }
} }
BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE); BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
ret = bdrv_pwrite(extent->file, cluster_offset + skip_end_bytes, ret = bdrv_co_pwrite(extent->file, cluster_offset + skip_end_bytes,
cluster_bytes - skip_end_bytes, cluster_bytes - skip_end_bytes,
whole_grain + skip_end_bytes, 0); whole_grain + skip_end_bytes, 0);
if (ret < 0) { if (ret < 0) {
ret = VMDK_ERROR; ret = VMDK_ERROR;
goto exit; goto exit;
@ -1485,29 +1484,29 @@ exit:
return ret; return ret;
} }
static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, static int coroutine_fn vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
uint32_t offset) uint32_t offset)
{ {
offset = cpu_to_le32(offset); offset = cpu_to_le32(offset);
/* update L2 table */ /* update L2 table */
BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE); BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE);
if (bdrv_pwrite(extent->file, if (bdrv_co_pwrite(extent->file,
((int64_t)m_data->l2_offset * 512) ((int64_t)m_data->l2_offset * 512)
+ (m_data->l2_index * sizeof(offset)), + (m_data->l2_index * sizeof(offset)),
sizeof(offset), &offset, 0) < 0) { sizeof(offset), &offset, 0) < 0) {
return VMDK_ERROR; return VMDK_ERROR;
} }
/* update backup L2 table */ /* update backup L2 table */
if (extent->l1_backup_table_offset != 0) { if (extent->l1_backup_table_offset != 0) {
m_data->l2_offset = extent->l1_backup_table[m_data->l1_index]; m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
if (bdrv_pwrite(extent->file, if (bdrv_co_pwrite(extent->file,
((int64_t)m_data->l2_offset * 512) ((int64_t)m_data->l2_offset * 512)
+ (m_data->l2_index * sizeof(offset)), + (m_data->l2_index * sizeof(offset)),
sizeof(offset), &offset, 0) < 0) { sizeof(offset), &offset, 0) < 0) {
return VMDK_ERROR; return VMDK_ERROR;
} }
} }
if (bdrv_flush(extent->file->bs) < 0) { if (bdrv_co_flush(extent->file->bs) < 0) {
return VMDK_ERROR; return VMDK_ERROR;
} }
if (m_data->l2_cache_entry) { if (m_data->l2_cache_entry) {
@ -1537,14 +1536,14 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
* VMDK_UNALLOC if cluster is not mapped and @allocate is false. * VMDK_UNALLOC if cluster is not mapped and @allocate is false.
* VMDK_ERROR if failed. * VMDK_ERROR if failed.
*/ */
static int get_cluster_offset(BlockDriverState *bs, static int coroutine_fn get_cluster_offset(BlockDriverState *bs,
VmdkExtent *extent, VmdkExtent *extent,
VmdkMetaData *m_data, VmdkMetaData *m_data,
uint64_t offset, uint64_t offset,
bool allocate, bool allocate,
uint64_t *cluster_offset, uint64_t *cluster_offset,
uint64_t skip_start_bytes, uint64_t skip_start_bytes,
uint64_t skip_end_bytes) uint64_t skip_end_bytes)
{ {
unsigned int l1_index, l2_offset, l2_index; unsigned int l1_index, l2_offset, l2_index;
int min_index, i, j; int min_index, i, j;
@ -1624,11 +1623,10 @@ static int get_cluster_offset(BlockDriverState *bs,
} }
l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes); l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes);
BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD); BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
if (bdrv_pread(extent->file, if (bdrv_co_pread(extent->file,
(int64_t)l2_offset * 512, (int64_t)l2_offset * 512,
l2_size_bytes, l2_size_bytes,
l2_table, l2_table, 0
0
) < 0) { ) < 0) {
return VMDK_ERROR; return VMDK_ERROR;
} }
@ -1899,7 +1897,8 @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
cluster_buf = g_malloc(buf_bytes); cluster_buf = g_malloc(buf_bytes);
uncomp_buf = g_malloc(cluster_bytes); uncomp_buf = g_malloc(cluster_bytes);
BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED); BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_pread(extent->file, cluster_offset, buf_bytes, cluster_buf, 0); ret = bdrv_co_pread(extent->file, cluster_offset, buf_bytes, cluster_buf,
0);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
@ -2144,8 +2143,8 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
return length; return length;
} }
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE); length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
ret = bdrv_truncate(s->extents[i].file, length, false, ret = bdrv_co_truncate(s->extents[i].file, length, false,
PREALLOC_MODE_OFF, 0, NULL); PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -2586,7 +2585,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
desc_offset = 0x200; desc_offset = 0x200;
} }
ret = blk_pwrite(blk, desc_offset, desc_len, desc, 0); ret = blk_co_pwrite(blk, desc_offset, desc_len, desc, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write description"); error_setg_errno(errp, -ret, "Could not write description");
goto exit; goto exit;
@ -2594,7 +2593,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
/* bdrv_pwrite write padding zeros to align to sector, we don't need that /* bdrv_pwrite write padding zeros to align to sector, we don't need that
* for description file */ * for description file */
if (desc_offset == 0) { if (desc_offset == 0) {
ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp); ret = blk_co_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }

View file

@ -233,10 +233,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
int64_t bs_size; int64_t bs_size;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
BDRV_CHILD_IMAGE, false, errp); if (ret < 0) {
if (!bs->file) { return ret;
return -EINVAL;
} }
opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort); opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);

View file

@ -499,7 +499,7 @@ static bool valid_filename(const unsigned char *name)
(c >= 'A' && c <= 'Z') || (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') || (c >= 'a' && c <= 'z') ||
c > 127 || c > 127 ||
strchr("$%'-_@~`!(){}^#&.+,;=[]", c) != NULL)) strchr(" $%'-_@~`!(){}^#&.+,;=[]", c) != NULL))
{ {
return false; return false;
} }
@ -2993,11 +2993,35 @@ DLOG(checkpoint());
vvfat_close_current_file(s); vvfat_close_current_file(s);
if (sector_num == s->offset_to_bootsector && nb_sectors == 1) {
/*
* Write on bootsector. Allow only changing the reserved1 field,
* used to mark volume dirtiness
*/
unsigned char *bootsector = s->first_sectors
+ s->offset_to_bootsector * 0x200;
/*
* LATER TODO: if FAT32, this is wrong (see init_directories(),
* which always creates a FAT16 bootsector)
*/
const int reserved1_offset = offsetof(bootsector_t, u.fat16.reserved1);
for (i = 0; i < 0x200; i++) {
if (i != reserved1_offset && bootsector[i] != buf[i]) {
fprintf(stderr, "Tried to write to protected bootsector\n");
return -1;
}
}
/* Update bootsector with the only updatable byte, and return success */
bootsector[reserved1_offset] = buf[reserved1_offset];
return 0;
}
/* /*
* Some sanity checks: * Some sanity checks:
* - do not allow writing to the boot sector * - do not allow writing to the boot sector
*/ */
if (sector_num < s->offset_to_fat) if (sector_num < s->offset_to_fat)
return -1; return -1;
@ -3146,10 +3170,9 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
array_init(&(s->commits), sizeof(commit_t)); array_init(&(s->commits), sizeof(commit_t));
s->qcow_filename = g_malloc(PATH_MAX); s->qcow_filename = create_tmp_file(errp);
ret = get_tmp_filename(s->qcow_filename, PATH_MAX); if (!s->qcow_filename) {
if (ret < 0) { ret = -ENOENT;
error_setg_errno(errp, -ret, "can't create temporary file");
goto err; goto err;
} }

View file

@ -1630,8 +1630,8 @@ static void external_snapshot_abort(BlkActionState *common)
aio_context_release(aio_context); aio_context_release(aio_context);
aio_context_acquire(tmp_context); aio_context_acquire(tmp_context);
ret = bdrv_try_set_aio_context(state->old_bs, ret = bdrv_try_change_aio_context(state->old_bs,
aio_context, NULL); aio_context, NULL, NULL);
assert(ret == 0); assert(ret == 0);
aio_context_release(tmp_context); aio_context_release(tmp_context);
@ -1792,12 +1792,12 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
goto out; goto out;
} }
/* Honor bdrv_try_set_aio_context() context acquisition requirements. */ /* Honor bdrv_try_change_aio_context() context acquisition requirements. */
old_context = bdrv_get_aio_context(target_bs); old_context = bdrv_get_aio_context(target_bs);
aio_context_release(aio_context); aio_context_release(aio_context);
aio_context_acquire(old_context); aio_context_acquire(old_context);
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp);
if (ret < 0) { if (ret < 0) {
bdrv_unref(target_bs); bdrv_unref(target_bs);
aio_context_release(old_context); aio_context_release(old_context);
@ -1892,12 +1892,12 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
return; return;
} }
/* Honor bdrv_try_set_aio_context() context acquisition requirements. */ /* Honor bdrv_try_change_aio_context() context acquisition requirements. */
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
old_context = bdrv_get_aio_context(target_bs); old_context = bdrv_get_aio_context(target_bs);
aio_context_acquire(old_context); aio_context_acquire(old_context);
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp);
if (ret < 0) { if (ret < 0) {
aio_context_release(old_context); aio_context_release(old_context);
return; return;
@ -2448,7 +2448,7 @@ void coroutine_fn qmp_block_resize(bool has_device, const char *device,
bdrv_co_unlock(bs); bdrv_co_unlock(bs);
old_ctx = bdrv_co_enter(bs); old_ctx = bdrv_co_enter(bs);
blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); blk_co_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
bdrv_co_leave(bs, old_ctx); bdrv_co_leave(bs, old_ctx);
bdrv_co_lock(bs); bdrv_co_lock(bs);
@ -3194,12 +3194,12 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
!bdrv_has_zero_init(target_bs))); !bdrv_has_zero_init(target_bs)));
/* Honor bdrv_try_set_aio_context() context acquisition requirements. */ /* Honor bdrv_try_change_aio_context() context acquisition requirements. */
old_context = bdrv_get_aio_context(target_bs); old_context = bdrv_get_aio_context(target_bs);
aio_context_release(aio_context); aio_context_release(aio_context);
aio_context_acquire(old_context); aio_context_acquire(old_context);
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp);
if (ret < 0) { if (ret < 0) {
bdrv_unref(target_bs); bdrv_unref(target_bs);
aio_context_release(old_context); aio_context_release(old_context);
@ -3266,12 +3266,12 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
zero_target = (sync == MIRROR_SYNC_MODE_FULL); zero_target = (sync == MIRROR_SYNC_MODE_FULL);
/* Honor bdrv_try_set_aio_context() context acquisition requirements. */ /* Honor bdrv_try_change_aio_context() context acquisition requirements. */
old_context = bdrv_get_aio_context(target_bs); old_context = bdrv_get_aio_context(target_bs);
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(old_context); aio_context_acquire(old_context);
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp);
aio_context_release(old_context); aio_context_release(old_context);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
@ -3767,7 +3767,7 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
old_context = bdrv_get_aio_context(bs); old_context = bdrv_get_aio_context(bs);
aio_context_acquire(old_context); aio_context_acquire(old_context);
bdrv_try_set_aio_context(bs, new_context, errp); bdrv_try_change_aio_context(bs, new_context, NULL, errp);
aio_context_release(old_context); aio_context_release(old_context);
} }

View file

@ -126,39 +126,50 @@ static void child_job_drained_end(BdrvChild *c, int *drained_end_counter)
job_resume(&job->job); job_resume(&job->job);
} }
static bool child_job_can_set_aio_ctx(BdrvChild *c, AioContext *ctx, typedef struct BdrvStateChildJobContext {
GSList **ignore, Error **errp) AioContext *new_ctx;
BlockJob *job;
} BdrvStateChildJobContext;
static void child_job_set_aio_ctx_commit(void *opaque)
{
BdrvStateChildJobContext *s = opaque;
BlockJob *job = s->job;
job_set_aio_context(&job->job, s->new_ctx);
}
static TransactionActionDrv change_child_job_context = {
.commit = child_job_set_aio_ctx_commit,
.clean = g_free,
};
static bool child_job_change_aio_ctx(BdrvChild *c, AioContext *ctx,
GHashTable *visited, Transaction *tran,
Error **errp)
{ {
BlockJob *job = c->opaque; BlockJob *job = c->opaque;
BdrvStateChildJobContext *s;
GSList *l; GSList *l;
for (l = job->nodes; l; l = l->next) { for (l = job->nodes; l; l = l->next) {
BdrvChild *sibling = l->data; BdrvChild *sibling = l->data;
if (!bdrv_child_can_set_aio_context(sibling, ctx, ignore, errp)) { if (!bdrv_child_change_aio_context(sibling, ctx, visited,
tran, errp)) {
return false; return false;
} }
} }
s = g_new(BdrvStateChildJobContext, 1);
*s = (BdrvStateChildJobContext) {
.new_ctx = ctx,
.job = job,
};
tran_add(tran, &change_child_job_context, s);
return true; return true;
} }
static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
GSList **ignore)
{
BlockJob *job = c->opaque;
GSList *l;
for (l = job->nodes; l; l = l->next) {
BdrvChild *sibling = l->data;
if (g_slist_find(*ignore, sibling)) {
continue;
}
*ignore = g_slist_prepend(*ignore, sibling);
bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore);
}
job_set_aio_context(&job->job, ctx);
}
static AioContext *child_job_get_parent_aio_context(BdrvChild *c) static AioContext *child_job_get_parent_aio_context(BdrvChild *c)
{ {
BlockJob *job = c->opaque; BlockJob *job = c->opaque;
@ -172,8 +183,7 @@ static const BdrvChildClass child_job = {
.drained_begin = child_job_drained_begin, .drained_begin = child_job_drained_begin,
.drained_poll = child_job_drained_poll, .drained_poll = child_job_drained_poll,
.drained_end = child_job_drained_end, .drained_end = child_job_drained_end,
.can_set_aio_ctx = child_job_can_set_aio_ctx, .change_aio_ctx = child_job_change_aio_ctx,
.set_aio_ctx = child_job_set_aio_ctx,
.stay_at_node = true, .stay_at_node = true,
.get_parent_aio_context = child_job_get_parent_aio_context, .get_parent_aio_context = child_job_get_parent_aio_context,
}; };

View file

@ -109,7 +109,7 @@ The AioContext originates from the QEMU block layer, even though nowadays
AioContext is a generic event loop that can be used by any QEMU subsystem. AioContext is a generic event loop that can be used by any QEMU subsystem.
The block layer has support for AioContext integrated. Each BlockDriverState The block layer has support for AioContext integrated. Each BlockDriverState
is associated with an AioContext using bdrv_try_set_aio_context() and is associated with an AioContext using bdrv_try_change_aio_context() and
bdrv_get_aio_context(). This allows block layer code to process I/O inside the bdrv_get_aio_context(). This allows block layer code to process I/O inside the
right AioContext. Other subsystems may wish to follow a similar approach. right AioContext. Other subsystems may wish to follow a similar approach.
@ -134,5 +134,5 @@ Long-running jobs (usually in the form of coroutines) are best scheduled in
the BlockDriverState's AioContext to avoid the need to acquire/release around the BlockDriverState's AioContext to avoid the need to acquire/release around
each bdrv_*() call. The functions bdrv_add/remove_aio_context_notifier, each bdrv_*() call. The functions bdrv_add/remove_aio_context_notifier,
or alternatively blk_add/remove_aio_context_notifier if you use BlockBackends, or alternatively blk_add/remove_aio_context_notifier if you use BlockBackends,
can be used to get a notification whenever bdrv_try_set_aio_context() moves a can be used to get a notification whenever bdrv_try_change_aio_context() moves a
BlockDriverState to a different AioContext. BlockDriverState to a different AioContext.

View file

@ -97,6 +97,10 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
VHostUserBlk *s = VHOST_USER_BLK(dev->vdev); VHostUserBlk *s = VHOST_USER_BLK(dev->vdev);
Error *local_err = NULL; Error *local_err = NULL;
if (!dev->started) {
return 0;
}
ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg, ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg,
vdev->config_len, &local_err); vdev->config_len, &local_err);
if (ret < 0) { if (ret < 0) {

View file

@ -322,6 +322,45 @@ enum {
* *
* At least one of DATA, METADATA, FILTERED, or COW must be set for * At least one of DATA, METADATA, FILTERED, or COW must be set for
* every child. * every child.
*
*
* = Connection with bs->children, bs->file and bs->backing fields =
*
* 1. Filters
*
* Filter drivers have drv->is_filter = true.
*
* Filter node has exactly one FILTERED|PRIMARY child, and may have other
* children which must not have these bits (one example is the
* copy-before-write filter, which also has its target DATA child).
*
* Filter nodes never have COW children.
*
* For most filters, the filtered child is linked in bs->file, bs->backing is
* NULL. For some filters (as an exception), it is the other way around; those
* drivers will have drv->filtered_child_is_backing set to true (see that
* fields documentation for what drivers this concerns)
*
* 2. "raw" driver (block/raw-format.c)
*
* Formally it's not a filter (drv->is_filter = false)
*
* bs->backing is always NULL
*
* Only has one child, linked in bs->file. Its role is either FILTERED|PRIMARY
* (like filter) or DATA|PRIMARY depending on options.
*
* 3. Other drivers
*
* Don't have any FILTERED children.
*
* May have at most one COW child. In this case it's linked in bs->backing.
* Otherwise bs->backing is NULL. COW child is never PRIMARY.
*
* May have at most one PRIMARY child. In this case it's linked in bs->file.
* Otherwise bs->file is NULL.
*
* May also have some other children that don't have the PRIMARY or COW bit set.
*/ */
enum BdrvChildRoleBits { enum BdrvChildRoleBits {
/* /*

View file

@ -76,6 +76,9 @@ BdrvChild *bdrv_open_child(const char *filename,
const BdrvChildClass *child_class, const BdrvChildClass *child_class,
BdrvChildRole child_role, BdrvChildRole child_role,
bool allow_none, Error **errp); bool allow_none, Error **errp);
int bdrv_open_file_child(const char *filename,
QDict *options, const char *bdref_key,
BlockDriverState *parent, Error **errp);
BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
Error **errp); Error **errp);
@ -217,17 +220,12 @@ void coroutine_fn bdrv_co_lock(BlockDriverState *bs);
*/ */
void coroutine_fn bdrv_co_unlock(BlockDriverState *bs); void coroutine_fn bdrv_co_unlock(BlockDriverState *bs);
void bdrv_set_aio_context_ignore(BlockDriverState *bs,
AioContext *new_context, GSList **ignore);
int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
Error **errp);
int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
BdrvChild *ignore_child, Error **errp);
bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
GSList **ignore, Error **errp);
bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
GSList **ignore, Error **errp);
AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c); AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c);
bool bdrv_child_change_aio_context(BdrvChild *c, AioContext *ctx,
GHashTable *visited, Transaction *tran,
Error **errp);
int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx,
BdrvChild *ignore_child, Error **errp);
int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);

View file

@ -38,7 +38,7 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict); void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
void hmp_block_resize(Monitor *mon, const QDict *qdict); void coroutine_fn hmp_block_resize(Monitor *mon, const QDict *qdict);
void hmp_block_stream(Monitor *mon, const QDict *qdict); void hmp_block_stream(Monitor *mon, const QDict *qdict);
void hmp_block_passwd(Monitor *mon, const QDict *qdict); void hmp_block_passwd(Monitor *mon, const QDict *qdict);
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict); void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);

View file

@ -83,12 +83,13 @@ void bdrv_aio_cancel(BlockAIOCB *acb);
void bdrv_aio_cancel_async(BlockAIOCB *acb); void bdrv_aio_cancel_async(BlockAIOCB *acb);
/* sg packet commands */ /* sg packet commands */
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
/* Ensure contents are flushed to disk. */ /* Ensure contents are flushed to disk. */
int coroutine_fn bdrv_co_flush(BlockDriverState *bs); int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
int64_t bytes);
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
int bdrv_block_status(BlockDriverState *bs, int64_t offset, int bdrv_block_status(BlockDriverState *bs, int64_t offset,
int64_t bytes, int64_t *pnum, int64_t *map, int64_t bytes, int64_t *pnum, int64_t *map,

View file

@ -119,6 +119,20 @@ struct BlockDriver {
* (And this filtered child must then be bs->file or bs->backing.) * (And this filtered child must then be bs->file or bs->backing.)
*/ */
bool is_filter; bool is_filter;
/*
* Only make sense for filter drivers, for others must be false.
* If true, filtered child is bs->backing. Otherwise it's bs->file.
* Two internal filters use bs->backing as filtered child and has this
* field set to true: mirror_top and commit_top. There also two such test
* filters in tests/unit/test-bdrv-graph-mod.c.
*
* Never create any more such filters!
*
* TODO: imagine how to deprecate this behavior and make all filters work
* similarly using bs->file as filtered child.
*/
bool filtered_child_is_backing;
/* /*
* Set to true if the BlockDriver is a format driver. Format nodes * Set to true if the BlockDriver is a format driver. Format nodes
* generally do not expect their children to be other format nodes * generally do not expect their children to be other format nodes
@ -734,13 +748,11 @@ struct BlockDriver {
void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs); void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs);
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
bool (*bdrv_co_can_store_new_dirty_bitmap)(BlockDriverState *bs, bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)(
const char *name, BlockDriverState *bs, const char *name, uint32_t granularity,
uint32_t granularity, Error **errp);
Error **errp); int coroutine_fn (*bdrv_co_remove_persistent_dirty_bitmap)(
int (*bdrv_co_remove_persistent_dirty_bitmap)(BlockDriverState *bs, BlockDriverState *bs, const char *name, Error **errp);
const char *name,
Error **errp);
}; };
static inline bool block_driver_can_compress(BlockDriver *drv) static inline bool block_driver_can_compress(BlockDriver *drv)
@ -895,9 +907,9 @@ struct BdrvChildClass {
int (*update_filename)(BdrvChild *child, BlockDriverState *new_base, int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
const char *filename, Error **errp); const char *filename, Error **errp);
bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx, bool (*change_aio_ctx)(BdrvChild *child, AioContext *ctx,
GSList **ignore, Error **errp); GHashTable *visited, Transaction *tran,
void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); Error **errp);
AioContext *(*get_parent_aio_context)(BdrvChild *child); AioContext *(*get_parent_aio_context)(BdrvChild *child);
@ -1045,9 +1057,6 @@ struct BlockDriverState {
QDict *full_open_options; QDict *full_open_options;
char exact_filename[PATH_MAX]; char exact_filename[PATH_MAX];
BdrvChild *backing;
BdrvChild *file;
/* I/O Limits */ /* I/O Limits */
BlockLimits bl; BlockLimits bl;
@ -1106,7 +1115,19 @@ struct BlockDriverState {
* parent node of this node. * parent node of this node.
*/ */
BlockDriverState *inherits_from; BlockDriverState *inherits_from;
/*
* @backing and @file are some of @children or NULL. All these three fields
* (@file, @backing and @children) are modified only in
* bdrv_child_cb_attach() and bdrv_child_cb_detach().
*
* See also comment in include/block/block.h, to learn how backing and file
* are connected with BdrvChildRole.
*/
QLIST_HEAD(, BdrvChild) children; QLIST_HEAD(, BdrvChild) children;
BdrvChild *backing;
BdrvChild *file;
QLIST_HEAD(, BdrvChild) parents; QLIST_HEAD(, BdrvChild) parents;
QDict *options; QDict *options;
@ -1233,7 +1254,7 @@ static inline BlockDriverState *child_bs(BdrvChild *child)
} }
int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp); int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp);
int get_tmp_filename(char *filename, int size); char *create_tmp_file(Error **errp);
void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix, void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
QDict *options); QDict *options);

View file

@ -15,6 +15,7 @@
#define HMP_H #define HMP_H
#include "qemu/readline.h" #include "qemu/readline.h"
#include "qemu/coroutine.h"
#include "qapi/qapi-types-common.h" #include "qapi/qapi-types-common.h"
bool hmp_handle_error(Monitor *mon, Error *err); bool hmp_handle_error(Monitor *mon, Error *err);
@ -81,7 +82,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict);
void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_getfd(Monitor *mon, const QDict *qdict);
void hmp_closefd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict);
void hmp_sendkey(Monitor *mon, const QDict *qdict); void hmp_sendkey(Monitor *mon, const QDict *qdict);
void hmp_screendump(Monitor *mon, const QDict *qdict); void coroutine_fn hmp_screendump(Monitor *mon, const QDict *qdict);
void hmp_chardev_add(Monitor *mon, const QDict *qdict); void hmp_chardev_add(Monitor *mon, const QDict *qdict);
void hmp_chardev_change(Monitor *mon, const QDict *qdict); void hmp_chardev_change(Monitor *mon, const QDict *qdict);
void hmp_chardev_remove(Monitor *mon, const QDict *qdict); void hmp_chardev_remove(Monitor *mon, const QDict *qdict);

View file

@ -287,7 +287,7 @@ void qemu_co_rwlock_init(CoRwlock *lock);
* of a parallel writer, control is transferred to the caller of the current * of a parallel writer, control is transferred to the caller of the current
* coroutine. * coroutine.
*/ */
void qemu_co_rwlock_rdlock(CoRwlock *lock); void coroutine_fn qemu_co_rwlock_rdlock(CoRwlock *lock);
/** /**
* Write Locks the CoRwlock from a reader. This is a bit more efficient than * Write Locks the CoRwlock from a reader. This is a bit more efficient than
@ -296,7 +296,7 @@ void qemu_co_rwlock_rdlock(CoRwlock *lock);
* to the caller of the current coroutine; another writer might run while * to the caller of the current coroutine; another writer might run while
* @qemu_co_rwlock_upgrade blocks. * @qemu_co_rwlock_upgrade blocks.
*/ */
void qemu_co_rwlock_upgrade(CoRwlock *lock); void coroutine_fn qemu_co_rwlock_upgrade(CoRwlock *lock);
/** /**
* Downgrades a write-side critical section to a reader. Downgrading with * Downgrades a write-side critical section to a reader. Downgrading with
@ -304,20 +304,20 @@ void qemu_co_rwlock_upgrade(CoRwlock *lock);
* followed by @qemu_co_rwlock_rdlock. This makes it more efficient, but * followed by @qemu_co_rwlock_rdlock. This makes it more efficient, but
* may also sometimes be necessary for correctness. * may also sometimes be necessary for correctness.
*/ */
void qemu_co_rwlock_downgrade(CoRwlock *lock); void coroutine_fn qemu_co_rwlock_downgrade(CoRwlock *lock);
/** /**
* Write Locks the mutex. If the lock cannot be taken immediately because * Write Locks the mutex. If the lock cannot be taken immediately because
* of a parallel reader, control is transferred to the caller of the current * of a parallel reader, control is transferred to the caller of the current
* coroutine. * coroutine.
*/ */
void qemu_co_rwlock_wrlock(CoRwlock *lock); void coroutine_fn qemu_co_rwlock_wrlock(CoRwlock *lock);
/** /**
* Unlocks the read/write lock and schedules the next coroutine that was * Unlocks the read/write lock and schedules the next coroutine that was
* waiting for this lock to be run. * waiting for this lock to be run.
*/ */
void qemu_co_rwlock_unlock(CoRwlock *lock); void coroutine_fn qemu_co_rwlock_unlock(CoRwlock *lock);
typedef struct QemuCoSleep { typedef struct QemuCoSleep {
Coroutine *to_wake; Coroutine *to_wake;
@ -389,8 +389,9 @@ void qemu_coroutine_dec_pool_size(unsigned int additional_pool_size);
* The same interface as qemu_sendv_recvv(), with added yielding. * The same interface as qemu_sendv_recvv(), with added yielding.
* XXX should mark these as coroutine_fn * XXX should mark these as coroutine_fn
*/ */
ssize_t qemu_co_sendv_recvv(int sockfd, struct iovec *iov, unsigned iov_cnt, ssize_t coroutine_fn qemu_co_sendv_recvv(int sockfd, struct iovec *iov,
size_t offset, size_t bytes, bool do_send); unsigned iov_cnt, size_t offset,
size_t bytes, bool do_send);
#define qemu_co_recvv(sockfd, iov, iov_cnt, offset, bytes) \ #define qemu_co_recvv(sockfd, iov, iov_cnt, offset, bytes) \
qemu_co_sendv_recvv(sockfd, iov, iov_cnt, offset, bytes, false) qemu_co_sendv_recvv(sockfd, iov, iov_cnt, offset, bytes, false)
#define qemu_co_sendv(sockfd, iov, iov_cnt, offset, bytes) \ #define qemu_co_sendv(sockfd, iov, iov_cnt, offset, bytes) \
@ -399,7 +400,8 @@ ssize_t qemu_co_sendv_recvv(int sockfd, struct iovec *iov, unsigned iov_cnt,
/** /**
* The same as above, but with just a single buffer * The same as above, but with just a single buffer
*/ */
ssize_t qemu_co_send_recv(int sockfd, void *buf, size_t bytes, bool do_send); ssize_t coroutine_fn qemu_co_send_recv(int sockfd, void *buf, size_t bytes,
bool do_send);
#define qemu_co_recv(sockfd, buf, bytes) \ #define qemu_co_recv(sockfd, buf, bytes) \
qemu_co_send_recv(sockfd, buf, bytes, false) qemu_co_send_recv(sockfd, buf, bytes, false)
#define qemu_co_send(sockfd, buf, bytes) \ #define qemu_co_send(sockfd, buf, bytes) \

2
job.c
View file

@ -588,7 +588,7 @@ static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns)
next_aio_context = job->aio_context; next_aio_context = job->aio_context;
/* /*
* Coroutine has resumed, but in the meanwhile the job AioContext * Coroutine has resumed, but in the meanwhile the job AioContext
* might have changed via bdrv_try_set_aio_context(), so we need to move * might have changed via bdrv_try_change_aio_context(), so we need to move
* the coroutine too in the new aiocontext. * the coroutine too in the new aiocontext.
*/ */
while (qemu_get_current_aio_context() != next_aio_context) { while (qemu_get_current_aio_context() != next_aio_context) {

View file

@ -1853,7 +1853,6 @@ config_host_data.set('CONFIG_LIBNFS', libnfs.found())
config_host_data.set('CONFIG_LIBSSH', libssh.found()) config_host_data.set('CONFIG_LIBSSH', libssh.found())
config_host_data.set('CONFIG_LINUX_AIO', libaio.found()) config_host_data.set('CONFIG_LINUX_AIO', libaio.found())
config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found()) config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found())
config_host_data.set('CONFIG_LIBURING_REGISTER_RING_FD', cc.has_function('io_uring_register_ring_fd', prefix: '#include <liburing.h>', dependencies:linux_io_uring))
config_host_data.set('CONFIG_LIBPMEM', libpmem.found()) config_host_data.set('CONFIG_LIBPMEM', libpmem.found())
config_host_data.set('CONFIG_NUMA', numa.found()) config_host_data.set('CONFIG_NUMA', numa.found())
config_host_data.set('CONFIG_OPENGL', opengl.found()) config_host_data.set('CONFIG_OPENGL', opengl.found())

View file

@ -375,7 +375,8 @@ if [ "${VALGRIND_QEMU_VM}" == "y" ]; then
_casenotrun "Valgrind needs a valid TMPDIR for itself" _casenotrun "Valgrind needs a valid TMPDIR for itself"
fi fi
VALGRIND_QEMU_VM= \ VALGRIND_QEMU_VM= \
TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on |
sed -e "s#'[^']*/vl\.[A-Za-z0-9]\{6\}'#SNAPSHOT_PATH#g"
# Using snapshot=on together with read-only=on # Using snapshot=on together with read-only=on
echo "info block" | echo "info block" |

View file

@ -459,7 +459,7 @@ wrote 4096/4096 bytes at offset 0
read 4096/4096 bytes at offset 0 read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive driver=null-co,snapshot=on Testing: -drive driver=null-co,snapshot=on
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory QEMU_PROG: -drive driver=null-co,snapshot=on: Could not open temporary file SNAPSHOT_PATH: No such file or directory
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0 Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information QEMU X.Y.Z monitor - type 'help' for more information

View file

@ -539,7 +539,7 @@ wrote 4096/4096 bytes at offset 0
read 4096/4096 bytes at offset 0 read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive driver=null-co,snapshot=on Testing: -drive driver=null-co,snapshot=on
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory QEMU_PROG: -drive driver=null-co,snapshot=on: Could not open temporary file SNAPSHOT_PATH: No such file or directory
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0 Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information QEMU X.Y.Z monitor - type 'help' for more information

View file

@ -1538,16 +1538,16 @@ static void test_set_aio_context(void)
&error_abort); &error_abort);
bdrv_drained_begin(bs); bdrv_drained_begin(bs);
bdrv_try_set_aio_context(bs, ctx_a, &error_abort); bdrv_try_change_aio_context(bs, ctx_a, NULL, &error_abort);
aio_context_acquire(ctx_a); aio_context_acquire(ctx_a);
bdrv_drained_end(bs); bdrv_drained_end(bs);
bdrv_drained_begin(bs); bdrv_drained_begin(bs);
bdrv_try_set_aio_context(bs, ctx_b, &error_abort); bdrv_try_change_aio_context(bs, ctx_b, NULL, &error_abort);
aio_context_release(ctx_a); aio_context_release(ctx_a);
aio_context_acquire(ctx_b); aio_context_acquire(ctx_b);
bdrv_try_set_aio_context(bs, qemu_get_aio_context(), &error_abort); bdrv_try_change_aio_context(bs, qemu_get_aio_context(), NULL, &error_abort);
aio_context_release(ctx_b); aio_context_release(ctx_b);
bdrv_drained_end(bs); bdrv_drained_end(bs);
@ -1830,9 +1830,8 @@ static void test_drop_intermediate_poll(void)
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (i) { if (i) {
/* Takes the reference to chain[i - 1] */ /* Takes the reference to chain[i - 1] */
chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1], bdrv_attach_child(chain[i], chain[i - 1], "chain",
"chain", &chain_child_class, &chain_child_class, BDRV_CHILD_COW, &error_abort);
BDRV_CHILD_COW, &error_abort);
} }
} }
@ -1970,6 +1969,7 @@ static void coroutine_fn bdrv_replace_test_co_drain_end(BlockDriverState *bs)
static BlockDriver bdrv_replace_test = { static BlockDriver bdrv_replace_test = {
.format_name = "replace_test", .format_name = "replace_test",
.instance_size = sizeof(BDRVReplaceTestState), .instance_size = sizeof(BDRVReplaceTestState),
.supports_backing = true,
.bdrv_close = bdrv_replace_test_close, .bdrv_close = bdrv_replace_test_close,
.bdrv_co_preadv = bdrv_replace_test_co_preadv, .bdrv_co_preadv = bdrv_replace_test_co_preadv,
@ -2049,9 +2049,8 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
new_child_bs->total_sectors = 1; new_child_bs->total_sectors = 1;
bdrv_ref(old_child_bs); bdrv_ref(old_child_bs);
parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child", bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
&child_of_bds, BDRV_CHILD_COW, BDRV_CHILD_COW, &error_abort);
&error_abort);
for (i = 0; i < old_drain_count; i++) { for (i = 0; i < old_drain_count; i++) {
bdrv_drained_begin(old_child_bs); bdrv_drained_begin(old_child_bs);

View file

@ -26,6 +26,8 @@
static BlockDriver bdrv_pass_through = { static BlockDriver bdrv_pass_through = {
.format_name = "pass-through", .format_name = "pass-through",
.is_filter = true,
.filtered_child_is_backing = true,
.bdrv_child_perm = bdrv_default_perms, .bdrv_child_perm = bdrv_default_perms,
}; };
@ -57,6 +59,8 @@ static void exclusive_write_perms(BlockDriverState *bs, BdrvChild *c,
static BlockDriver bdrv_exclusive_writer = { static BlockDriver bdrv_exclusive_writer = {
.format_name = "exclusive-writer", .format_name = "exclusive-writer",
.is_filter = true,
.filtered_child_is_backing = true,
.bdrv_child_perm = exclusive_write_perms, .bdrv_child_perm = exclusive_write_perms,
}; };
@ -134,7 +138,7 @@ static void test_update_perm_tree(void)
blk_insert_bs(root, bs, &error_abort); blk_insert_bs(root, bs, &error_abort);
bdrv_attach_child(filter, bs, "child", &child_of_bds, bdrv_attach_child(filter, bs, "child", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); BDRV_CHILD_DATA, &error_abort);
ret = bdrv_append(filter, bs, NULL); ret = bdrv_append(filter, bs, NULL);
g_assert_cmpint(ret, <, 0); g_assert_cmpint(ret, <, 0);
@ -228,11 +232,14 @@ static void test_parallel_exclusive_write(void)
*/ */
bdrv_ref(base); bdrv_ref(base);
bdrv_attach_child(top, fl1, "backing", &child_of_bds, BDRV_CHILD_DATA, bdrv_attach_child(top, fl1, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort); &error_abort);
bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, bdrv_attach_child(fl1, base, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort); &error_abort);
bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, bdrv_attach_child(fl2, base, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort); &error_abort);
bdrv_replace_node(fl1, fl2, &error_abort); bdrv_replace_node(fl1, fl2, &error_abort);
@ -241,13 +248,26 @@ static void test_parallel_exclusive_write(void)
bdrv_unref(top); bdrv_unref(top);
} }
static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c, /*
BdrvChildRole role, * write-to-selected node may have several DATA children, one of them may be
BlockReopenQueue *reopen_queue, * "selected". Exclusive write permission is taken on selected child.
uint64_t perm, uint64_t shared, *
uint64_t *nperm, uint64_t *nshared) * We don't realize write handler itself, as we need only to test how permission
* update works.
*/
typedef struct BDRVWriteToSelectedState {
BdrvChild *selected;
} BDRVWriteToSelectedState;
static void write_to_selected_perms(BlockDriverState *bs, BdrvChild *c,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{ {
if (bs->file && c == bs->file) { BDRVWriteToSelectedState *s = bs->opaque;
if (s->selected && c == s->selected) {
*nperm = BLK_PERM_WRITE; *nperm = BLK_PERM_WRITE;
*nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE; *nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE;
} else { } else {
@ -256,9 +276,10 @@ static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c,
} }
} }
static BlockDriver bdrv_write_to_file = { static BlockDriver bdrv_write_to_selected = {
.format_name = "tricky-perm", .format_name = "write-to-selected",
.bdrv_child_perm = write_to_file_perms, .instance_size = sizeof(BDRVWriteToSelectedState),
.bdrv_child_perm = write_to_selected_perms,
}; };
@ -266,15 +287,18 @@ static BlockDriver bdrv_write_to_file = {
* The following test shows that topological-sort order is required for * The following test shows that topological-sort order is required for
* permission update, simple DFS is not enough. * permission update, simple DFS is not enough.
* *
* Consider the block driver which has two filter children: one active * Consider the block driver (write-to-selected) which has two children: one is
* with exclusive write access and one inactive with no specific * selected so we have exclusive write access to it and for the other one we
* permissions. * don't need any specific permissions.
* *
* And, these two children has a common base child, like this: * And, these two children has a common base child, like this:
* (additional "top" on top is used in test just because the only public
* function to update permission should get a specific child to update.
* Making bdrv_refresh_perms() public just for this test isn't worth it)
* *
* *
* fl2 top * fl2 write-to-selected top
* *
* *
* w * w
* *
@ -290,14 +314,14 @@ static BlockDriver bdrv_write_to_file = {
* *
* So, exclusive write is propagated. * So, exclusive write is propagated.
* *
* Assume, we want to make fl2 active instead of fl1. * Assume, we want to select fl2 instead of fl1.
* So, we set some option for top driver and do permission update. * So, we set some option for write-to-selected driver and do permission update.
* *
* With simple DFS, if permission update goes first through * With simple DFS, if permission update goes first through
* top->fl1->base branch it will succeed: it firstly drop exclusive write * write-to-selected -> fl1 -> base branch it will succeed: it firstly drop
* permissions and than apply them for another BdrvChildren. * exclusive write permissions and than apply them for another BdrvChildren.
* But if permission update goes first through top->fl2->base branch it * But if permission update goes first through write-to-selected -> fl2 -> base
* will fail, as when we try to update fl2->base child, old not yet * branch it will fail, as when we try to update fl2->base child, old not yet
* updated fl1->base child will be in conflict. * updated fl1->base child will be in conflict.
* *
* With topological-sort order we always update parents before children, so fl1 * With topological-sort order we always update parents before children, so fl1
@ -306,9 +330,10 @@ static BlockDriver bdrv_write_to_file = {
static void test_parallel_perm_update(void) static void test_parallel_perm_update(void)
{ {
BlockDriverState *top = no_perm_node("top"); BlockDriverState *top = no_perm_node("top");
BlockDriverState *tricky = BlockDriverState *ws =
bdrv_new_open_driver(&bdrv_write_to_file, "tricky", BDRV_O_RDWR, bdrv_new_open_driver(&bdrv_write_to_selected, "ws", BDRV_O_RDWR,
&error_abort); &error_abort);
BDRVWriteToSelectedState *s = ws->opaque;
BlockDriverState *base = no_perm_node("base"); BlockDriverState *base = no_perm_node("base");
BlockDriverState *fl1 = pass_through_node("fl1"); BlockDriverState *fl1 = pass_through_node("fl1");
BlockDriverState *fl2 = pass_through_node("fl2"); BlockDriverState *fl2 = pass_through_node("fl2");
@ -320,33 +345,35 @@ static void test_parallel_perm_update(void)
*/ */
bdrv_ref(base); bdrv_ref(base);
bdrv_attach_child(top, tricky, "file", &child_of_bds, BDRV_CHILD_DATA, bdrv_attach_child(top, ws, "file", &child_of_bds, BDRV_CHILD_DATA,
&error_abort); &error_abort);
c_fl1 = bdrv_attach_child(tricky, fl1, "first", &child_of_bds, c_fl1 = bdrv_attach_child(ws, fl1, "first", &child_of_bds,
BDRV_CHILD_FILTERED, &error_abort); BDRV_CHILD_DATA, &error_abort);
c_fl2 = bdrv_attach_child(tricky, fl2, "second", &child_of_bds, c_fl2 = bdrv_attach_child(ws, fl2, "second", &child_of_bds,
BDRV_CHILD_FILTERED, &error_abort); BDRV_CHILD_DATA, &error_abort);
bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, bdrv_attach_child(fl1, base, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort); &error_abort);
bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, bdrv_attach_child(fl2, base, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort); &error_abort);
/* Select fl1 as first child to be active */ /* Select fl1 as first child to be active */
tricky->file = c_fl1; s->selected = c_fl1;
bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
assert(c_fl1->perm & BLK_PERM_WRITE); assert(c_fl1->perm & BLK_PERM_WRITE);
assert(!(c_fl2->perm & BLK_PERM_WRITE)); assert(!(c_fl2->perm & BLK_PERM_WRITE));
/* Now, try to switch active child and update permissions */ /* Now, try to switch active child and update permissions */
tricky->file = c_fl2; s->selected = c_fl2;
bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
assert(c_fl2->perm & BLK_PERM_WRITE); assert(c_fl2->perm & BLK_PERM_WRITE);
assert(!(c_fl1->perm & BLK_PERM_WRITE)); assert(!(c_fl1->perm & BLK_PERM_WRITE));
/* Switch once more, to not care about real child order in the list */ /* Switch once more, to not care about real child order in the list */
tricky->file = c_fl1; s->selected = c_fl1;
bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
assert(c_fl1->perm & BLK_PERM_WRITE); assert(c_fl1->perm & BLK_PERM_WRITE);
@ -379,7 +406,8 @@ static void test_append_greedy_filter(void)
BlockDriverState *base = no_perm_node("base"); BlockDriverState *base = no_perm_node("base");
BlockDriverState *fl = exclusive_writer_node("fl1"); BlockDriverState *fl = exclusive_writer_node("fl1");
bdrv_attach_child(top, base, "backing", &child_of_bds, BDRV_CHILD_COW, bdrv_attach_child(top, base, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort); &error_abort);
bdrv_append(fl, base, &error_abort); bdrv_append(fl, base, &error_abort);

View file

@ -765,7 +765,7 @@ static void test_propagate_mirror(void)
filter = bdrv_find_node("filter_node"); filter = bdrv_find_node("filter_node");
/* Change the AioContext of src */ /* Change the AioContext of src */
bdrv_try_set_aio_context(src, ctx, &error_abort); bdrv_try_change_aio_context(src, ctx, NULL, &error_abort);
g_assert(bdrv_get_aio_context(src) == ctx); g_assert(bdrv_get_aio_context(src) == ctx);
g_assert(bdrv_get_aio_context(target) == ctx); g_assert(bdrv_get_aio_context(target) == ctx);
g_assert(bdrv_get_aio_context(filter) == ctx); g_assert(bdrv_get_aio_context(filter) == ctx);
@ -773,7 +773,7 @@ static void test_propagate_mirror(void)
/* Change the AioContext of target */ /* Change the AioContext of target */
aio_context_acquire(ctx); aio_context_acquire(ctx);
bdrv_try_set_aio_context(target, main_ctx, &error_abort); bdrv_try_change_aio_context(target, main_ctx, NULL, &error_abort);
aio_context_release(ctx); aio_context_release(ctx);
g_assert(bdrv_get_aio_context(src) == main_ctx); g_assert(bdrv_get_aio_context(src) == main_ctx);
g_assert(bdrv_get_aio_context(target) == main_ctx); g_assert(bdrv_get_aio_context(target) == main_ctx);
@ -783,7 +783,7 @@ static void test_propagate_mirror(void)
blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
blk_insert_bs(blk, src, &error_abort); blk_insert_bs(blk, src, &error_abort);
bdrv_try_set_aio_context(target, ctx, &local_err); bdrv_try_change_aio_context(target, ctx, NULL, &local_err);
error_free_or_abort(&local_err); error_free_or_abort(&local_err);
g_assert(blk_get_aio_context(blk) == main_ctx); g_assert(blk_get_aio_context(blk) == main_ctx);
@ -794,7 +794,7 @@ static void test_propagate_mirror(void)
/* ...unless we explicitly allow it */ /* ...unless we explicitly allow it */
aio_context_acquire(ctx); aio_context_acquire(ctx);
blk_set_allow_aio_context_change(blk, true); blk_set_allow_aio_context_change(blk, true);
bdrv_try_set_aio_context(target, ctx, &error_abort); bdrv_try_change_aio_context(target, ctx, NULL, &error_abort);
aio_context_release(ctx); aio_context_release(ctx);
g_assert(blk_get_aio_context(blk) == ctx); g_assert(blk_get_aio_context(blk) == ctx);
@ -806,7 +806,7 @@ static void test_propagate_mirror(void)
aio_context_acquire(ctx); aio_context_acquire(ctx);
blk_set_aio_context(blk, main_ctx, &error_abort); blk_set_aio_context(blk, main_ctx, &error_abort);
bdrv_try_set_aio_context(target, main_ctx, &error_abort); bdrv_try_change_aio_context(target, main_ctx, NULL, &error_abort);
aio_context_release(ctx); aio_context_release(ctx);
blk_unref(blk); blk_unref(blk);