mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging
Block layer patches - Fix blockdev-create with iothreads - Remove aio_disable_external() API # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmR2JIARHGt3b2xmQHJl # ZGhhdC5jb20ACgkQfwmycsiPL9brtA/9HVdAdtJxW78J60TE2lTqE9XlqMOEHBZl # 8GN72trjP2geY/9mVsv/XoFie4ecqFsYjwAWWUuXZwLgAo53jh7oFN7gBH5iGyyD # +EukYEfjqoykX5BkoK0gbMZZUe5Y4Dr2CNXYw4bNg8kDzj2RLifGA1XhdL3HoiVt # PHZrhwBR7ddww6gVOnyJrfGL8fMkW/ZNeKRhrTZuSP+63oDOeGTsTumD+YKJzfPs # p5WlwkuPjcqbO+w32FeVOHVhNI4swkN5svz3fkr8NuflfA7kH6nBQ5wymObbaTLc # Erx03lrtP1+6nw43V11UnYt6iDMg4EBUQwtzNaKFnk3rMIdjoQYxIM5FTBWL2rYD # Dg6PhkncXQ1WNWhUaFqpTFLB52XAYsSa4/y2QAGP6nWbqAUAUknQ3exaMvWiq7Z0 # nZeyyhIWvpJIHGCArWRdqqh+zsBdsmUVuPGyZnZgL/cXoJboYiHMyMJSUWE0XxML # NGrncwxdsBXkVGGwTdHpBT64dcu3ENRgwtraqRLQm+tp5MKNTJB/+Ug2/p1vonHT # UOoHz//UPskn8sHIyevoHXeu2Ns0uIHzrAXr+7Ay+9UYyIH6a07F4b2BGqkfyi/i # 8wQsDmJ/idx5C4q1+jS+GuIbpnjIx6nxXwXMqpscUXZmM4Am8OMkiKxQAa1wExGF # paId+HHwyks= # =yuER # -----END PGP SIGNATURE----- # gpg: Signature made Tue 30 May 2023 09:29:52 AM PDT # gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6 # gpg: issuer "kwolf@redhat.com" # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] * tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (32 commits) aio: remove aio_disable_external() API virtio: do not set is_external=true on host notifiers virtio-scsi: implement BlockDevOps->drained_begin() virtio-blk: implement BlockDevOps->drained_begin() virtio: make it possible to detach host notifier from any thread block/fuse: do not set is_external=true on FUSE fd block/export: don't require AioContext lock around blk_exp_ref/unref() block/export: rewrite vduse-blk drain code hw/xen: do not set is_external=true on evtchn fds xen-block: implement BlockDevOps->drained_begin() block: drain from main loop thread in bdrv_co_yield_to_drain() block: add blk_in_drain() API hw/xen: do not use aio_set_fd_handler(is_external=true) in xen_xenstore block/export: stop using is_external in vhost-user-blk server block/export: wait for vhost-user-blk requests when draining util/vhost-user-server: rename refcount to in_flight counter virtio-scsi: stop using aio_disable_external() during unplug virtio-scsi: avoid race between unplug and transport event hw/qdev: introduce qdev_is_realized() helper block-backend: split blk_do_set_aio_context() ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
@@ -1613,6 +1613,7 @@ static int no_coroutine_fn GRAPH_UNLOCKED
|
||||
bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
|
||||
QDict *options, int open_flags, Error **errp)
|
||||
{
|
||||
AioContext *ctx;
|
||||
Error *local_err = NULL;
|
||||
int i, ret;
|
||||
GLOBAL_STATE_CODE();
|
||||
@@ -1660,15 +1661,21 @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
|
||||
bs->supported_read_flags |= BDRV_REQ_REGISTERED_BUF;
|
||||
bs->supported_write_flags |= BDRV_REQ_REGISTERED_BUF;
|
||||
|
||||
/* Get the context after .bdrv_open, it can change the context */
|
||||
ctx = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(ctx);
|
||||
|
||||
ret = bdrv_refresh_total_sectors(bs, bs->total_sectors);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not refresh total sector count");
|
||||
aio_context_release(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bdrv_graph_rdlock_main_loop();
|
||||
bdrv_refresh_limits(bs, NULL, &local_err);
|
||||
bdrv_graph_rdunlock_main_loop();
|
||||
aio_context_release(ctx);
|
||||
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -3478,6 +3485,8 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
|
||||
* itself, all options starting with "${bdref_key}." are considered part of the
|
||||
* BlockdevRef.
|
||||
*
|
||||
* The caller must hold the main AioContext lock.
|
||||
*
|
||||
* TODO Can this be unified with bdrv_open_image()?
|
||||
*/
|
||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
|
||||
@@ -3644,6 +3653,9 @@ done:
|
||||
* BlockdevRef.
|
||||
*
|
||||
* The BlockdevRef will be removed from the options QDict.
|
||||
*
|
||||
* @parent can move to a different AioContext in this function. Callers must
|
||||
* make sure that their AioContext locking is still correct after this.
|
||||
*/
|
||||
BdrvChild *bdrv_open_child(const char *filename,
|
||||
QDict *options, const char *bdref_key,
|
||||
@@ -3668,6 +3680,9 @@ BdrvChild *bdrv_open_child(const char *filename,
|
||||
|
||||
/*
|
||||
* Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
|
||||
*
|
||||
* @parent can move to a different AioContext in this function. Callers must
|
||||
* make sure that their AioContext locking is still correct after this.
|
||||
*/
|
||||
int bdrv_open_file_child(const char *filename,
|
||||
QDict *options, const char *bdref_key,
|
||||
@@ -3810,9 +3825,7 @@ out:
|
||||
* should be opened. If specified, neither options nor a filename may be given,
|
||||
* nor can an existing BDS be reused (that is, *pbs has to be NULL).
|
||||
*
|
||||
* The caller must always hold @filename AioContext lock, because this
|
||||
* function eventually calls bdrv_refresh_total_sectors() which polls
|
||||
* when called from non-coroutine context.
|
||||
* The caller must always hold the main AioContext lock.
|
||||
*/
|
||||
static BlockDriverState * no_coroutine_fn
|
||||
bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
|
||||
@@ -4100,11 +4113,7 @@ close_and_fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller must always hold @filename AioContext lock, because this
|
||||
* function eventually calls bdrv_refresh_total_sectors() which polls
|
||||
* when called from non-coroutine context.
|
||||
*/
|
||||
/* The caller must always hold the main AioContext lock. */
|
||||
BlockDriverState *bdrv_open(const char *filename, const char *reference,
|
||||
QDict *options, int flags, Error **errp)
|
||||
{
|
||||
@@ -5390,12 +5399,17 @@ static void bdrv_delete(BlockDriverState *bs)
|
||||
* empty set of options. The reference to the QDict belongs to the block layer
|
||||
* after the call (even on failure), so if the caller intends to reuse the
|
||||
* dictionary, it needs to use qobject_ref() before calling bdrv_open.
|
||||
*
|
||||
* The caller holds the AioContext lock for @bs. It must make sure that @bs
|
||||
* stays in the same AioContext, i.e. @options must not refer to nodes in a
|
||||
* different AioContext.
|
||||
*/
|
||||
BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
|
||||
int flags, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
int ret;
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
BlockDriverState *new_node_bs = NULL;
|
||||
const char *drvname, *node_name;
|
||||
BlockDriver *drv;
|
||||
@@ -5416,8 +5430,14 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
|
||||
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
aio_context_release(ctx);
|
||||
aio_context_acquire(qemu_get_aio_context());
|
||||
new_node_bs = bdrv_new_open_driver_opts(drv, node_name, options, flags,
|
||||
errp);
|
||||
aio_context_release(qemu_get_aio_context());
|
||||
aio_context_acquire(ctx);
|
||||
assert(bdrv_get_aio_context(bs) == ctx);
|
||||
|
||||
options = NULL; /* bdrv_new_open_driver() eats options */
|
||||
if (!new_node_bs) {
|
||||
error_prepend(errp, "Could not create node: ");
|
||||
@@ -7043,6 +7063,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context_acquire(qemu_get_aio_context());
|
||||
|
||||
/* Create parameter list */
|
||||
create_opts = qemu_opts_append(create_opts, drv->create_opts);
|
||||
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
|
||||
@@ -7192,6 +7214,7 @@ out:
|
||||
qemu_opts_del(opts);
|
||||
qemu_opts_free(create_opts);
|
||||
error_propagate(errp, local_err);
|
||||
aio_context_release(qemu_get_aio_context());
|
||||
}
|
||||
|
||||
AioContext *bdrv_get_aio_context(BlockDriverState *bs)
|
||||
@@ -7282,9 +7305,6 @@ static void bdrv_detach_aio_context(BlockDriverState *bs)
|
||||
bs->drv->bdrv_detach_aio_context(bs);
|
||||
}
|
||||
|
||||
if (bs->quiesce_counter) {
|
||||
aio_enable_external(bs->aio_context);
|
||||
}
|
||||
bs->aio_context = NULL;
|
||||
}
|
||||
|
||||
@@ -7294,10 +7314,6 @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||
BdrvAioNotifier *ban, *ban_tmp;
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
if (bs->quiesce_counter) {
|
||||
aio_disable_external(new_context);
|
||||
}
|
||||
|
||||
bs->aio_context = new_context;
|
||||
|
||||
if (bs->drv && bs->drv->bdrv_attach_aio_context) {
|
||||
|
||||
+5
-10
@@ -306,23 +306,18 @@ static void blkio_attach_aio_context(BlockDriverState *bs,
|
||||
{
|
||||
BDRVBlkioState *s = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(new_context,
|
||||
s->completion_fd,
|
||||
false,
|
||||
blkio_completion_fd_read,
|
||||
NULL,
|
||||
aio_set_fd_handler(new_context, s->completion_fd,
|
||||
blkio_completion_fd_read, NULL,
|
||||
blkio_completion_fd_poll,
|
||||
blkio_completion_fd_poll_ready,
|
||||
bs);
|
||||
blkio_completion_fd_poll_ready, bs);
|
||||
}
|
||||
|
||||
static void blkio_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkioState *s = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs),
|
||||
s->completion_fd,
|
||||
false, NULL, NULL, NULL, NULL, NULL);
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->completion_fd, NULL, NULL,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Call with s->blkio_lock held to submit I/O after enqueuing a new request */
|
||||
|
||||
+64
-50
@@ -389,6 +389,8 @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
|
||||
* Both sets of permissions can be changed later using blk_set_perm().
|
||||
*
|
||||
* Return the new BlockBackend on success, null on failure.
|
||||
*
|
||||
* Callers must hold the AioContext lock of @bs.
|
||||
*/
|
||||
BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm,
|
||||
uint64_t shared_perm, Error **errp)
|
||||
@@ -406,11 +408,15 @@ BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm,
|
||||
|
||||
/*
|
||||
* Creates a new BlockBackend, opens a new BlockDriverState, and connects both.
|
||||
* The new BlockBackend is in the main AioContext.
|
||||
* By default, the new BlockBackend is in the main AioContext, but if the
|
||||
* parameters connect it with any existing node in a different AioContext, it
|
||||
* may end up there instead.
|
||||
*
|
||||
* Just as with bdrv_open(), after having called this function the reference to
|
||||
* @options belongs to the block layer (even on failure).
|
||||
*
|
||||
* Called without holding an AioContext lock.
|
||||
*
|
||||
* TODO: Remove @filename and @flags; it should be possible to specify a whole
|
||||
* BDS tree just by specifying the @options QDict (or @reference,
|
||||
* alternatively). At the time of adding this function, this is not possible,
|
||||
@@ -422,6 +428,7 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
AioContext *ctx;
|
||||
uint64_t perm = 0;
|
||||
uint64_t shared = BLK_PERM_ALL;
|
||||
|
||||
@@ -451,16 +458,24 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
|
||||
shared = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
|
||||
}
|
||||
|
||||
blk = blk_new(qemu_get_aio_context(), perm, shared);
|
||||
aio_context_acquire(qemu_get_aio_context());
|
||||
bs = bdrv_open(filename, reference, options, flags, errp);
|
||||
aio_context_release(qemu_get_aio_context());
|
||||
if (!bs) {
|
||||
blk_unref(blk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
perm, shared, blk, errp);
|
||||
/* bdrv_open() could have moved bs to a different AioContext */
|
||||
ctx = bdrv_get_aio_context(bs);
|
||||
blk = blk_new(bdrv_get_aio_context(bs), perm, shared);
|
||||
blk->perm = perm;
|
||||
blk->shared_perm = shared;
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
blk_insert_bs(blk, bs, errp);
|
||||
bdrv_unref(bs);
|
||||
aio_context_release(ctx);
|
||||
|
||||
if (!blk->root) {
|
||||
blk_unref(blk);
|
||||
return NULL;
|
||||
@@ -901,6 +916,8 @@ void blk_remove_bs(BlockBackend *blk)
|
||||
|
||||
/*
|
||||
* Associates a new BlockDriverState with @blk.
|
||||
*
|
||||
* Callers must hold the AioContext lock of @bs.
|
||||
*/
|
||||
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
@@ -1270,6 +1287,13 @@ blk_check_byte_request(BlockBackend *blk, int64_t offset, int64_t bytes)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Are we currently in a drained section? */
|
||||
bool blk_in_drain(BlockBackend *blk)
|
||||
{
|
||||
GLOBAL_STATE_CODE(); /* change to IO_OR_GS_CODE(), if necessary */
|
||||
return qatomic_read(&blk->quiesce_counter);
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
|
||||
{
|
||||
@@ -2394,9 +2418,14 @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason)
|
||||
|
||||
AioContext *blk_get_aio_context(BlockBackend *blk)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
BlockDriverState *bs;
|
||||
IO_CODE();
|
||||
|
||||
if (!blk) {
|
||||
return qemu_get_aio_context();
|
||||
}
|
||||
|
||||
bs = blk_bs(blk);
|
||||
if (bs) {
|
||||
AioContext *ctx = bdrv_get_aio_context(blk_bs(blk));
|
||||
assert(ctx == blk->ctx);
|
||||
@@ -2411,52 +2440,31 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
|
||||
return blk_get_aio_context(blk_acb->blk);
|
||||
}
|
||||
|
||||
static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
|
||||
bool update_root_node, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
int ret;
|
||||
|
||||
if (bs) {
|
||||
bdrv_ref(bs);
|
||||
|
||||
if (update_root_node) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Make blk->ctx consistent with the root node before we invoke any
|
||||
* other operations like drain that might inquire blk->ctx
|
||||
*/
|
||||
blk->ctx = new_context;
|
||||
if (tgm->throttle_state) {
|
||||
bdrv_drained_begin(bs);
|
||||
throttle_group_detach_aio_context(tgm);
|
||||
throttle_group_attach_aio_context(tgm, new_context);
|
||||
bdrv_drained_end(bs);
|
||||
}
|
||||
|
||||
bdrv_unref(bs);
|
||||
} else {
|
||||
blk->ctx = new_context;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
|
||||
Error **errp)
|
||||
{
|
||||
bool old_allow_change;
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
int ret;
|
||||
|
||||
GLOBAL_STATE_CODE();
|
||||
return blk_do_set_aio_context(blk, new_context, true, errp);
|
||||
|
||||
if (!bs) {
|
||||
blk->ctx = new_context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bdrv_ref(bs);
|
||||
|
||||
old_allow_change = blk->allow_aio_context_change;
|
||||
blk->allow_aio_context_change = true;
|
||||
|
||||
ret = bdrv_try_change_aio_context(bs, new_context, NULL, errp);
|
||||
|
||||
blk->allow_aio_context_change = old_allow_change;
|
||||
|
||||
bdrv_unref(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct BdrvStateBlkRootContext {
|
||||
@@ -2468,8 +2476,14 @@ static void blk_root_set_aio_ctx_commit(void *opaque)
|
||||
{
|
||||
BdrvStateBlkRootContext *s = opaque;
|
||||
BlockBackend *blk = s->blk;
|
||||
AioContext *new_context = s->new_ctx;
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
|
||||
blk_do_set_aio_context(blk, s->new_ctx, false, &error_abort);
|
||||
blk->ctx = new_context;
|
||||
if (tgm->throttle_state) {
|
||||
throttle_group_detach_aio_context(tgm);
|
||||
throttle_group_attach_aio_context(tgm, new_context);
|
||||
}
|
||||
}
|
||||
|
||||
static TransactionActionDrv set_blk_root_context = {
|
||||
|
||||
@@ -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;
|
||||
AioContext *ctx;
|
||||
int ret;
|
||||
|
||||
full_opts = cbw_parse_options(options, errp);
|
||||
@@ -432,11 +433,15 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(ctx);
|
||||
|
||||
if (opts->bitmap) {
|
||||
bitmap = block_dirty_bitmap_lookup(opts->bitmap->node,
|
||||
opts->bitmap->name, NULL, errp);
|
||||
if (!bitmap) {
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
s->on_cbw_error = opts->has_on_cbw_error ? opts->on_cbw_error :
|
||||
@@ -454,21 +459,24 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->bcs = block_copy_state_new(bs->file, s->target, bitmap, errp);
|
||||
if (!s->bcs) {
|
||||
error_prepend(errp, "Cannot create block-copy-state: ");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cluster_size = block_copy_cluster_size(s->bcs);
|
||||
|
||||
s->done_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp);
|
||||
if (!s->done_bitmap) {
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
bdrv_disable_dirty_bitmap(s->done_bitmap);
|
||||
|
||||
/* s->access_bitmap starts equal to bcs bitmap */
|
||||
s->access_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp);
|
||||
if (!s->access_bitmap) {
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
bdrv_disable_dirty_bitmap(s->access_bitmap);
|
||||
bdrv_dirty_bitmap_merge_internal(s->access_bitmap,
|
||||
@@ -478,7 +486,10 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
QLIST_INIT(&s->frozen_read_reqs);
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
out:
|
||||
aio_context_release(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cbw_close(BlockDriverState *bs)
|
||||
|
||||
+5
-5
@@ -132,7 +132,7 @@ static gboolean curl_drop_socket(void *key, void *value, void *opaque)
|
||||
CURLSocket *socket = value;
|
||||
BDRVCURLState *s = socket->s;
|
||||
|
||||
aio_set_fd_handler(s->aio_context, socket->fd, false,
|
||||
aio_set_fd_handler(s->aio_context, socket->fd,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
return true;
|
||||
}
|
||||
@@ -180,20 +180,20 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||
trace_curl_sock_cb(action, (int)fd);
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
aio_set_fd_handler(s->aio_context, fd,
|
||||
curl_multi_do, NULL, NULL, NULL, socket);
|
||||
break;
|
||||
case CURL_POLL_OUT:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
aio_set_fd_handler(s->aio_context, fd,
|
||||
NULL, curl_multi_do, NULL, NULL, socket);
|
||||
break;
|
||||
case CURL_POLL_INOUT:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
aio_set_fd_handler(s->aio_context, fd,
|
||||
curl_multi_do, curl_multi_do,
|
||||
NULL, NULL, socket);
|
||||
break;
|
||||
case CURL_POLL_REMOVE:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
aio_set_fd_handler(s->aio_context, fd,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -204,11 +204,10 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Callers must hold exp->ctx lock */
|
||||
void blk_exp_ref(BlockExport *exp)
|
||||
{
|
||||
assert(exp->refcount > 0);
|
||||
exp->refcount++;
|
||||
assert(qatomic_read(&exp->refcount) > 0);
|
||||
qatomic_inc(&exp->refcount);
|
||||
}
|
||||
|
||||
/* Runs in the main thread */
|
||||
@@ -231,11 +230,10 @@ static void blk_exp_delete_bh(void *opaque)
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
/* Callers must hold exp->ctx lock */
|
||||
void blk_exp_unref(BlockExport *exp)
|
||||
{
|
||||
assert(exp->refcount > 0);
|
||||
if (--exp->refcount == 0) {
|
||||
assert(qatomic_read(&exp->refcount) > 0);
|
||||
if (qatomic_fetch_dec(&exp->refcount) == 1) {
|
||||
/* Touch the block_exports list only in the main thread */
|
||||
aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_exp_delete_bh,
|
||||
exp);
|
||||
@@ -343,7 +341,8 @@ void qmp_block_export_del(const char *id,
|
||||
if (!has_mode) {
|
||||
mode = BLOCK_EXPORT_REMOVE_MODE_SAFE;
|
||||
}
|
||||
if (mode == BLOCK_EXPORT_REMOVE_MODE_SAFE && exp->refcount > 1) {
|
||||
if (mode == BLOCK_EXPORT_REMOVE_MODE_SAFE &&
|
||||
qatomic_read(&exp->refcount) > 1) {
|
||||
error_setg(errp, "export '%s' still in use", exp->id);
|
||||
error_append_hint(errp, "Use mode='hard' to force client "
|
||||
"disconnect\n");
|
||||
|
||||
+54
-2
@@ -50,6 +50,7 @@ typedef struct FuseExport {
|
||||
|
||||
struct fuse_session *fuse_session;
|
||||
struct fuse_buf fuse_buf;
|
||||
unsigned int in_flight; /* atomic */
|
||||
bool mounted, fd_handler_set_up;
|
||||
|
||||
char *mountpoint;
|
||||
@@ -78,6 +79,42 @@ static void read_from_fuse_export(void *opaque);
|
||||
static bool is_regular_file(const char *path, Error **errp);
|
||||
|
||||
|
||||
static void fuse_export_drained_begin(void *opaque)
|
||||
{
|
||||
FuseExport *exp = opaque;
|
||||
|
||||
aio_set_fd_handler(exp->common.ctx,
|
||||
fuse_session_fd(exp->fuse_session),
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
exp->fd_handler_set_up = false;
|
||||
}
|
||||
|
||||
static void fuse_export_drained_end(void *opaque)
|
||||
{
|
||||
FuseExport *exp = opaque;
|
||||
|
||||
/* Refresh AioContext in case it changed */
|
||||
exp->common.ctx = blk_get_aio_context(exp->common.blk);
|
||||
|
||||
aio_set_fd_handler(exp->common.ctx,
|
||||
fuse_session_fd(exp->fuse_session),
|
||||
read_from_fuse_export, NULL, NULL, NULL, exp);
|
||||
exp->fd_handler_set_up = true;
|
||||
}
|
||||
|
||||
static bool fuse_export_drained_poll(void *opaque)
|
||||
{
|
||||
FuseExport *exp = opaque;
|
||||
|
||||
return qatomic_read(&exp->in_flight) > 0;
|
||||
}
|
||||
|
||||
static const BlockDevOps fuse_export_blk_dev_ops = {
|
||||
.drained_begin = fuse_export_drained_begin,
|
||||
.drained_end = fuse_export_drained_end,
|
||||
.drained_poll = fuse_export_drained_poll,
|
||||
};
|
||||
|
||||
static int fuse_export_create(BlockExport *blk_exp,
|
||||
BlockExportOptions *blk_exp_args,
|
||||
Error **errp)
|
||||
@@ -101,6 +138,15 @@ static int fuse_export_create(BlockExport *blk_exp,
|
||||
}
|
||||
}
|
||||
|
||||
blk_set_dev_ops(exp->common.blk, &fuse_export_blk_dev_ops, exp);
|
||||
|
||||
/*
|
||||
* We handle draining ourselves using an in-flight counter and by disabling
|
||||
* the FUSE fd handler. Do not queue BlockBackend requests, they need to
|
||||
* complete so the in-flight counter reaches zero.
|
||||
*/
|
||||
blk_set_disable_request_queuing(exp->common.blk, true);
|
||||
|
||||
init_exports_table();
|
||||
|
||||
/*
|
||||
@@ -224,7 +270,7 @@ static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
|
||||
g_hash_table_insert(exports, g_strdup(mountpoint), NULL);
|
||||
|
||||
aio_set_fd_handler(exp->common.ctx,
|
||||
fuse_session_fd(exp->fuse_session), true,
|
||||
fuse_session_fd(exp->fuse_session),
|
||||
read_from_fuse_export, NULL, NULL, NULL, exp);
|
||||
exp->fd_handler_set_up = true;
|
||||
|
||||
@@ -246,6 +292,8 @@ static void read_from_fuse_export(void *opaque)
|
||||
|
||||
blk_exp_ref(&exp->common);
|
||||
|
||||
qatomic_inc(&exp->in_flight);
|
||||
|
||||
do {
|
||||
ret = fuse_session_receive_buf(exp->fuse_session, &exp->fuse_buf);
|
||||
} while (ret == -EINTR);
|
||||
@@ -256,6 +304,10 @@ static void read_from_fuse_export(void *opaque)
|
||||
fuse_session_process_buf(exp->fuse_session, &exp->fuse_buf);
|
||||
|
||||
out:
|
||||
if (qatomic_fetch_dec(&exp->in_flight) == 1) {
|
||||
aio_wait_kick(); /* wake AIO_WAIT_WHILE() */
|
||||
}
|
||||
|
||||
blk_exp_unref(&exp->common);
|
||||
}
|
||||
|
||||
@@ -268,7 +320,7 @@ static void fuse_export_shutdown(BlockExport *blk_exp)
|
||||
|
||||
if (exp->fd_handler_set_up) {
|
||||
aio_set_fd_handler(exp->common.ctx,
|
||||
fuse_session_fd(exp->fuse_session), true,
|
||||
fuse_session_fd(exp->fuse_session),
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
exp->fd_handler_set_up = false;
|
||||
}
|
||||
|
||||
+89
-39
@@ -31,7 +31,8 @@ typedef struct VduseBlkExport {
|
||||
VduseDev *dev;
|
||||
uint16_t num_queues;
|
||||
char *recon_file;
|
||||
unsigned int inflight;
|
||||
unsigned int inflight; /* atomic */
|
||||
bool vqs_started;
|
||||
} VduseBlkExport;
|
||||
|
||||
typedef struct VduseBlkReq {
|
||||
@@ -41,13 +42,20 @@ typedef struct VduseBlkReq {
|
||||
|
||||
static void vduse_blk_inflight_inc(VduseBlkExport *vblk_exp)
|
||||
{
|
||||
vblk_exp->inflight++;
|
||||
if (qatomic_fetch_inc(&vblk_exp->inflight) == 0) {
|
||||
/* Prevent export from being deleted */
|
||||
blk_exp_ref(&vblk_exp->export);
|
||||
}
|
||||
}
|
||||
|
||||
static void vduse_blk_inflight_dec(VduseBlkExport *vblk_exp)
|
||||
{
|
||||
if (--vblk_exp->inflight == 0) {
|
||||
if (qatomic_fetch_dec(&vblk_exp->inflight) == 1) {
|
||||
/* Wake AIO_WAIT_WHILE() */
|
||||
aio_wait_kick();
|
||||
|
||||
/* Now the export can be deleted */
|
||||
blk_exp_unref(&vblk_exp->export);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +132,12 @@ static void vduse_blk_enable_queue(VduseDev *dev, VduseVirtq *vq)
|
||||
{
|
||||
VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev);
|
||||
|
||||
if (!vblk_exp->vqs_started) {
|
||||
return; /* vduse_blk_drained_end() will start vqs later */
|
||||
}
|
||||
|
||||
aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq),
|
||||
true, on_vduse_vq_kick, NULL, NULL, NULL, vq);
|
||||
on_vduse_vq_kick, NULL, NULL, NULL, vq);
|
||||
/* Make sure we don't miss any kick afer reconnecting */
|
||||
eventfd_write(vduse_queue_get_fd(vq), 1);
|
||||
}
|
||||
@@ -133,9 +145,14 @@ static void vduse_blk_enable_queue(VduseDev *dev, VduseVirtq *vq)
|
||||
static void vduse_blk_disable_queue(VduseDev *dev, VduseVirtq *vq)
|
||||
{
|
||||
VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev);
|
||||
int fd = vduse_queue_get_fd(vq);
|
||||
|
||||
aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq),
|
||||
true, NULL, NULL, NULL, NULL, NULL);
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
aio_set_fd_handler(vblk_exp->export.ctx, fd,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static const VduseOps vduse_blk_ops = {
|
||||
@@ -152,42 +169,19 @@ static void on_vduse_dev_kick(void *opaque)
|
||||
|
||||
static void vduse_blk_attach_ctx(VduseBlkExport *vblk_exp, AioContext *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev),
|
||||
true, on_vduse_dev_kick, NULL, NULL, NULL,
|
||||
on_vduse_dev_kick, NULL, NULL, NULL,
|
||||
vblk_exp->dev);
|
||||
|
||||
for (i = 0; i < vblk_exp->num_queues; i++) {
|
||||
VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
|
||||
int fd = vduse_queue_get_fd(vq);
|
||||
|
||||
if (fd < 0) {
|
||||
continue;
|
||||
}
|
||||
aio_set_fd_handler(vblk_exp->export.ctx, fd, true,
|
||||
on_vduse_vq_kick, NULL, NULL, NULL, vq);
|
||||
}
|
||||
/* Virtqueues are handled by vduse_blk_drained_end() */
|
||||
}
|
||||
|
||||
static void vduse_blk_detach_ctx(VduseBlkExport *vblk_exp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vblk_exp->num_queues; i++) {
|
||||
VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
|
||||
int fd = vduse_queue_get_fd(vq);
|
||||
|
||||
if (fd < 0) {
|
||||
continue;
|
||||
}
|
||||
aio_set_fd_handler(vblk_exp->export.ctx, fd,
|
||||
true, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev),
|
||||
true, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
AIO_WAIT_WHILE(vblk_exp->export.ctx, vblk_exp->inflight > 0);
|
||||
/* Virtqueues are handled by vduse_blk_drained_begin() */
|
||||
}
|
||||
|
||||
|
||||
@@ -220,8 +214,55 @@ static void vduse_blk_resize(void *opaque)
|
||||
(char *)&config.capacity);
|
||||
}
|
||||
|
||||
static void vduse_blk_stop_virtqueues(VduseBlkExport *vblk_exp)
|
||||
{
|
||||
for (uint16_t i = 0; i < vblk_exp->num_queues; i++) {
|
||||
VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
|
||||
vduse_blk_disable_queue(vblk_exp->dev, vq);
|
||||
}
|
||||
|
||||
vblk_exp->vqs_started = false;
|
||||
}
|
||||
|
||||
static void vduse_blk_start_virtqueues(VduseBlkExport *vblk_exp)
|
||||
{
|
||||
vblk_exp->vqs_started = true;
|
||||
|
||||
for (uint16_t i = 0; i < vblk_exp->num_queues; i++) {
|
||||
VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
|
||||
vduse_blk_enable_queue(vblk_exp->dev, vq);
|
||||
}
|
||||
}
|
||||
|
||||
static void vduse_blk_drained_begin(void *opaque)
|
||||
{
|
||||
BlockExport *exp = opaque;
|
||||
VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
|
||||
|
||||
vduse_blk_stop_virtqueues(vblk_exp);
|
||||
}
|
||||
|
||||
static void vduse_blk_drained_end(void *opaque)
|
||||
{
|
||||
BlockExport *exp = opaque;
|
||||
VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
|
||||
|
||||
vduse_blk_start_virtqueues(vblk_exp);
|
||||
}
|
||||
|
||||
static bool vduse_blk_drained_poll(void *opaque)
|
||||
{
|
||||
BlockExport *exp = opaque;
|
||||
VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
|
||||
|
||||
return qatomic_read(&vblk_exp->inflight) > 0;
|
||||
}
|
||||
|
||||
static const BlockDevOps vduse_block_ops = {
|
||||
.resize_cb = vduse_blk_resize,
|
||||
.resize_cb = vduse_blk_resize,
|
||||
.drained_begin = vduse_blk_drained_begin,
|
||||
.drained_end = vduse_blk_drained_end,
|
||||
.drained_poll = vduse_blk_drained_poll,
|
||||
};
|
||||
|
||||
static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
|
||||
@@ -268,6 +309,7 @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
|
||||
vblk_exp->handler.serial = g_strdup(vblk_opts->serial ?: "");
|
||||
vblk_exp->handler.logical_block_size = logical_block_size;
|
||||
vblk_exp->handler.writable = opts->writable;
|
||||
vblk_exp->vqs_started = true;
|
||||
|
||||
config.capacity =
|
||||
cpu_to_le64(blk_getlength(exp->blk) >> VIRTIO_BLK_SECTOR_BITS);
|
||||
@@ -322,14 +364,20 @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
|
||||
vduse_dev_setup_queue(vblk_exp->dev, i, queue_size);
|
||||
}
|
||||
|
||||
aio_set_fd_handler(exp->ctx, vduse_dev_get_fd(vblk_exp->dev), true,
|
||||
aio_set_fd_handler(exp->ctx, vduse_dev_get_fd(vblk_exp->dev),
|
||||
on_vduse_dev_kick, NULL, NULL, NULL, vblk_exp->dev);
|
||||
|
||||
blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
|
||||
vblk_exp);
|
||||
|
||||
blk_set_dev_ops(exp->blk, &vduse_block_ops, exp);
|
||||
|
||||
/*
|
||||
* We handle draining ourselves using an in-flight counter and by disabling
|
||||
* virtqueue fd handlers. Do not queue BlockBackend requests, they need to
|
||||
* complete so the in-flight counter reaches zero.
|
||||
*/
|
||||
blk_set_disable_request_queuing(exp->blk, true);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
vduse_dev_destroy(vblk_exp->dev);
|
||||
@@ -344,6 +392,9 @@ static void vduse_blk_exp_delete(BlockExport *exp)
|
||||
VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
|
||||
int ret;
|
||||
|
||||
assert(qatomic_read(&vblk_exp->inflight) == 0);
|
||||
|
||||
vduse_blk_detach_ctx(vblk_exp);
|
||||
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
|
||||
vblk_exp);
|
||||
ret = vduse_dev_destroy(vblk_exp->dev);
|
||||
@@ -354,13 +405,12 @@ static void vduse_blk_exp_delete(BlockExport *exp)
|
||||
g_free(vblk_exp->handler.serial);
|
||||
}
|
||||
|
||||
/* Called with exp->ctx acquired */
|
||||
static void vduse_blk_exp_request_shutdown(BlockExport *exp)
|
||||
{
|
||||
VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
|
||||
|
||||
aio_context_acquire(vblk_exp->export.ctx);
|
||||
vduse_blk_detach_ctx(vblk_exp);
|
||||
aio_context_acquire(vblk_exp->export.ctx);
|
||||
vduse_blk_stop_virtqueues(vblk_exp);
|
||||
}
|
||||
|
||||
const BlockExportDriver blk_exp_vduse_blk = {
|
||||
|
||||
@@ -50,7 +50,10 @@ static void vu_blk_req_complete(VuBlkReq *req, size_t in_len)
|
||||
free(req);
|
||||
}
|
||||
|
||||
/* Called with server refcount increased, must decrease before returning */
|
||||
/*
|
||||
* Called with server in_flight counter increased, must decrease before
|
||||
* returning.
|
||||
*/
|
||||
static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
|
||||
{
|
||||
VuBlkReq *req = opaque;
|
||||
@@ -68,12 +71,12 @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
|
||||
in_num, out_num);
|
||||
if (in_len < 0) {
|
||||
free(req);
|
||||
vhost_user_server_unref(server);
|
||||
vhost_user_server_dec_in_flight(server);
|
||||
return;
|
||||
}
|
||||
|
||||
vu_blk_req_complete(req, in_len);
|
||||
vhost_user_server_unref(server);
|
||||
vhost_user_server_dec_in_flight(server);
|
||||
}
|
||||
|
||||
static void vu_blk_process_vq(VuDev *vu_dev, int idx)
|
||||
@@ -95,7 +98,7 @@ static void vu_blk_process_vq(VuDev *vu_dev, int idx)
|
||||
Coroutine *co =
|
||||
qemu_coroutine_create(vu_blk_virtio_process_req, req);
|
||||
|
||||
vhost_user_server_ref(server);
|
||||
vhost_user_server_inc_in_flight(server);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
}
|
||||
@@ -209,15 +212,21 @@ static void blk_aio_attached(AioContext *ctx, void *opaque)
|
||||
{
|
||||
VuBlkExport *vexp = opaque;
|
||||
|
||||
/*
|
||||
* The actual attach will happen in vu_blk_drained_end() and we just
|
||||
* restore ctx here.
|
||||
*/
|
||||
vexp->export.ctx = ctx;
|
||||
vhost_user_server_attach_aio_context(&vexp->vu_server, ctx);
|
||||
}
|
||||
|
||||
static void blk_aio_detach(void *opaque)
|
||||
{
|
||||
VuBlkExport *vexp = opaque;
|
||||
|
||||
vhost_user_server_detach_aio_context(&vexp->vu_server);
|
||||
/*
|
||||
* The actual detach already happened in vu_blk_drained_begin() but from
|
||||
* this point on we must not access ctx anymore.
|
||||
*/
|
||||
vexp->export.ctx = NULL;
|
||||
}
|
||||
|
||||
@@ -269,7 +278,38 @@ static void vu_blk_exp_resize(void *opaque)
|
||||
vu_config_change_msg(&vexp->vu_server.vu_dev);
|
||||
}
|
||||
|
||||
/* Called with vexp->export.ctx acquired */
|
||||
static void vu_blk_drained_begin(void *opaque)
|
||||
{
|
||||
VuBlkExport *vexp = opaque;
|
||||
|
||||
vhost_user_server_detach_aio_context(&vexp->vu_server);
|
||||
}
|
||||
|
||||
/* Called with vexp->export.blk AioContext acquired */
|
||||
static void vu_blk_drained_end(void *opaque)
|
||||
{
|
||||
VuBlkExport *vexp = opaque;
|
||||
|
||||
vhost_user_server_attach_aio_context(&vexp->vu_server, vexp->export.ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensures that bdrv_drained_begin() waits until in-flight requests complete.
|
||||
*
|
||||
* Called with vexp->export.ctx acquired.
|
||||
*/
|
||||
static bool vu_blk_drained_poll(void *opaque)
|
||||
{
|
||||
VuBlkExport *vexp = opaque;
|
||||
|
||||
return vhost_user_server_has_in_flight(&vexp->vu_server);
|
||||
}
|
||||
|
||||
static const BlockDevOps vu_blk_dev_ops = {
|
||||
.drained_begin = vu_blk_drained_begin,
|
||||
.drained_end = vu_blk_drained_end,
|
||||
.drained_poll = vu_blk_drained_poll,
|
||||
.resize_cb = vu_blk_exp_resize,
|
||||
};
|
||||
|
||||
|
||||
+10
-6
@@ -60,7 +60,7 @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
|
||||
|
||||
void bdrv_parent_drained_end_single(BdrvChild *c)
|
||||
{
|
||||
IO_OR_GS_CODE();
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
assert(c->quiesced_parent);
|
||||
c->quiesced_parent = false;
|
||||
@@ -108,7 +108,7 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
|
||||
|
||||
void bdrv_parent_drained_begin_single(BdrvChild *c)
|
||||
{
|
||||
IO_OR_GS_CODE();
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
assert(!c->quiesced_parent);
|
||||
c->quiesced_parent = true;
|
||||
@@ -247,7 +247,7 @@ typedef struct {
|
||||
bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
|
||||
bool ignore_bds_parents)
|
||||
{
|
||||
IO_OR_GS_CODE();
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) {
|
||||
return true;
|
||||
@@ -334,7 +334,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
|
||||
if (ctx != co_ctx) {
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
replay_bh_schedule_oneshot_event(ctx, bdrv_co_drain_bh_cb, &data);
|
||||
replay_bh_schedule_oneshot_event(qemu_get_aio_context(),
|
||||
bdrv_co_drain_bh_cb, &data);
|
||||
|
||||
qemu_coroutine_yield();
|
||||
/* If we are resumed from some other event (such as an aio completion or a
|
||||
@@ -357,9 +358,10 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
|
||||
return;
|
||||
}
|
||||
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
/* Stop things in parent-to-child order */
|
||||
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
|
||||
aio_disable_external(bdrv_get_aio_context(bs));
|
||||
bdrv_parent_drained_begin(bs, parent);
|
||||
if (bs->drv && bs->drv->bdrv_drain_begin) {
|
||||
bs->drv->bdrv_drain_begin(bs);
|
||||
@@ -399,11 +401,14 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
|
||||
{
|
||||
int old_quiesce_counter;
|
||||
|
||||
IO_OR_GS_CODE();
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_yield_to_drain(bs, false, parent, false);
|
||||
return;
|
||||
}
|
||||
assert(bs->quiesce_counter > 0);
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
/* Re-enable things in child-to-parent order */
|
||||
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
|
||||
@@ -412,7 +417,6 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
|
||||
bs->drv->bdrv_drain_end(bs);
|
||||
}
|
||||
bdrv_parent_drained_end(bs, parent);
|
||||
aio_enable_external(bdrv_get_aio_context(bs));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -410,7 +410,7 @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
|
||||
|
||||
void luring_detach_aio_context(LuringState *s, AioContext *old_context)
|
||||
{
|
||||
aio_set_fd_handler(old_context, s->ring.ring_fd, false,
|
||||
aio_set_fd_handler(old_context, s->ring.ring_fd,
|
||||
NULL, NULL, NULL, NULL, s);
|
||||
qemu_bh_delete(s->completion_bh);
|
||||
s->aio_context = NULL;
|
||||
@@ -420,7 +420,7 @@ void luring_attach_aio_context(LuringState *s, AioContext *new_context)
|
||||
{
|
||||
s->aio_context = new_context;
|
||||
s->completion_bh = aio_bh_new(new_context, qemu_luring_completion_bh, s);
|
||||
aio_set_fd_handler(s->aio_context, s->ring.ring_fd, false,
|
||||
aio_set_fd_handler(s->aio_context, s->ring.ring_fd,
|
||||
qemu_luring_completion_cb, NULL,
|
||||
qemu_luring_poll_cb, qemu_luring_poll_ready, s);
|
||||
}
|
||||
|
||||
+1
-2
@@ -363,7 +363,6 @@ iscsi_set_events(IscsiLun *iscsilun)
|
||||
|
||||
if (ev != iscsilun->events) {
|
||||
aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsi),
|
||||
false,
|
||||
(ev & POLLIN) ? iscsi_process_read : NULL,
|
||||
(ev & POLLOUT) ? iscsi_process_write : NULL,
|
||||
NULL, NULL,
|
||||
@@ -1540,7 +1539,7 @@ static void iscsi_detach_aio_context(BlockDriverState *bs)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsilun->iscsi),
|
||||
false, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
iscsilun->events = 0;
|
||||
|
||||
if (iscsilun->nop_timer) {
|
||||
|
||||
+2
-2
@@ -446,7 +446,7 @@ int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
|
||||
|
||||
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
|
||||
{
|
||||
aio_set_event_notifier(old_context, &s->e, false, NULL, NULL, NULL);
|
||||
aio_set_event_notifier(old_context, &s->e, NULL, NULL, NULL);
|
||||
qemu_bh_delete(s->completion_bh);
|
||||
s->aio_context = NULL;
|
||||
}
|
||||
@@ -455,7 +455,7 @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
|
||||
{
|
||||
s->aio_context = new_context;
|
||||
s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s);
|
||||
aio_set_event_notifier(new_context, &s->e, false,
|
||||
aio_set_event_notifier(new_context, &s->e,
|
||||
qemu_laio_completion_cb,
|
||||
qemu_laio_poll_cb,
|
||||
qemu_laio_poll_ready);
|
||||
|
||||
@@ -662,11 +662,15 @@ static int mirror_exit_common(Job *job)
|
||||
bool abort = job->ret < 0;
|
||||
int ret = 0;
|
||||
|
||||
GLOBAL_STATE_CODE();
|
||||
|
||||
if (s->prepared) {
|
||||
return 0;
|
||||
}
|
||||
s->prepared = true;
|
||||
|
||||
aio_context_acquire(qemu_get_aio_context());
|
||||
|
||||
mirror_top_bs = s->mirror_top_bs;
|
||||
bs_opaque = mirror_top_bs->opaque;
|
||||
src = mirror_top_bs->backing->bs;
|
||||
@@ -789,6 +793,8 @@ static int mirror_exit_common(Job *job)
|
||||
bdrv_unref(mirror_top_bs);
|
||||
bdrv_unref(src);
|
||||
|
||||
aio_context_release(qemu_get_aio_context());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -195,7 +195,6 @@ static void nfs_set_events(NFSClient *client)
|
||||
int ev = nfs_which_events(client->context);
|
||||
if (ev != client->events) {
|
||||
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
|
||||
false,
|
||||
(ev & POLLIN) ? nfs_process_read : NULL,
|
||||
(ev & POLLOUT) ? nfs_process_write : NULL,
|
||||
NULL, NULL, client);
|
||||
@@ -373,7 +372,7 @@ static void nfs_detach_aio_context(BlockDriverState *bs)
|
||||
NFSClient *client = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
|
||||
false, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
client->events = 0;
|
||||
}
|
||||
|
||||
@@ -391,7 +390,7 @@ static void nfs_client_close(NFSClient *client)
|
||||
if (client->context) {
|
||||
qemu_mutex_lock(&client->mutex);
|
||||
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
|
||||
false, NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
qemu_mutex_unlock(&client->mutex);
|
||||
if (client->fh) {
|
||||
nfs_close(client->context, client->fh);
|
||||
|
||||
+4
-4
@@ -862,7 +862,7 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
|
||||
}
|
||||
aio_set_event_notifier(bdrv_get_aio_context(bs),
|
||||
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
|
||||
false, nvme_handle_event, nvme_poll_cb,
|
||||
nvme_handle_event, nvme_poll_cb,
|
||||
nvme_poll_ready);
|
||||
|
||||
if (!nvme_identify(bs, namespace, errp)) {
|
||||
@@ -948,7 +948,7 @@ static void nvme_close(BlockDriverState *bs)
|
||||
g_free(s->queues);
|
||||
aio_set_event_notifier(bdrv_get_aio_context(bs),
|
||||
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
|
||||
false, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]);
|
||||
qemu_vfio_pci_unmap_bar(s->vfio, 0, s->bar0_wo_map,
|
||||
0, sizeof(NvmeBar) + NVME_DOORBELL_SIZE);
|
||||
@@ -1546,7 +1546,7 @@ static void nvme_detach_aio_context(BlockDriverState *bs)
|
||||
|
||||
aio_set_event_notifier(bdrv_get_aio_context(bs),
|
||||
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
|
||||
false, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void nvme_attach_aio_context(BlockDriverState *bs,
|
||||
@@ -1556,7 +1556,7 @@ static void nvme_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
s->aio_context = new_context;
|
||||
aio_set_event_notifier(new_context, &s->irq_notifier[MSIX_SHARED_IRQ_IDX],
|
||||
false, nvme_handle_event, nvme_poll_cb,
|
||||
nvme_handle_event, nvme_poll_cb,
|
||||
nvme_poll_ready);
|
||||
|
||||
for (unsigned i = 0; i < s->queue_count; i++) {
|
||||
|
||||
@@ -362,7 +362,10 @@ void qmp_blockdev_change_medium(const char *device,
|
||||
qdict_put_str(options, "driver", format);
|
||||
}
|
||||
|
||||
aio_context_acquire(qemu_get_aio_context());
|
||||
medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
|
||||
aio_context_release(qemu_get_aio_context());
|
||||
|
||||
if (!medium_bs) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+6
-2
@@ -1904,6 +1904,8 @@ static void coroutine_fn qcow2_open_entry(void *opaque)
|
||||
qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true,
|
||||
qoc->errp);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
@@ -1929,8 +1931,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
assert(!qemu_in_coroutine());
|
||||
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
qemu_coroutine_enter(qemu_coroutine_create(qcow2_open_entry, &qoc));
|
||||
BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
|
||||
|
||||
aio_co_enter(bdrv_get_aio_context(bs),
|
||||
qemu_coroutine_create(qcow2_open_entry, &qoc));
|
||||
AIO_WAIT_WHILE_UNLOCKED(NULL, qoc.ret == -EINPROGRESS);
|
||||
|
||||
return qoc.ret;
|
||||
}
|
||||
|
||||
@@ -468,6 +468,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
AioContext *ctx;
|
||||
bool has_size;
|
||||
uint64_t offset, size;
|
||||
BdrvChildRole file_role;
|
||||
@@ -515,7 +516,11 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
bs->file->bs->filename);
|
||||
}
|
||||
|
||||
ctx = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(ctx);
|
||||
ret = raw_apply_options(bs, s, offset, has_size, size, errp);
|
||||
aio_context_release(ctx);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1019,7 +1019,7 @@ static void restart_coroutine(void *opaque)
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
trace_ssh_restart_coroutine(restart->co);
|
||||
aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL, NULL);
|
||||
aio_set_fd_handler(ctx, s->sock, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
aio_co_wake(restart->co);
|
||||
}
|
||||
@@ -1049,7 +1049,7 @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
|
||||
trace_ssh_co_yield(s->sock, rd_handler, wr_handler);
|
||||
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
|
||||
false, rd_handler, wr_handler, NULL, NULL, &restart);
|
||||
rd_handler, wr_handler, NULL, NULL, &restart);
|
||||
qemu_coroutine_yield();
|
||||
trace_ssh_co_yield_back(s->sock);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user