const BlockDevOps *dev_ops;
void *dev_opaque;
- /* the block size for which the guest device expects atomicity */
- int guest_block_size;
-
/* If the BDS tree is removed, some of its options are stored here (which
* can be used to restore those options in the new BDS on insert) */
BlockBackendRootState root_state;
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)
{
static AioContext *blk_root_get_parent_aio_context(BdrvChild *c)
{
BlockBackend *blk = c->opaque;
+ IO_CODE();
return blk_get_aio_context(blk);
}
.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,
};
blk->dev = NULL;
blk->dev_ops = NULL;
blk->dev_opaque = NULL;
- blk->guest_block_size = 512;
blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort);
blk_unref(blk);
}
blk->dev_opaque = opaque;
/* Are we currently quiesced? Should we enforce this right now? */
- if (blk->quiesce_counter && ops->drained_begin) {
+ if (blk->quiesce_counter && ops && ops->drained_begin) {
ops->drained_begin(opaque);
}
}
}
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
-int coroutine_fn
-blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes,
- QEMUIOVector *qiov, BdrvRequestFlags flags)
+static int coroutine_fn
+blk_co_do_preadv_part(BlockBackend *blk, int64_t offset, int64_t bytes,
+ QEMUIOVector *qiov, size_t qiov_offset,
+ BdrvRequestFlags flags)
{
int ret;
BlockDriverState *bs;
+ IO_CODE();
blk_wait_while_drained(blk);
bytes, false);
}
- ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
+ ret = bdrv_co_preadv_part(blk->root, offset, bytes, qiov, qiov_offset,
+ flags);
bdrv_dec_in_flight(bs);
return ret;
}
+int coroutine_fn blk_co_pread(BlockBackend *blk, int64_t offset, int64_t bytes,
+ void *buf, BdrvRequestFlags flags)
+{
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
+ IO_OR_GS_CODE();
+
+ assert(bytes <= SIZE_MAX);
+
+ return blk_co_preadv(blk, offset, bytes, &qiov, flags);
+}
+
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags)
IO_OR_GS_CODE();
blk_inc_in_flight(blk);
- ret = blk_co_do_preadv(blk, offset, bytes, qiov, flags);
+ ret = blk_co_do_preadv_part(blk, offset, bytes, qiov, 0, flags);
+ blk_dec_in_flight(blk);
+
+ return ret;
+}
+
+int coroutine_fn blk_co_preadv_part(BlockBackend *blk, int64_t offset,
+ int64_t bytes, QEMUIOVector *qiov,
+ size_t qiov_offset, BdrvRequestFlags flags)
+{
+ int ret;
+ IO_OR_GS_CODE();
+
+ blk_inc_in_flight(blk);
+ ret = blk_co_do_preadv_part(blk, offset, bytes, qiov, qiov_offset, flags);
blk_dec_in_flight(blk);
return ret;
}
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
-int coroutine_fn
+static int coroutine_fn
blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset,
BdrvRequestFlags flags)
{
int ret;
BlockDriverState *bs;
+ IO_CODE();
blk_wait_while_drained(blk);
return ret;
}
+int coroutine_fn blk_co_pwrite(BlockBackend *blk, int64_t offset, int64_t bytes,
+ const void *buf, BdrvRequestFlags flags)
+{
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
+ IO_OR_GS_CODE();
+
+ assert(bytes <= SIZE_MAX);
+
+ return blk_co_pwritev(blk, offset, bytes, &qiov, flags);
+}
+
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags)
return blk_co_pwritev_part(blk, offset, bytes, qiov, 0, flags);
}
-static int coroutine_fn blk_pwritev_part(BlockBackend *blk, int64_t offset,
- int64_t bytes,
- QEMUIOVector *qiov, size_t qiov_offset,
- BdrvRequestFlags flags)
-{
- int ret;
-
- blk_inc_in_flight(blk);
- ret = blk_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags);
- blk_dec_in_flight(blk);
-
- return ret;
-}
-
typedef struct BlkRwCo {
BlockBackend *blk;
int64_t offset;
BdrvRequestFlags flags;
} BlkRwCo;
-int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset,
- int64_t bytes, BdrvRequestFlags flags)
-{
- IO_OR_GS_CODE();
- return blk_pwritev_part(blk, offset, bytes, NULL, 0,
- flags | BDRV_REQ_ZERO_WRITE);
-}
-
int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
{
GLOBAL_STATE_CODE();
return &acb->common;
}
-static void blk_aio_read_entry(void *opaque)
+static void coroutine_fn blk_aio_read_entry(void *opaque)
{
BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco;
QEMUIOVector *qiov = rwco->iobuf;
assert(qiov->size == acb->bytes);
- rwco->ret = blk_co_do_preadv(rwco->blk, rwco->offset, acb->bytes,
- qiov, rwco->flags);
+ rwco->ret = blk_co_do_preadv_part(rwco->blk, rwco->offset, acb->bytes, qiov,
+ 0, rwco->flags);
blk_aio_complete(acb);
}
-static void blk_aio_write_entry(void *opaque)
+static void coroutine_fn blk_aio_write_entry(void *opaque)
{
BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco;
flags | BDRV_REQ_ZERO_WRITE, cb, opaque);
}
-int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int bytes)
-{
- int ret;
- QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
- IO_OR_GS_CODE();
-
- blk_inc_in_flight(blk);
- ret = blk_do_preadv(blk, offset, bytes, &qiov, 0);
- blk_dec_in_flight(blk);
-
- return ret < 0 ? ret : bytes;
-}
-
-int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes,
- BdrvRequestFlags flags)
-{
- int ret;
- QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
- IO_OR_GS_CODE();
-
- ret = blk_pwritev_part(blk, offset, bytes, &qiov, 0, flags);
-
- return ret < 0 ? ret : bytes;
-}
-
int64_t blk_getlength(BlockBackend *blk)
{
IO_CODE();
}
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
-int coroutine_fn
+static int coroutine_fn
blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{
+ IO_CODE();
+
blk_wait_while_drained(blk);
if (!blk_is_available(blk)) {
return bdrv_co_ioctl(blk_bs(blk), req, buf);
}
-int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
+int coroutine_fn blk_co_ioctl(BlockBackend *blk, unsigned long int req,
+ void *buf)
{
int ret;
IO_OR_GS_CODE();
blk_inc_in_flight(blk);
- ret = blk_do_ioctl(blk, req, buf);
+ ret = blk_co_do_ioctl(blk, req, buf);
blk_dec_in_flight(blk);
return ret;
}
-static void blk_aio_ioctl_entry(void *opaque)
+static void coroutine_fn blk_aio_ioctl_entry(void *opaque)
{
BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco;
}
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
-int coroutine_fn
+static int coroutine_fn
blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
{
int ret;
+ IO_CODE();
blk_wait_while_drained(blk);
return bdrv_co_pdiscard(blk->root, offset, bytes);
}
-static void blk_aio_pdiscard_entry(void *opaque)
+static void coroutine_fn blk_aio_pdiscard_entry(void *opaque)
{
BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco;
return ret;
}
-int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
-{
- int ret;
- IO_OR_GS_CODE();
-
- blk_inc_in_flight(blk);
- ret = blk_do_pdiscard(blk, offset, bytes);
- blk_dec_in_flight(blk);
-
- return ret;
-}
-
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
-int coroutine_fn blk_co_do_flush(BlockBackend *blk)
+static int coroutine_fn blk_co_do_flush(BlockBackend *blk)
{
blk_wait_while_drained(blk);
+ IO_CODE();
if (!blk_is_available(blk)) {
return -ENOMEDIUM;
return bdrv_co_flush(blk_bs(blk));
}
-static void blk_aio_flush_entry(void *opaque)
+static void coroutine_fn blk_aio_flush_entry(void *opaque)
{
BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco;
return ret;
}
-int blk_flush(BlockBackend *blk)
-{
- int ret;
-
- blk_inc_in_flight(blk);
- ret = blk_do_flush(blk);
- blk_dec_in_flight(blk);
-
- return ret;
-}
-
void blk_drain(BlockBackend *blk)
{
BlockDriverState *bs = blk_bs(blk);
BlockDriverState *bs = blk_bs(blk);
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
- qapi_event_send_block_io_error(blk_name(blk), !!bs,
+ qapi_event_send_block_io_error(blk_name(blk),
bs ? bdrv_get_node_name(bs) : NULL, optype,
action, blk_iostatus_is_enabled(blk),
error == ENOSPC, strerror(error));
void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
{
- GLOBAL_STATE_CODE();
+ IO_CODE();
blk->enable_write_cache = wce;
}
return blk->root->bs->bl.max_iov;
}
-void blk_set_guest_block_size(BlockBackend *blk, int align)
-{
- IO_CODE();
- blk->guest_block_size = align;
-}
-
void *blk_try_blockalign(BlockBackend *blk, size_t size)
{
IO_CODE();
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;
}
}
+ /*
+ * 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);
}
bdrv_unref(bs);
+ } else {
+ blk->ctx = new_context;
}
- blk->ctx = new_context;
return 0;
}
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)
+{
+ BdrvStateBlkRootContext *s = opaque;
+ BlockBackend *blk = s->blk;
+
+ blk_do_set_aio_context(blk, s->new_ctx, false, &error_abort);
+}
+
+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;
+ BdrvStateBlkRootContext *s;
- if (blk->allow_aio_context_change) {
- return true;
+ 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;
+ }
}
- /* 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;
- }
+ s = g_new(BdrvStateBlkRootContext, 1);
+ *s = (BdrvStateBlkRootContext) {
+ .new_ctx = ctx,
+ .blk = blk,
+ };
+ tran_add(tran, &set_blk_root_context, s);
return true;
}
-static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
- GSList **ignore)
-{
- BlockBackend *blk = child->opaque;
- blk_do_set_aio_context(blk, ctx, false, &error_abort);
-}
-
void blk_add_aio_context_notifier(BlockBackend *blk,
void (*attached_aio_context)(AioContext *new_context, void *opaque),
void (*detach_aio_context)(void *opaque), void *opaque)
flags | BDRV_REQ_ZERO_WRITE);
}
-int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
- int64_t bytes)
+int coroutine_fn blk_co_pwrite_compressed(BlockBackend *blk, int64_t offset,
+ int64_t bytes, const void *buf)
{
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
IO_OR_GS_CODE();
- return blk_pwritev_part(blk, offset, bytes, &qiov, 0,
- BDRV_REQ_WRITE_COMPRESSED);
+ return blk_co_pwritev_part(blk, offset, bytes, &qiov, 0,
+ BDRV_REQ_WRITE_COMPRESSED);
}
-int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
- PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
+int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact,
+ PreallocMode prealloc, BdrvRequestFlags flags,
+ Error **errp)
{
IO_OR_GS_CODE();
if (!blk_is_available(blk)) {
return -ENOMEDIUM;
}
- return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
+ return bdrv_co_truncate(blk->root, offset, exact, prealloc, flags, errp);
}
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
}
}
-void blk_register_buf(BlockBackend *blk, void *host, size_t size)
+bool blk_register_buf(BlockBackend *blk, void *host, size_t size, Error **errp)
{
+ BlockDriverState *bs = blk_bs(blk);
+
GLOBAL_STATE_CODE();
- bdrv_register_buf(blk_bs(blk), host, size);
+
+ if (bs) {
+ return bdrv_register_buf(bs, host, size, errp);
+ }
+ return true;
}
-void blk_unregister_buf(BlockBackend *blk, void *host)
+void blk_unregister_buf(BlockBackend *blk, void *host, size_t size)
{
+ BlockDriverState *bs = blk_bs(blk);
+
GLOBAL_STATE_CODE();
- bdrv_unregister_buf(blk_bs(blk), host);
+
+ if (bs) {
+ bdrv_unregister_buf(bs, host, size);
+ }
}
int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,