#include "block/block_int.h"
#include "block/blockjob.h"
#include "block/throttle-groups.h"
+#include "hw/qdev-core.h"
#include "sysemu/blockdev.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
#include "qapi/qapi-events-block.h"
#include "qemu/id.h"
+#include "qemu/main-loop.h"
#include "qemu/option.h"
#include "trace.h"
#include "migration/misc.h"
char *name;
int refcnt;
BdrvChild *root;
+ AioContext *ctx;
DriveInfo *legacy_dinfo; /* null unless created by drive_new() */
QTAILQ_ENTRY(BlockBackend) link; /* for block_backends */
QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */
}
static void blk_root_drained_begin(BdrvChild *child);
static bool blk_root_drained_poll(BdrvChild *child);
-static void blk_root_drained_end(BdrvChild *child);
+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);
*
* Return the new BlockBackend on success, null on failure.
*/
-BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
+BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
{
BlockBackend *blk;
blk = g_new0(BlockBackend, 1);
blk->refcnt = 1;
+ blk->ctx = ctx;
blk->perm = perm;
blk->shared_perm = shared_perm;
blk_set_enable_write_cache(blk, true);
/*
* Creates a new BlockBackend, opens a new BlockDriverState, and connects both.
+ * The new BlockBackend is in the main AioContext.
*
* Just as with bdrv_open(), after having called this function the reference to
* @options belongs to the block layer (even on failure).
perm |= BLK_PERM_RESIZE;
}
- blk = blk_new(perm, BLK_PERM_ALL);
+ blk = blk_new(qemu_get_aio_context(), perm, BLK_PERM_ALL);
bs = bdrv_open(filename, reference, options, flags, errp);
if (!bs) {
blk_unref(blk);
return NULL;
}
- blk->root = bdrv_root_attach_child(bs, "root", &child_root,
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
perm, BLK_PERM_ALL, blk, errp);
if (!blk->root) {
blk_unref(blk);
{
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
bdrv_ref(bs);
- blk->root = bdrv_root_attach_child(bs, "root", &child_root,
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
blk->perm, blk->shared_perm, blk, errp);
if (blk->root == NULL) {
return -EPERM;
void blk_iostatus_reset(BlockBackend *blk)
{
if (blk_iostatus_is_enabled(blk)) {
- BlockDriverState *bs = blk_bs(blk);
blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
- if (bs && bs->job) {
- block_job_iostatus_reset(bs->job);
- }
}
}
blk_root_drained_begin(blk->root);
ret = blk_pread(blk, offset, buf, count);
- blk_root_drained_end(blk->root);
+ blk_root_drained_end(blk->root, NULL);
return ret;
}
AioContext *blk_get_aio_context(BlockBackend *blk)
{
- return bdrv_get_aio_context(blk_bs(blk));
+ BlockDriverState *bs = blk_bs(blk);
+
+ if (bs) {
+ AioContext *ctx = bdrv_get_aio_context(blk_bs(blk));
+ assert(ctx == blk->ctx);
+ }
+
+ return blk->ctx;
}
static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
return blk_get_aio_context(blk_acb->blk);
}
-static void blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
- bool update_root_node)
+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) {
+ if (update_root_node) {
+ ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root,
+ errp);
+ if (ret < 0) {
+ return ret;
+ }
+ }
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);
}
- if (update_root_node) {
- GSList *ignore = g_slist_prepend(NULL, blk->root);
- bdrv_set_aio_context_ignore(bs, new_context, &ignore);
- g_slist_free(ignore);
- }
}
+
+ blk->ctx = new_context;
+ return 0;
}
-void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
+int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
+ Error **errp)
{
- blk_do_set_aio_context(blk, new_context, true);
+ 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)
{
BlockBackend *blk = child->opaque;
- blk_do_set_aio_context(blk, ctx, false);
+ blk_do_set_aio_context(blk, ctx, false, &error_abort);
}
void blk_add_aio_context_notifier(BlockBackend *blk,
return !!blk->in_flight;
}
-static void blk_root_drained_end(BdrvChild *child)
+static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter)
{
BlockBackend *blk = child->opaque;
assert(blk->quiesce_counter);