mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-26 21:10:42 +00:00
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:
commit
d5ab9490cd
12
MAINTAINERS
12
MAINTAINERS
@ -2509,6 +2509,8 @@ S: Supported
|
||||
F: block*
|
||||
F: block/
|
||||
F: hw/block/
|
||||
F: qapi/block*.json
|
||||
F: qapi/transaction.json
|
||||
F: include/block/
|
||||
F: include/sysemu/block-*.h
|
||||
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/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
|
||||
M: Ben Widawsky <ben.widawsky@intel.com>
|
||||
M: Jonathan Cameron <jonathan.cameron@huawei.com>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -503,12 +503,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* Open the image file */
|
||||
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
|
||||
bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
ret = -EINVAL;
|
||||
ret = bdrv_open_file_child(qemu_opt_get(opts, "x-image"), options, "image",
|
||||
bs, errp);
|
||||
if (ret < 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -155,11 +155,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* Open the file */
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false,
|
||||
errp);
|
||||
if (!bs->file) {
|
||||
ret = -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -257,10 +254,6 @@ fail_log:
|
||||
s->log_file = NULL;
|
||||
}
|
||||
fail:
|
||||
if (ret < 0) {
|
||||
bdrv_unref_child(bs, bs->file);
|
||||
bs->file = NULL;
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
|
@ -26,11 +26,8 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
|
||||
/* Open the image file */
|
||||
bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
ret = -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "image", bs, errp);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -122,12 +122,9 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* Open the raw file */
|
||||
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw",
|
||||
bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
ret = -EINVAL;
|
||||
ret = bdrv_open_file_child(qemu_opt_get(opts, "x-raw"), options, "raw",
|
||||
bs, errp);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -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_resize(BdrvChild *child);
|
||||
|
||||
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore, Error **errp);
|
||||
static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore);
|
||||
static bool blk_root_change_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GHashTable *visited, Transaction *tran,
|
||||
Error **errp);
|
||||
|
||||
static char *blk_root_get_parent_desc(BdrvChild *child)
|
||||
{
|
||||
@ -334,8 +333,7 @@ static const BdrvChildClass child_root = {
|
||||
.attach = blk_root_attach,
|
||||
.detach = blk_root_detach,
|
||||
|
||||
.can_set_aio_ctx = blk_root_can_set_aio_ctx,
|
||||
.set_aio_ctx = blk_root_set_aio_ctx,
|
||||
.change_aio_ctx = blk_root_change_aio_ctx,
|
||||
|
||||
.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)
|
||||
{
|
||||
GLOBAL_STATE_CODE();
|
||||
IO_CODE();
|
||||
blk->enable_write_cache = wce;
|
||||
}
|
||||
|
||||
@ -2149,8 +2147,11 @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
|
||||
bdrv_ref(bs);
|
||||
|
||||
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) {
|
||||
bdrv_unref(bs);
|
||||
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);
|
||||
}
|
||||
|
||||
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore, Error **errp)
|
||||
typedef struct BdrvStateBlkRootContext {
|
||||
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) {
|
||||
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;
|
||||
blk_do_set_aio_context(blk, s->new_ctx, false, &error_abort);
|
||||
}
|
||||
|
||||
static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore)
|
||||
static TransactionActionDrv set_blk_root_context = {
|
||||
.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;
|
||||
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,
|
||||
|
@ -110,10 +110,9 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0);
|
||||
|
@ -71,10 +71,9 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read header */
|
||||
|
@ -135,7 +135,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
|
||||
}
|
||||
|
||||
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) {
|
||||
return ret;
|
||||
}
|
||||
@ -238,6 +238,7 @@ static BlockDriver bdrv_commit_top = {
|
||||
.bdrv_child_perm = bdrv_commit_top_child_perm,
|
||||
|
||||
.is_filter = true,
|
||||
.filtered_child_is_backing = true,
|
||||
};
|
||||
|
||||
void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
|
@ -412,6 +412,7 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int64_t cluster_size;
|
||||
g_autoptr(BlockdevOptions) full_opts = NULL;
|
||||
BlockdevOptionsCbw *opts;
|
||||
int ret;
|
||||
|
||||
full_opts = cbw_parse_options(options, errp);
|
||||
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);
|
||||
opts = &full_opts->u.copy_before_write;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds,
|
||||
|
@ -41,12 +41,11 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
BDRVStateCOR *state = bs->opaque;
|
||||
/* Find a bottom node name, if any */
|
||||
const char *bottom_node = qdict_get_try_str(options, "bottom");
|
||||
int ret;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bs->supported_read_flags = BDRV_REQ_PREFETCH;
|
||||
|
@ -261,15 +261,14 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
QemuOpts *opts = NULL;
|
||||
int ret = -EINVAL;
|
||||
int ret;
|
||||
QCryptoBlockOpenOptions *open_opts = NULL;
|
||||
unsigned int cflags = 0;
|
||||
QDict *cryptoopts = NULL;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
|
||||
ret = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -285,6 +285,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
|
||||
|
||||
open_opts = block_crypto_open_opts_init(cryptoopts, errp);
|
||||
if (!open_opts) {
|
||||
ret = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -440,10 +440,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
block_module_load_one("dmg-bz2");
|
||||
|
@ -129,7 +129,7 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
|
||||
|
||||
/* Ignore errors with fixed-iothread=false */
|
||||
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) {
|
||||
aio_context_release(ctx);
|
||||
aio_context_acquire(new_ctx);
|
||||
|
@ -30,11 +30,9 @@
|
||||
static int compress_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
int ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
|
||||
|
@ -2744,8 +2744,8 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = bdrv_common_block_status_above(bs, NULL, false, false, offset,
|
||||
bytes, &pnum, NULL, NULL, NULL);
|
||||
ret = bdrv_co_common_block_status_above(bs, NULL, false, false, offset,
|
||||
bytes, &pnum, NULL, NULL, NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, int64_t *pnum)
|
||||
int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
int64_t *pnum)
|
||||
{
|
||||
int ret;
|
||||
int64_t dummy;
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include <liburing.h>
|
||||
#include "block/aio.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "block/block.h"
|
||||
#include "block/raw-aio.h"
|
||||
@ -19,7 +18,6 @@
|
||||
#include "qapi/error.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
/* io_uring ring size */
|
||||
#define MAX_ENTRIES 128
|
||||
|
||||
@ -432,17 +430,8 @@ LuringState *luring_init(Error **errp)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
void luring_cleanup(LuringState *s)
|
||||
|
@ -922,8 +922,8 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
|
||||
* active layer. */
|
||||
if (s->base == blk_bs(s->target)) {
|
||||
if (s->bdev_length > target_length) {
|
||||
ret = blk_truncate(s->target, s->bdev_length, false,
|
||||
PREALLOC_MODE_OFF, 0, NULL);
|
||||
ret = blk_co_truncate(s->target, s->bdev_length, false,
|
||||
PREALLOC_MODE_OFF, 0, NULL);
|
||||
if (ret < 0) {
|
||||
goto immediate_exit;
|
||||
}
|
||||
@ -1589,6 +1589,7 @@ static BlockDriver bdrv_mirror_top = {
|
||||
.bdrv_child_perm = bdrv_mirror_top_child_perm,
|
||||
|
||||
.is_filter = true,
|
||||
.filtered_child_is_backing = true,
|
||||
};
|
||||
|
||||
static BlockJob *mirror_start_job(
|
||||
|
@ -489,7 +489,7 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
|
||||
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");
|
||||
int64_t size = qdict_get_int(qdict, "size");
|
||||
|
@ -418,7 +418,11 @@ static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts,
|
||||
int flags, int open_flags, Error **errp)
|
||||
{
|
||||
int64_t ret = -EINVAL;
|
||||
#ifdef _WIN32
|
||||
struct __stat64 st;
|
||||
#else
|
||||
struct stat st;
|
||||
#endif
|
||||
char *file = NULL, *strp = NULL;
|
||||
|
||||
qemu_mutex_init(&client->mutex);
|
||||
@ -781,7 +785,11 @@ static int nfs_reopen_prepare(BDRVReopenState *state,
|
||||
BlockReopenQueue *queue, Error **errp)
|
||||
{
|
||||
NFSClient *client = state->bs->opaque;
|
||||
#ifdef _WIN32
|
||||
struct __stat64 st;
|
||||
#else
|
||||
struct stat st;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
if (state->flags & BDRV_O_RDWR && bdrv_is_read_only(state->bs)) {
|
||||
|
@ -205,18 +205,18 @@ static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs,
|
||||
* force the safer-but-slower fallocate.
|
||||
*/
|
||||
if (s->prealloc_mode == PRL_PREALLOC_MODE_TRUNCATE) {
|
||||
ret = bdrv_truncate(bs->file,
|
||||
(s->data_end + space) << BDRV_SECTOR_BITS,
|
||||
false, PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE,
|
||||
NULL);
|
||||
ret = bdrv_co_truncate(bs->file,
|
||||
(s->data_end + space) << BDRV_SECTOR_BITS,
|
||||
false, PREALLOC_MODE_OFF,
|
||||
BDRV_REQ_ZERO_WRITE, NULL);
|
||||
if (ret == -ENOTSUP) {
|
||||
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
|
||||
}
|
||||
}
|
||||
if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
|
||||
ret = bdrv_pwrite_zeroes(bs->file,
|
||||
s->data_end << BDRV_SECTOR_BITS,
|
||||
space << BDRV_SECTOR_BITS, 0);
|
||||
ret = bdrv_co_pwrite_zeroes(bs->file,
|
||||
s->data_end << BDRV_SECTOR_BITS,
|
||||
space << BDRV_SECTOR_BITS, 0);
|
||||
}
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -278,8 +278,8 @@ static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
|
||||
if (off + to_write > s->header_size) {
|
||||
to_write = s->header_size - off;
|
||||
}
|
||||
ret = bdrv_pwrite(bs->file, off, to_write, (uint8_t *)s->header + off,
|
||||
0);
|
||||
ret = bdrv_co_pwrite(bs->file, off, to_write,
|
||||
(uint8_t *)s->header + off, 0);
|
||||
if (ret < 0) {
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
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.
|
||||
* That means we have to pass exact=true.
|
||||
*/
|
||||
ret = bdrv_truncate(bs->file, res->image_end_offset, true,
|
||||
PREALLOC_MODE_OFF, 0, &local_err);
|
||||
ret = bdrv_co_truncate(bs->file, res->image_end_offset, true,
|
||||
PREALLOC_MODE_OFF, 0, &local_err);
|
||||
if (ret < 0) {
|
||||
error_report_err(local_err);
|
||||
res->check_errors++;
|
||||
@ -599,12 +599,12 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
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) {
|
||||
goto exit;
|
||||
}
|
||||
ret = blk_pwrite_zeroes(blk, BDRV_SECTOR_SIZE,
|
||||
(bat_sectors - 1) << BDRV_SECTOR_BITS, 0);
|
||||
ret = blk_co_pwrite_zeroes(blk, BDRV_SECTOR_SIZE,
|
||||
(bat_sectors - 1) << BDRV_SECTOR_BITS, 0);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
@ -736,10 +736,9 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error *local_err = NULL;
|
||||
char *buf;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_pread(bs->file, 0, sizeof(ph), &ph, 0);
|
||||
|
@ -134,6 +134,7 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVPreallocateState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) {
|
||||
|
66
block/qcow.c
66
block/qcow.c
@ -92,7 +92,8 @@ typedef struct BDRVQcowState {
|
||||
|
||||
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)
|
||||
{
|
||||
@ -121,10 +122,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
qdict_extract_subqdict(options, &encryptopts, "encrypt.");
|
||||
encryptfmt = qdict_get_try_str(encryptopts, "format");
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
ret = -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
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
|
||||
* errno on failure.
|
||||
*/
|
||||
static int get_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset, int allocate,
|
||||
int compressed_size,
|
||||
int n_start, int n_end, uint64_t *result)
|
||||
static int coroutine_fn get_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset, int allocate,
|
||||
int compressed_size,
|
||||
int n_start, int n_end,
|
||||
uint64_t *result)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
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;
|
||||
tmp = cpu_to_be64(l2_offset);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
||||
ret = bdrv_pwrite_sync(bs->file,
|
||||
s->l1_table_offset + l1_index * sizeof(tmp),
|
||||
sizeof(tmp), &tmp, 0);
|
||||
ret = bdrv_co_pwrite_sync(bs->file,
|
||||
s->l1_table_offset + l1_index * sizeof(tmp),
|
||||
sizeof(tmp), &tmp, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -414,14 +414,14 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
|
||||
if (new_l2_table) {
|
||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
||||
ret = bdrv_pwrite_sync(bs->file, l2_offset,
|
||||
s->l2_size * sizeof(uint64_t), l2_table, 0);
|
||||
ret = bdrv_co_pwrite_sync(bs->file, l2_offset,
|
||||
s->l2_size * sizeof(uint64_t), l2_table, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = bdrv_pread(bs->file, l2_offset, s->l2_size * sizeof(uint64_t),
|
||||
l2_table, 0);
|
||||
ret = bdrv_co_pread(bs->file, l2_offset,
|
||||
s->l2_size * sizeof(uint64_t), l2_table, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -453,8 +453,8 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
|
||||
/* write the cluster content */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_size,
|
||||
s->cluster_cache, 0);
|
||||
ret = bdrv_co_pwrite(bs->file, cluster_offset, s->cluster_size,
|
||||
s->cluster_cache, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -469,8 +469,9 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
if (cluster_offset + s->cluster_size > INT64_MAX) {
|
||||
return -E2BIG;
|
||||
}
|
||||
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
|
||||
false, PREALLOC_MODE_OFF, 0, NULL);
|
||||
ret = bdrv_co_truncate(bs->file,
|
||||
cluster_offset + s->cluster_size,
|
||||
false, PREALLOC_MODE_OFF, 0, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -492,9 +493,9 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
return -EIO;
|
||||
}
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
ret = bdrv_pwrite(bs->file, cluster_offset + i,
|
||||
BDRV_SECTOR_SIZE,
|
||||
s->cluster_data, 0);
|
||||
ret = bdrv_co_pwrite(bs->file, cluster_offset + i,
|
||||
BDRV_SECTOR_SIZE,
|
||||
s->cluster_data, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -514,8 +515,8 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
} else {
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
|
||||
}
|
||||
ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
|
||||
sizeof(tmp), &tmp, 0);
|
||||
ret = bdrv_co_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
|
||||
sizeof(tmp), &tmp, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -585,7 +586,8 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
|
||||
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;
|
||||
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 &= (s->cluster_size - 1);
|
||||
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)
|
||||
return -1;
|
||||
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 */
|
||||
ret = blk_pwrite(qcow_blk, 0, sizeof(header), &header, 0);
|
||||
ret = blk_co_pwrite(qcow_blk, 0, sizeof(header), &header, 0);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (qcow_opts->has_backing_file) {
|
||||
ret = blk_pwrite(qcow_blk, sizeof(header), backing_filename_len,
|
||||
qcow_opts->backing_file, 0);
|
||||
ret = blk_co_pwrite(qcow_blk, sizeof(header), backing_filename_len,
|
||||
qcow_opts->backing_file, 0);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
@ -904,8 +906,8 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
|
||||
tmp = g_malloc0(BDRV_SECTOR_SIZE);
|
||||
for (i = 0; i < DIV_ROUND_UP(sizeof(uint64_t) * l1_size, BDRV_SECTOR_SIZE);
|
||||
i++) {
|
||||
ret = blk_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i,
|
||||
BDRV_SECTOR_SIZE, tmp, 0);
|
||||
ret = blk_co_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i,
|
||||
BDRV_SECTOR_SIZE, tmp, 0);
|
||||
if (ret < 0) {
|
||||
g_free(tmp);
|
||||
goto exit;
|
||||
|
@ -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
|
||||
* the return value.
|
||||
*/
|
||||
bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated,
|
||||
Error **errp)
|
||||
bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
|
||||
bool *header_updated, Error **errp)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
Qcow2BitmapList *bm_list;
|
||||
|
@ -31,7 +31,8 @@
|
||||
#include "qemu/memalign.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;
|
||||
int new_l1_size, i, ret;
|
||||
@ -47,14 +48,14 @@ int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size)
|
||||
#endif
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE);
|
||||
ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset +
|
||||
new_l1_size * L1E_SIZE,
|
||||
(s->l1_size - new_l1_size) * L1E_SIZE, 0);
|
||||
ret = bdrv_co_pwrite_zeroes(bs->file,
|
||||
s->l1_table_offset + new_l1_size * L1E_SIZE,
|
||||
(s->l1_size - new_l1_size) * L1E_SIZE, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = bdrv_flush(bs->file->bs);
|
||||
ret = bdrv_co_flush(bs->file->bs);
|
||||
if (ret < 0) {
|
||||
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
|
||||
*/
|
||||
int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int compressed_size,
|
||||
uint64_t *host_offset)
|
||||
int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int compressed_size,
|
||||
uint64_t *host_offset)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int l2_index, ret;
|
||||
@ -1488,8 +1489,9 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,
|
||||
*
|
||||
* -errno: in error cases
|
||||
*/
|
||||
static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
|
||||
uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
|
||||
static int coroutine_fn handle_copied(BlockDriverState *bs,
|
||||
uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes,
|
||||
QCowL2Meta **m)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int l2_index;
|
||||
@ -1653,8 +1655,9 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||
*
|
||||
* -errno: in error cases
|
||||
*/
|
||||
static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
|
||||
uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
|
||||
static int coroutine_fn handle_alloc(BlockDriverState *bs,
|
||||
uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes,
|
||||
QCowL2Meta **m)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int l2_index;
|
||||
|
@ -97,7 +97,7 @@ static void update_max_refcount_table_index(BDRVQcow2State *s)
|
||||
s->max_refcount_table_index = i;
|
||||
}
|
||||
|
||||
int qcow2_refcount_init(BlockDriverState *bs)
|
||||
int coroutine_fn qcow2_refcount_init(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
unsigned int refcount_table_size2, i;
|
||||
@ -118,8 +118,8 @@ int qcow2_refcount_init(BlockDriverState *bs)
|
||||
goto fail;
|
||||
}
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
|
||||
ret = bdrv_pread(bs->file, s->refcount_table_offset,
|
||||
refcount_table_size2, s->refcount_table, 0);
|
||||
ret = bdrv_co_pread(bs->file, s->refcount_table_offset,
|
||||
refcount_table_size2, s->refcount_table, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@ -3559,8 +3559,8 @@ static int64_t get_refblock_offset(BlockDriverState *bs, uint64_t offset)
|
||||
return covering_refblock_offset;
|
||||
}
|
||||
|
||||
static int qcow2_discard_refcount_block(BlockDriverState *bs,
|
||||
uint64_t discard_block_offs)
|
||||
static int coroutine_fn
|
||||
qcow2_discard_refcount_block(BlockDriverState *bs, uint64_t discard_block_offs)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int64_t refblock_offs;
|
||||
@ -3616,7 +3616,7 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qcow2_shrink_reftable(BlockDriverState *bs)
|
||||
int coroutine_fn qcow2_shrink_reftable(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
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]);
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset,
|
||||
s->refcount_table_size * REFTABLE_ENTRY_SIZE,
|
||||
reftable_tmp, 0);
|
||||
ret = bdrv_co_pwrite_sync(bs->file, s->refcount_table_offset,
|
||||
s->refcount_table_size * REFTABLE_ENTRY_SIZE,
|
||||
reftable_tmp, 0);
|
||||
/*
|
||||
* 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
|
||||
|
@ -441,9 +441,9 @@ int coroutine_fn qcow2_check_read_snapshot_table(BlockDriverState *bs,
|
||||
} QEMU_PACKED snapshot_table_pointer;
|
||||
|
||||
/* qcow2_do_open() discards this information in check mode */
|
||||
ret = bdrv_pread(bs->file, offsetof(QCowHeader, nb_snapshots),
|
||||
sizeof(snapshot_table_pointer), &snapshot_table_pointer,
|
||||
0);
|
||||
ret = bdrv_co_pread(bs->file, offsetof(QCowHeader, nb_snapshots),
|
||||
sizeof(snapshot_table_pointer), &snapshot_table_pointer,
|
||||
0);
|
||||
if (ret < 0) {
|
||||
result->check_errors++;
|
||||
fprintf(stderr, "ERROR failed to read the snapshot table pointer from "
|
||||
|
@ -1306,7 +1306,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||
uint64_t l1_vm_state_index;
|
||||
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) {
|
||||
error_setg_errno(errp, -ret, "Could not read qcow2 header");
|
||||
goto fail;
|
||||
@ -1382,9 +1382,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||
if (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);
|
||||
ret = bdrv_pread(bs->file, sizeof(header),
|
||||
s->unknown_header_fields_size,
|
||||
s->unknown_header_fields, 0);
|
||||
ret = bdrv_co_pread(bs->file, sizeof(header),
|
||||
s->unknown_header_fields_size,
|
||||
s->unknown_header_fields, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not read unknown qcow2 header "
|
||||
"fields");
|
||||
@ -1579,8 +1579,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_size * L1E_SIZE,
|
||||
s->l1_table, 0);
|
||||
ret = bdrv_co_pread(bs->file, s->l1_table_offset, s->l1_size * L1E_SIZE,
|
||||
s->l1_table, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not read L1 table");
|
||||
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);
|
||||
ret = bdrv_pread(bs->file, header.backing_file_offset, len,
|
||||
s->image_backing_file, 0);
|
||||
ret = bdrv_co_pread(bs->file, header.backing_file_offset, len,
|
||||
s->image_backing_file, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not read backing file name");
|
||||
goto fail;
|
||||
@ -1905,11 +1905,11 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
.errp = errp,
|
||||
.ret = -EINPROGRESS
|
||||
};
|
||||
int ret;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialise locks */
|
||||
@ -3679,7 +3679,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
|
||||
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);
|
||||
if (ret < 0) {
|
||||
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 */
|
||||
refcount_table = g_malloc0(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);
|
||||
|
||||
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 */
|
||||
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
|
||||
0, errp);
|
||||
ret = blk_co_truncate(blk, qcow2_opts->size, false,
|
||||
qcow2_opts->preallocation, 0, errp);
|
||||
if (ret < 0) {
|
||||
error_prepend(errp, "Could not resize image: ");
|
||||
goto out;
|
||||
@ -5287,8 +5287,8 @@ static int64_t qcow2_check_vmstate_request(BlockDriverState *bs,
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
int64_t pos)
|
||||
static coroutine_fn int qcow2_save_vmstate(BlockDriverState *bs,
|
||||
QEMUIOVector *qiov, int64_t pos)
|
||||
{
|
||||
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos);
|
||||
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);
|
||||
}
|
||||
|
||||
static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
int64_t pos)
|
||||
static coroutine_fn int qcow2_load_vmstate(BlockDriverState *bs,
|
||||
QEMUIOVector *qiov, int64_t pos)
|
||||
{
|
||||
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos);
|
||||
if (offset < 0) {
|
||||
|
@ -846,7 +846,7 @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
|
||||
Error **errp);
|
||||
|
||||
/* qcow2-refcount.c functions */
|
||||
int qcow2_refcount_init(BlockDriverState *bs);
|
||||
int coroutine_fn qcow2_refcount_init(BlockDriverState *bs);
|
||||
void qcow2_refcount_close(BlockDriverState *bs);
|
||||
|
||||
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,
|
||||
BlockDriverAmendStatusCB *status_cb,
|
||||
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);
|
||||
int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs);
|
||||
|
||||
/* qcow2-cluster.c functions */
|
||||
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_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_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
|
||||
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,
|
||||
unsigned int *bytes,
|
||||
uint64_t *host_offset, QCowL2Meta **m);
|
||||
int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int compressed_size,
|
||||
uint64_t *host_offset);
|
||||
int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int compressed_size,
|
||||
uint64_t *host_offset);
|
||||
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
|
||||
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,
|
||||
void **refcount_table,
|
||||
int64_t *refcount_table_size);
|
||||
bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated,
|
||||
Error **errp);
|
||||
bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
|
||||
bool *header_updated, Error **errp);
|
||||
bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
|
||||
Qcow2BitmapInfoList **info_list, 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 release_stored, Error **errp);
|
||||
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
|
||||
bool qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
|
||||
const char *name,
|
||||
uint32_t granularity,
|
||||
Error **errp);
|
||||
int qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
|
||||
const char *name,
|
||||
Error **errp);
|
||||
bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
|
||||
const char *name,
|
||||
uint32_t granularity,
|
||||
Error **errp);
|
||||
int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
|
||||
const char *name,
|
||||
Error **errp);
|
||||
bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs);
|
||||
uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs,
|
||||
uint32_t cluster_size);
|
||||
|
@ -100,7 +100,7 @@ static int coroutine_fn qed_write_table(BDRVQEDState *s, uint64_t offset,
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
ret = bdrv_flush(s->bs);
|
||||
ret = bdrv_co_flush(s->bs);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
20
block/qed.c
20
block/qed.c
@ -387,7 +387,7 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
|
||||
int64_t file_size;
|
||||
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) {
|
||||
error_setg(errp, "Failed to read QED header");
|
||||
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 */
|
||||
bdrv_flush(bs->file->bs);
|
||||
bdrv_co_flush(bs->file->bs);
|
||||
}
|
||||
|
||||
s->l1_table = qed_alloc_table(s);
|
||||
@ -561,11 +561,11 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
.errp = errp,
|
||||
.ret = -EINPROGRESS
|
||||
};
|
||||
int ret;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
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,
|
||||
* 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) {
|
||||
goto out;
|
||||
}
|
||||
@ -712,18 +712,18 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
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) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -460,8 +460,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
file_role = BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY;
|
||||
}
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
file_role, false, errp);
|
||||
bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
file_role, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -88,11 +88,9 @@ static int replication_open(BlockDriverState *bs, QDict *options,
|
||||
const char *mode;
|
||||
const char *top_id;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
|
@ -82,9 +82,9 @@ static void snapshot_access_refresh_filename(BlockDriverState *bs)
|
||||
static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -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.
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* The only BdrvChild pointers that are safe to modify (and which
|
||||
* 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) {
|
||||
/* We allow fallback only to primary child */
|
||||
if (!fallback) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that there are no other children that would need to be
|
||||
* snapshotted. If there are, it is not safe to fall back to
|
||||
* *fallback.
|
||||
* fallback.
|
||||
*/
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA |
|
||||
BDRV_CHILD_FILTERED) &&
|
||||
child != *fallback)
|
||||
child != fallback)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -196,8 +184,7 @@ static BdrvChild **bdrv_snapshot_fallback_ptr(BlockDriverState *bs)
|
||||
|
||||
static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild **child_ptr = bdrv_snapshot_fallback_ptr(bs);
|
||||
return child_ptr ? (*child_ptr)->bs : NULL;
|
||||
return child_bs(bdrv_snapshot_fallback_child(bs));
|
||||
}
|
||||
|
||||
int bdrv_can_snapshot(BlockDriverState *bs)
|
||||
@ -244,7 +231,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
BdrvChild **fallback_ptr;
|
||||
BdrvChild *fallback;
|
||||
int ret, open_ret;
|
||||
|
||||
GLOBAL_STATE_CODE();
|
||||
@ -267,13 +254,13 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
fallback_ptr = bdrv_snapshot_fallback_ptr(bs);
|
||||
if (fallback_ptr) {
|
||||
fallback = bdrv_snapshot_fallback_child(bs);
|
||||
if (fallback) {
|
||||
QDict *options;
|
||||
QDict *file_options;
|
||||
Error *local_err = NULL;
|
||||
BlockDriverState *fallback_bs = (*fallback_ptr)->bs;
|
||||
char *subqdict_prefix = g_strdup_printf("%s.", (*fallback_ptr)->name);
|
||||
BlockDriverState *fallback_bs = fallback->bs;
|
||||
char *subqdict_prefix = g_strdup_printf("%s.", fallback->name);
|
||||
|
||||
options = qdict_clone_shallow(bs->options);
|
||||
|
||||
@ -284,8 +271,8 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
qobject_unref(file_options);
|
||||
g_free(subqdict_prefix);
|
||||
|
||||
/* Force .bdrv_open() below to re-attach fallback_bs on *fallback_ptr */
|
||||
qdict_put_str(options, (*fallback_ptr)->name,
|
||||
/* Force .bdrv_open() below to re-attach fallback_bs on fallback */
|
||||
qdict_put_str(options, fallback->name,
|
||||
bdrv_get_node_name(fallback_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_unref_child(bs, *fallback_ptr);
|
||||
*fallback_ptr = NULL;
|
||||
bdrv_unref_child(bs, fallback);
|
||||
|
||||
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
|
||||
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
|
||||
* was closed above and set to NULL, but the .bdrv_open() call
|
||||
* has opened it again, because we set the respective option
|
||||
* (with the qdict_put_str() call above).
|
||||
* 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).
|
||||
* fallback was a primary child. It was closed above and set to NULL,
|
||||
* but the .bdrv_open() call has opened it again, because we set the
|
||||
* respective option (with the qdict_put_str() call above).
|
||||
* Assert that .bdrv_open() has attached the right BDS as primary child.
|
||||
*/
|
||||
assert(*fallback_ptr && fallback_bs == (*fallback_ptr)->bs);
|
||||
assert(bdrv_primary_bs(bs) == fallback_bs);
|
||||
bdrv_unref(fallback_bs);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1129,9 +1129,9 @@ static coroutine_fn int ssh_co_readv(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
|
||||
int64_t offset, size_t size,
|
||||
QEMUIOVector *qiov)
|
||||
static coroutine_fn int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
|
||||
int64_t offset, size_t size,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
ssize_t r;
|
||||
size_t written;
|
||||
|
@ -78,11 +78,9 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
|
||||
char *group;
|
||||
int ret;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
bs->supported_write_flags = bs->file->bs->supported_write_flags |
|
||||
BDRV_REQ_WRITE_UNCHANGED;
|
||||
|
24
block/vdi.c
24
block/vdi.c
@ -377,10 +377,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
QemuUUID uuid_link, uuid_parent;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
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
|
||||
* 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);
|
||||
} else {
|
||||
nonallocating_write:
|
||||
@ -709,7 +709,7 @@ nonallocating_write:
|
||||
assert(VDI_IS_ALLOCATED(bmap_first));
|
||||
*header = s->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);
|
||||
|
||||
if (ret < 0) {
|
||||
@ -726,8 +726,8 @@ nonallocating_write:
|
||||
base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
|
||||
logout("will write %u block map sectors starting from entry %u\n",
|
||||
n_sectors, bmap_first);
|
||||
ret = bdrv_pwrite(bs->file, offset * SECTOR_SIZE,
|
||||
n_sectors * SECTOR_SIZE, base, 0);
|
||||
ret = bdrv_co_pwrite(bs->file, offset * SECTOR_SIZE,
|
||||
n_sectors * SECTOR_SIZE, base, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -845,7 +845,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
|
||||
vdi_header_print(&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) {
|
||||
error_setg(errp, "Error writing header");
|
||||
goto exit;
|
||||
@ -866,7 +866,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
|
||||
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) {
|
||||
error_setg(errp, "Error writing bmap");
|
||||
goto exit;
|
||||
@ -875,8 +875,8 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
|
||||
}
|
||||
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
ret = blk_truncate(blk, offset + blocks * block_size, false,
|
||||
PREALLOC_MODE_OFF, 0, errp);
|
||||
ret = blk_co_truncate(blk, offset + blocks * block_size, false,
|
||||
PREALLOC_MODE_OFF, 0, errp);
|
||||
if (ret < 0) {
|
||||
error_prepend(errp, "Failed to statically allocate file");
|
||||
goto exit;
|
||||
|
15
block/vhdx.c
15
block/vhdx.c
@ -1001,10 +1001,9 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
uint64_t signature;
|
||||
Error *local_err = NULL;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_items, NULL);
|
||||
signature = cpu_to_le64(VHDX_FILE_SIGNATURE);
|
||||
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET, sizeof(signature), &signature,
|
||||
0);
|
||||
ret = blk_co_pwrite(blk, VHDX_FILE_ID_OFFSET, sizeof(signature), &signature,
|
||||
0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to write file signature");
|
||||
goto delete_and_exit;
|
||||
}
|
||||
if (creator) {
|
||||
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature),
|
||||
creator_items * sizeof(gunichar2), creator, 0);
|
||||
ret = blk_co_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature),
|
||||
creator_items * sizeof(gunichar2), creator, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to write creator field");
|
||||
goto delete_and_exit;
|
||||
|
95
block/vmdk.c
95
block/vmdk.c
@ -1308,10 +1308,9 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
uint32_t magic;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
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
|
||||
* it for call to write user data in the request.
|
||||
*/
|
||||
static int get_whole_cluster(BlockDriverState *bs,
|
||||
VmdkExtent *extent,
|
||||
uint64_t cluster_offset,
|
||||
uint64_t offset,
|
||||
uint64_t skip_start_bytes,
|
||||
uint64_t skip_end_bytes,
|
||||
bool zeroed)
|
||||
static int coroutine_fn get_whole_cluster(BlockDriverState *bs,
|
||||
VmdkExtent *extent,
|
||||
uint64_t cluster_offset,
|
||||
uint64_t offset,
|
||||
uint64_t skip_start_bytes,
|
||||
uint64_t skip_end_bytes,
|
||||
bool zeroed)
|
||||
{
|
||||
int ret = VMDK_OK;
|
||||
int64_t cluster_bytes;
|
||||
@ -1441,16 +1440,16 @@ static int get_whole_cluster(BlockDriverState *bs,
|
||||
if (copy_from_backing) {
|
||||
/* qcow2 emits this on bs->file instead of bs->backing */
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
|
||||
ret = bdrv_pread(bs->backing, offset, skip_start_bytes,
|
||||
whole_grain, 0);
|
||||
ret = bdrv_co_pread(bs->backing, offset, skip_start_bytes,
|
||||
whole_grain, 0);
|
||||
if (ret < 0) {
|
||||
ret = VMDK_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
|
||||
ret = bdrv_pwrite(extent->file, cluster_offset, skip_start_bytes,
|
||||
whole_grain, 0);
|
||||
ret = bdrv_co_pwrite(extent->file, cluster_offset, skip_start_bytes,
|
||||
whole_grain, 0);
|
||||
if (ret < 0) {
|
||||
ret = VMDK_ERROR;
|
||||
goto exit;
|
||||
@ -1461,18 +1460,18 @@ static int get_whole_cluster(BlockDriverState *bs,
|
||||
if (copy_from_backing) {
|
||||
/* qcow2 emits this on bs->file instead of bs->backing */
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
|
||||
ret = bdrv_pread(bs->backing, offset + skip_end_bytes,
|
||||
cluster_bytes - skip_end_bytes,
|
||||
whole_grain + skip_end_bytes, 0);
|
||||
ret = bdrv_co_pread(bs->backing, offset + skip_end_bytes,
|
||||
cluster_bytes - skip_end_bytes,
|
||||
whole_grain + skip_end_bytes, 0);
|
||||
if (ret < 0) {
|
||||
ret = VMDK_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
|
||||
ret = bdrv_pwrite(extent->file, cluster_offset + skip_end_bytes,
|
||||
cluster_bytes - skip_end_bytes,
|
||||
whole_grain + skip_end_bytes, 0);
|
||||
ret = bdrv_co_pwrite(extent->file, cluster_offset + skip_end_bytes,
|
||||
cluster_bytes - skip_end_bytes,
|
||||
whole_grain + skip_end_bytes, 0);
|
||||
if (ret < 0) {
|
||||
ret = VMDK_ERROR;
|
||||
goto exit;
|
||||
@ -1485,29 +1484,29 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
|
||||
uint32_t offset)
|
||||
static int coroutine_fn vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
|
||||
uint32_t offset)
|
||||
{
|
||||
offset = cpu_to_le32(offset);
|
||||
/* update L2 table */
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE);
|
||||
if (bdrv_pwrite(extent->file,
|
||||
((int64_t)m_data->l2_offset * 512)
|
||||
+ (m_data->l2_index * sizeof(offset)),
|
||||
sizeof(offset), &offset, 0) < 0) {
|
||||
if (bdrv_co_pwrite(extent->file,
|
||||
((int64_t)m_data->l2_offset * 512)
|
||||
+ (m_data->l2_index * sizeof(offset)),
|
||||
sizeof(offset), &offset, 0) < 0) {
|
||||
return VMDK_ERROR;
|
||||
}
|
||||
/* update backup L2 table */
|
||||
if (extent->l1_backup_table_offset != 0) {
|
||||
m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
|
||||
if (bdrv_pwrite(extent->file,
|
||||
((int64_t)m_data->l2_offset * 512)
|
||||
+ (m_data->l2_index * sizeof(offset)),
|
||||
sizeof(offset), &offset, 0) < 0) {
|
||||
if (bdrv_co_pwrite(extent->file,
|
||||
((int64_t)m_data->l2_offset * 512)
|
||||
+ (m_data->l2_index * sizeof(offset)),
|
||||
sizeof(offset), &offset, 0) < 0) {
|
||||
return VMDK_ERROR;
|
||||
}
|
||||
}
|
||||
if (bdrv_flush(extent->file->bs) < 0) {
|
||||
if (bdrv_co_flush(extent->file->bs) < 0) {
|
||||
return VMDK_ERROR;
|
||||
}
|
||||
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_ERROR if failed.
|
||||
*/
|
||||
static int get_cluster_offset(BlockDriverState *bs,
|
||||
VmdkExtent *extent,
|
||||
VmdkMetaData *m_data,
|
||||
uint64_t offset,
|
||||
bool allocate,
|
||||
uint64_t *cluster_offset,
|
||||
uint64_t skip_start_bytes,
|
||||
uint64_t skip_end_bytes)
|
||||
static int coroutine_fn get_cluster_offset(BlockDriverState *bs,
|
||||
VmdkExtent *extent,
|
||||
VmdkMetaData *m_data,
|
||||
uint64_t offset,
|
||||
bool allocate,
|
||||
uint64_t *cluster_offset,
|
||||
uint64_t skip_start_bytes,
|
||||
uint64_t skip_end_bytes)
|
||||
{
|
||||
unsigned int l1_index, l2_offset, l2_index;
|
||||
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);
|
||||
BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
|
||||
if (bdrv_pread(extent->file,
|
||||
if (bdrv_co_pread(extent->file,
|
||||
(int64_t)l2_offset * 512,
|
||||
l2_size_bytes,
|
||||
l2_table,
|
||||
0
|
||||
l2_table, 0
|
||||
) < 0) {
|
||||
return VMDK_ERROR;
|
||||
}
|
||||
@ -1899,7 +1897,8 @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
cluster_buf = g_malloc(buf_bytes);
|
||||
uncomp_buf = g_malloc(cluster_bytes);
|
||||
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) {
|
||||
goto out;
|
||||
}
|
||||
@ -2144,8 +2143,8 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
return length;
|
||||
}
|
||||
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
|
||||
ret = bdrv_truncate(s->extents[i].file, length, false,
|
||||
PREALLOC_MODE_OFF, 0, NULL);
|
||||
ret = bdrv_co_truncate(s->extents[i].file, length, false,
|
||||
PREALLOC_MODE_OFF, 0, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -2586,7 +2585,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
|
||||
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) {
|
||||
error_setg_errno(errp, -ret, "Could not write description");
|
||||
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
|
||||
* for description file */
|
||||
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) {
|
||||
goto exit;
|
||||
}
|
||||
|
@ -233,10 +233,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
int64_t bs_size;
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
|
||||
|
@ -499,7 +499,7 @@ static bool valid_filename(const unsigned char *name)
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
c > 127 ||
|
||||
strchr("$%'-_@~`!(){}^#&.+,;=[]", c) != NULL))
|
||||
strchr(" $%'-_@~`!(){}^#&.+,;=[]", c) != NULL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2993,11 +2993,35 @@ DLOG(checkpoint());
|
||||
|
||||
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:
|
||||
* - do not allow writing to the boot sector
|
||||
*/
|
||||
|
||||
if (sector_num < s->offset_to_fat)
|
||||
return -1;
|
||||
|
||||
@ -3146,10 +3170,9 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
|
||||
|
||||
array_init(&(s->commits), sizeof(commit_t));
|
||||
|
||||
s->qcow_filename = g_malloc(PATH_MAX);
|
||||
ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "can't create temporary file");
|
||||
s->qcow_filename = create_tmp_file(errp);
|
||||
if (!s->qcow_filename) {
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
24
blockdev.c
24
blockdev.c
@ -1630,8 +1630,8 @@ static void external_snapshot_abort(BlkActionState *common)
|
||||
aio_context_release(aio_context);
|
||||
aio_context_acquire(tmp_context);
|
||||
|
||||
ret = bdrv_try_set_aio_context(state->old_bs,
|
||||
aio_context, NULL);
|
||||
ret = bdrv_try_change_aio_context(state->old_bs,
|
||||
aio_context, NULL, NULL);
|
||||
assert(ret == 0);
|
||||
|
||||
aio_context_release(tmp_context);
|
||||
@ -1792,12 +1792,12 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
|
||||
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);
|
||||
aio_context_release(aio_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) {
|
||||
bdrv_unref(target_bs);
|
||||
aio_context_release(old_context);
|
||||
@ -1892,12 +1892,12 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
|
||||
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);
|
||||
old_context = bdrv_get_aio_context(target_bs);
|
||||
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) {
|
||||
aio_context_release(old_context);
|
||||
return;
|
||||
@ -2448,7 +2448,7 @@ void coroutine_fn qmp_block_resize(bool has_device, const char *device,
|
||||
bdrv_co_unlock(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_lock(bs);
|
||||
@ -3194,12 +3194,12 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
|
||||
!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);
|
||||
aio_context_release(aio_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) {
|
||||
bdrv_unref(target_bs);
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
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_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);
|
||||
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);
|
||||
}
|
||||
|
56
blockjob.c
56
blockjob.c
@ -126,39 +126,50 @@ static void child_job_drained_end(BdrvChild *c, int *drained_end_counter)
|
||||
job_resume(&job->job);
|
||||
}
|
||||
|
||||
static bool child_job_can_set_aio_ctx(BdrvChild *c, AioContext *ctx,
|
||||
GSList **ignore, Error **errp)
|
||||
typedef struct BdrvStateChildJobContext {
|
||||
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;
|
||||
BdrvStateChildJobContext *s;
|
||||
GSList *l;
|
||||
|
||||
for (l = job->nodes; l; l = l->next) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
s = g_new(BdrvStateChildJobContext, 1);
|
||||
*s = (BdrvStateChildJobContext) {
|
||||
.new_ctx = ctx,
|
||||
.job = job,
|
||||
};
|
||||
|
||||
tran_add(tran, &change_child_job_context, s);
|
||||
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)
|
||||
{
|
||||
BlockJob *job = c->opaque;
|
||||
@ -172,8 +183,7 @@ static const BdrvChildClass child_job = {
|
||||
.drained_begin = child_job_drained_begin,
|
||||
.drained_poll = child_job_drained_poll,
|
||||
.drained_end = child_job_drained_end,
|
||||
.can_set_aio_ctx = child_job_can_set_aio_ctx,
|
||||
.set_aio_ctx = child_job_set_aio_ctx,
|
||||
.change_aio_ctx = child_job_change_aio_ctx,
|
||||
.stay_at_node = true,
|
||||
.get_parent_aio_context = child_job_get_parent_aio_context,
|
||||
};
|
||||
|
@ -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.
|
||||
|
||||
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
|
||||
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
|
||||
each bdrv_*() call. The functions bdrv_add/remove_aio_context_notifier,
|
||||
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.
|
||||
|
@ -97,6 +97,10 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
|
||||
VHostUserBlk *s = VHOST_USER_BLK(dev->vdev);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!dev->started) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg,
|
||||
vdev->config_len, &local_err);
|
||||
if (ret < 0) {
|
||||
|
@ -322,6 +322,45 @@ enum {
|
||||
*
|
||||
* At least one of DATA, METADATA, FILTERED, or COW must be set for
|
||||
* 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
|
||||
* field’s 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 {
|
||||
/*
|
||||
|
@ -76,6 +76,9 @@ BdrvChild *bdrv_open_child(const char *filename,
|
||||
const BdrvChildClass *child_class,
|
||||
BdrvChildRole child_role,
|
||||
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);
|
||||
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
|
||||
Error **errp);
|
||||
@ -217,17 +220,12 @@ void coroutine_fn bdrv_co_lock(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);
|
||||
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_geometry(BlockDriverState *bs, HDGeometry *geo);
|
||||
|
@ -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_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_passwd(Monitor *mon, const QDict *qdict);
|
||||
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
|
||||
|
@ -83,12 +83,13 @@ void bdrv_aio_cancel(BlockAIOCB *acb);
|
||||
void bdrv_aio_cancel_async(BlockAIOCB *acb);
|
||||
|
||||
/* 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. */
|
||||
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);
|
||||
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, int64_t *pnum, int64_t *map,
|
||||
|
@ -119,6 +119,20 @@ struct BlockDriver {
|
||||
* (And this filtered child must then be bs->file or bs->backing.)
|
||||
*/
|
||||
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
|
||||
* 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);
|
||||
|
||||
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
|
||||
bool (*bdrv_co_can_store_new_dirty_bitmap)(BlockDriverState *bs,
|
||||
const char *name,
|
||||
uint32_t granularity,
|
||||
Error **errp);
|
||||
int (*bdrv_co_remove_persistent_dirty_bitmap)(BlockDriverState *bs,
|
||||
const char *name,
|
||||
Error **errp);
|
||||
bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)(
|
||||
BlockDriverState *bs, const char *name, uint32_t granularity,
|
||||
Error **errp);
|
||||
int coroutine_fn (*bdrv_co_remove_persistent_dirty_bitmap)(
|
||||
BlockDriverState *bs, const char *name, Error **errp);
|
||||
};
|
||||
|
||||
static inline bool block_driver_can_compress(BlockDriver *drv)
|
||||
@ -895,9 +907,9 @@ struct BdrvChildClass {
|
||||
int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
|
||||
const char *filename, Error **errp);
|
||||
|
||||
bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore, Error **errp);
|
||||
void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore);
|
||||
bool (*change_aio_ctx)(BdrvChild *child, AioContext *ctx,
|
||||
GHashTable *visited, Transaction *tran,
|
||||
Error **errp);
|
||||
|
||||
AioContext *(*get_parent_aio_context)(BdrvChild *child);
|
||||
|
||||
@ -1045,9 +1057,6 @@ struct BlockDriverState {
|
||||
QDict *full_open_options;
|
||||
char exact_filename[PATH_MAX];
|
||||
|
||||
BdrvChild *backing;
|
||||
BdrvChild *file;
|
||||
|
||||
/* I/O Limits */
|
||||
BlockLimits bl;
|
||||
|
||||
@ -1106,7 +1115,19 @@ struct BlockDriverState {
|
||||
* parent node of this node.
|
||||
*/
|
||||
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;
|
||||
BdrvChild *backing;
|
||||
BdrvChild *file;
|
||||
|
||||
QLIST_HEAD(, BdrvChild) parents;
|
||||
|
||||
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 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,
|
||||
QDict *options);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define HMP_H
|
||||
|
||||
#include "qemu/readline.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "qapi/qapi-types-common.h"
|
||||
|
||||
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_closefd(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_change(Monitor *mon, const QDict *qdict);
|
||||
void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
|
||||
|
@ -287,7 +287,7 @@ void qemu_co_rwlock_init(CoRwlock *lock);
|
||||
* of a parallel writer, control is transferred to the caller of the current
|
||||
* 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
|
||||
@ -296,7 +296,7 @@ void qemu_co_rwlock_rdlock(CoRwlock *lock);
|
||||
* to the caller of the current coroutine; another writer might run while
|
||||
* @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
|
||||
@ -304,20 +304,20 @@ void qemu_co_rwlock_upgrade(CoRwlock *lock);
|
||||
* followed by @qemu_co_rwlock_rdlock. This makes it more efficient, but
|
||||
* 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
|
||||
* of a parallel reader, control is transferred to the caller of the current
|
||||
* 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
|
||||
* 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 {
|
||||
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.
|
||||
* XXX should mark these as coroutine_fn
|
||||
*/
|
||||
ssize_t qemu_co_sendv_recvv(int sockfd, struct iovec *iov, unsigned iov_cnt,
|
||||
size_t offset, size_t bytes, bool do_send);
|
||||
ssize_t coroutine_fn qemu_co_sendv_recvv(int sockfd, struct iovec *iov,
|
||||
unsigned iov_cnt, size_t offset,
|
||||
size_t bytes, bool do_send);
|
||||
#define qemu_co_recvv(sockfd, iov, iov_cnt, offset, bytes) \
|
||||
qemu_co_sendv_recvv(sockfd, iov, iov_cnt, offset, bytes, false)
|
||||
#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
|
||||
*/
|
||||
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) \
|
||||
qemu_co_send_recv(sockfd, buf, bytes, false)
|
||||
#define qemu_co_send(sockfd, buf, bytes) \
|
||||
|
2
job.c
2
job.c
@ -588,7 +588,7 @@ static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns)
|
||||
next_aio_context = job->aio_context;
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
while (qemu_get_current_aio_context() != next_aio_context) {
|
||||
|
@ -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_LINUX_AIO', libaio.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_NUMA', numa.found())
|
||||
config_host_data.set('CONFIG_OPENGL', opengl.found())
|
||||
|
@ -375,7 +375,8 @@ if [ "${VALGRIND_QEMU_VM}" == "y" ]; then
|
||||
_casenotrun "Valgrind needs a valid TMPDIR for itself"
|
||||
fi
|
||||
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
|
||||
echo "info block" |
|
||||
|
@ -459,7 +459,7 @@ wrote 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)
|
||||
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
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
|
@ -539,7 +539,7 @@ wrote 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)
|
||||
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
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
|
@ -1538,16 +1538,16 @@ static void test_set_aio_context(void)
|
||||
&error_abort);
|
||||
|
||||
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);
|
||||
bdrv_drained_end(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_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);
|
||||
bdrv_drained_end(bs);
|
||||
|
||||
@ -1830,9 +1830,8 @@ static void test_drop_intermediate_poll(void)
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (i) {
|
||||
/* Takes the reference to chain[i - 1] */
|
||||
chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1],
|
||||
"chain", &chain_child_class,
|
||||
BDRV_CHILD_COW, &error_abort);
|
||||
bdrv_attach_child(chain[i], chain[i - 1], "chain",
|
||||
&chain_child_class, 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 = {
|
||||
.format_name = "replace_test",
|
||||
.instance_size = sizeof(BDRVReplaceTestState),
|
||||
.supports_backing = true,
|
||||
|
||||
.bdrv_close = bdrv_replace_test_close,
|
||||
.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;
|
||||
|
||||
bdrv_ref(old_child_bs);
|
||||
parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child",
|
||||
&child_of_bds, BDRV_CHILD_COW,
|
||||
&error_abort);
|
||||
bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
|
||||
BDRV_CHILD_COW, &error_abort);
|
||||
|
||||
for (i = 0; i < old_drain_count; i++) {
|
||||
bdrv_drained_begin(old_child_bs);
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
static BlockDriver bdrv_pass_through = {
|
||||
.format_name = "pass-through",
|
||||
.is_filter = true,
|
||||
.filtered_child_is_backing = true,
|
||||
.bdrv_child_perm = bdrv_default_perms,
|
||||
};
|
||||
|
||||
@ -57,6 +59,8 @@ static void exclusive_write_perms(BlockDriverState *bs, BdrvChild *c,
|
||||
|
||||
static BlockDriver bdrv_exclusive_writer = {
|
||||
.format_name = "exclusive-writer",
|
||||
.is_filter = true,
|
||||
.filtered_child_is_backing = true,
|
||||
.bdrv_child_perm = exclusive_write_perms,
|
||||
};
|
||||
|
||||
@ -134,7 +138,7 @@ static void test_update_perm_tree(void)
|
||||
blk_insert_bs(root, bs, &error_abort);
|
||||
|
||||
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);
|
||||
g_assert_cmpint(ret, <, 0);
|
||||
@ -228,11 +232,14 @@ static void test_parallel_exclusive_write(void)
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
bdrv_replace_node(fl1, fl2, &error_abort);
|
||||
@ -241,13 +248,26 @@ static void test_parallel_exclusive_write(void)
|
||||
bdrv_unref(top);
|
||||
}
|
||||
|
||||
static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
/*
|
||||
* write-to-selected node may have several DATA children, one of them may be
|
||||
* "selected". Exclusive write permission is taken on selected child.
|
||||
*
|
||||
* 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;
|
||||
*nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE;
|
||||
} else {
|
||||
@ -256,9 +276,10 @@ static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c,
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_write_to_file = {
|
||||
.format_name = "tricky-perm",
|
||||
.bdrv_child_perm = write_to_file_perms,
|
||||
static BlockDriver bdrv_write_to_selected = {
|
||||
.format_name = "write-to-selected",
|
||||
.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
|
||||
* permission update, simple DFS is not enough.
|
||||
*
|
||||
* Consider the block driver which has two filter children: one active
|
||||
* with exclusive write access and one inactive with no specific
|
||||
* permissions.
|
||||
* Consider the block driver (write-to-selected) which has two children: one is
|
||||
* selected so we have exclusive write access to it and for the other one we
|
||||
* don't need any specific permissions.
|
||||
*
|
||||
* 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
|
||||
* │ ▼
|
||||
@ -290,14 +314,14 @@ static BlockDriver bdrv_write_to_file = {
|
||||
*
|
||||
* So, exclusive write is propagated.
|
||||
*
|
||||
* Assume, we want to make fl2 active instead of fl1.
|
||||
* So, we set some option for top driver and do permission update.
|
||||
* Assume, we want to select fl2 instead of fl1.
|
||||
* So, we set some option for write-to-selected driver and do permission update.
|
||||
*
|
||||
* With simple DFS, if permission update goes first through
|
||||
* top->fl1->base branch it will succeed: it firstly drop exclusive write
|
||||
* permissions and than apply them for another BdrvChildren.
|
||||
* But if permission update goes first through top->fl2->base branch it
|
||||
* will fail, as when we try to update fl2->base child, old not yet
|
||||
* write-to-selected -> fl1 -> base branch it will succeed: it firstly drop
|
||||
* exclusive write permissions and than apply them for another BdrvChildren.
|
||||
* But if permission update goes first through write-to-selected -> fl2 -> base
|
||||
* branch it will fail, as when we try to update fl2->base child, old not yet
|
||||
* updated fl1->base child will be in conflict.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
BlockDriverState *top = no_perm_node("top");
|
||||
BlockDriverState *tricky =
|
||||
bdrv_new_open_driver(&bdrv_write_to_file, "tricky", BDRV_O_RDWR,
|
||||
BlockDriverState *ws =
|
||||
bdrv_new_open_driver(&bdrv_write_to_selected, "ws", BDRV_O_RDWR,
|
||||
&error_abort);
|
||||
BDRVWriteToSelectedState *s = ws->opaque;
|
||||
BlockDriverState *base = no_perm_node("base");
|
||||
BlockDriverState *fl1 = pass_through_node("fl1");
|
||||
BlockDriverState *fl2 = pass_through_node("fl2");
|
||||
@ -320,33 +345,35 @@ static void test_parallel_perm_update(void)
|
||||
*/
|
||||
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);
|
||||
c_fl1 = bdrv_attach_child(tricky, fl1, "first", &child_of_bds,
|
||||
BDRV_CHILD_FILTERED, &error_abort);
|
||||
c_fl2 = bdrv_attach_child(tricky, fl2, "second", &child_of_bds,
|
||||
BDRV_CHILD_FILTERED, &error_abort);
|
||||
bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED,
|
||||
c_fl1 = bdrv_attach_child(ws, fl1, "first", &child_of_bds,
|
||||
BDRV_CHILD_DATA, &error_abort);
|
||||
c_fl2 = bdrv_attach_child(ws, fl2, "second", &child_of_bds,
|
||||
BDRV_CHILD_DATA, &error_abort);
|
||||
bdrv_attach_child(fl1, base, "backing", &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
&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);
|
||||
|
||||
/* 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);
|
||||
|
||||
assert(c_fl1->perm & BLK_PERM_WRITE);
|
||||
assert(!(c_fl2->perm & BLK_PERM_WRITE));
|
||||
|
||||
/* 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);
|
||||
|
||||
assert(c_fl2->perm & BLK_PERM_WRITE);
|
||||
assert(!(c_fl1->perm & BLK_PERM_WRITE));
|
||||
|
||||
/* 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);
|
||||
|
||||
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 *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);
|
||||
|
||||
bdrv_append(fl, base, &error_abort);
|
||||
|
@ -765,7 +765,7 @@ static void test_propagate_mirror(void)
|
||||
filter = bdrv_find_node("filter_node");
|
||||
|
||||
/* 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(target) == ctx);
|
||||
g_assert(bdrv_get_aio_context(filter) == ctx);
|
||||
@ -773,7 +773,7 @@ static void test_propagate_mirror(void)
|
||||
|
||||
/* Change the AioContext of target */
|
||||
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);
|
||||
g_assert(bdrv_get_aio_context(src) == 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_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);
|
||||
|
||||
g_assert(blk_get_aio_context(blk) == main_ctx);
|
||||
@ -794,7 +794,7 @@ static void test_propagate_mirror(void)
|
||||
/* ...unless we explicitly allow it */
|
||||
aio_context_acquire(ctx);
|
||||
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);
|
||||
|
||||
g_assert(blk_get_aio_context(blk) == ctx);
|
||||
@ -806,7 +806,7 @@ static void test_propagate_mirror(void)
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
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);
|
||||
|
||||
blk_unref(blk);
|
||||
|
Loading…
Reference in New Issue
Block a user