#include "block/trace.h"
#include "block/block_int.h"
#include "block/blockjob.h"
+#include "block/dirty-bitmap.h"
#include "block/fuse.h"
#include "block/nbd.h"
#include "block/qdict.h"
return !(bs->open_flags & BDRV_O_RDWR);
}
-int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
- bool ignore_allow_rdw, Error **errp)
+static int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
+ bool ignore_allow_rdw, Error **errp)
{
IO_CODE();
* On success, return @blk's actual length.
* Otherwise, return -errno.
*/
-static int64_t create_file_fallback_truncate(BlockBackend *blk,
- int64_t minimum_size, Error **errp)
+static int64_t coroutine_fn GRAPH_UNLOCKED
+create_file_fallback_truncate(BlockBackend *blk, int64_t minimum_size,
+ Error **errp)
{
Error *local_err = NULL;
int64_t size;
GLOBAL_STATE_CODE();
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
- &local_err);
+ ret = blk_co_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
+ &local_err);
if (ret < 0 && ret != -ENOTSUP) {
error_propagate(errp, local_err);
return ret;
}
- size = blk_getlength(blk);
+ size = blk_co_getlength(blk);
if (size < 0) {
error_free(local_err);
error_setg_errno(errp, -size,
options = qdict_new();
qdict_put_str(options, "driver", drv->format_name);
- blk = blk_new_open(filename, NULL, options,
- BDRV_O_RDWR | BDRV_O_RESIZE, errp);
+ blk = blk_co_new_open(filename, NULL, options,
+ BDRV_O_RDWR | BDRV_O_RESIZE, errp);
if (!blk) {
error_prepend(errp, "Protocol driver '%s' does not support image "
"creation, and opening the image failed: ",
ret = 0;
out:
- blk_unref(blk);
+ blk_co_unref(blk);
return ret;
}
IO_CODE();
assert(bs != NULL);
+ assert_bdrv_graph_readable();
if (!bs->drv) {
error_setg(errp, "Block node '%s' is not opened", bs->filename);
* Set the current 'total_sectors' value
* Return 0 on success, -errno on error.
*/
-int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
+int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs,
+ int64_t hint)
{
BlockDriver *drv = bs->drv;
IO_CODE();
+ assert_bdrv_graph_readable();
if (!drv) {
return -ENOMEDIUM;
}
- /* Do not attempt drv->bdrv_getlength() on scsi-generic devices */
+ /* Do not attempt drv->bdrv_co_getlength() on scsi-generic devices */
if (bdrv_is_sg(bs))
return 0;
/* query actual device if possible, otherwise just trust the hint */
- if (drv->bdrv_getlength) {
- int64_t length = drv->bdrv_getlength(bs);
+ if (drv->bdrv_co_getlength) {
+ int64_t length = drv->bdrv_co_getlength(bs);
if (length < 0) {
return length;
}
g_free(gen_node_name);
}
-static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
- const char *node_name, QDict *options,
- int open_flags, Error **errp)
+/*
+ * The caller must always hold @bs AioContext lock, because this function calls
+ * bdrv_refresh_total_sectors() which polls when called from non-coroutine
+ * context.
+ */
+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();
bs->supported_read_flags |= BDRV_REQ_REGISTERED_BUF;
bs->supported_write_flags |= BDRV_REQ_REGISTERED_BUF;
- ret = refresh_total_sectors(bs, bs->total_sectors);
+ /* 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);
return -EINVAL;
* Replaces the node that a BdrvChild points to without updating permissions.
*
* If @new_bs is non-NULL, the parent of @child must already be drained through
- * @child.
+ * @child and the caller must hold the AioContext lock for @new_bs.
*/
static void bdrv_replace_child_noperm(BdrvChild *child,
BlockDriverState *new_bs)
}
/* TODO Pull this up into the callers to avoid polling here */
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock(new_bs);
if (old_bs) {
if (child->klass->detach) {
child->klass->detach(child);
* Function doesn't update permissions, caller is responsible for this.
*
* Returns new created child.
+ *
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
+ * @child_bs can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
*/
static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
const char *child_name,
Transaction *tran, Error **errp)
{
BdrvChild *new_child;
- AioContext *parent_ctx;
+ AioContext *parent_ctx, *new_child_ctx;
AioContext *child_ctx = bdrv_get_aio_context(child_bs);
assert(child_class->get_parent_desc);
}
}
+ new_child_ctx = bdrv_get_aio_context(child_bs);
+ if (new_child_ctx != child_ctx) {
+ aio_context_release(child_ctx);
+ aio_context_acquire(new_child_ctx);
+ }
+
bdrv_ref(child_bs);
/*
* Let every new BdrvChild start with a drained parent. Inserting the child
};
tran_add(tran, &bdrv_attach_child_common_drv, s);
+ if (new_child_ctx != child_ctx) {
+ aio_context_release(new_child_ctx);
+ aio_context_acquire(child_ctx);
+ }
+
return new_child;
}
/*
* Function doesn't update permissions, caller is responsible for this.
+ *
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
+ * @child_bs can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
*/
static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
* callers which don't need their own reference any more must call bdrv_unref().
*
* Function doesn't update permissions, caller is responsible for this.
+ *
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
+ * @child_bs can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
*/
static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
}
out:
+ bdrv_graph_rdlock_main_loop();
bdrv_refresh_limits(parent_bs, tran, NULL);
+ bdrv_graph_rdunlock_main_loop();
return 0;
}
+/*
+ * The caller must hold the AioContext lock for @backing_hd. Both @bs and
+ * @backing_hd can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
+ */
static int bdrv_set_backing_noperm(BlockDriverState *bs,
BlockDriverState *backing_hd,
Transaction *tran, Error **errp)
* 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,
int ret = 0;
bool implicit_backing = false;
BlockDriverState *backing_hd;
+ AioContext *backing_hd_ctx;
QDict *options;
QDict *tmp_parent_options = NULL;
Error *local_err = NULL;
/* Hook up the backing file link; drop our reference, bs owns the
* backing_hd reference now */
+ backing_hd_ctx = bdrv_get_aio_context(backing_hd);
+ aio_context_acquire(backing_hd_ctx);
ret = bdrv_set_backing_hd(bs, backing_hd, errp);
bdrv_unref(backing_hd);
+ aio_context_release(backing_hd_ctx);
+
if (ret < 0) {
goto free_exit;
}
* BlockdevRef.
*
* The BlockdevRef will be removed from the options QDict.
+ *
+ * The caller must hold the lock of the main AioContext and no other AioContext.
+ * @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,
bool allow_none, Error **errp)
{
BlockDriverState *bs;
+ BdrvChild *child;
+ AioContext *ctx;
GLOBAL_STATE_CODE();
return NULL;
}
- return bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
- errp);
+ ctx = bdrv_get_aio_context(bs);
+ aio_context_acquire(ctx);
+ child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
+ errp);
+ aio_context_release(ctx);
+
+ return child;
}
/*
* Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
+ *
+ * The caller must hold the lock of the main AioContext and no other AioContext.
+ * @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,
int64_t total_size;
QemuOpts *opts = NULL;
BlockDriverState *bs_snapshot = NULL;
+ AioContext *ctx = bdrv_get_aio_context(bs);
int ret;
GLOBAL_STATE_CODE();
instead of opening 'filename' directly */
/* Get the required size from the image */
+ aio_context_acquire(ctx);
total_size = bdrv_getlength(bs);
+ aio_context_release(ctx);
+
if (total_size < 0) {
error_setg_errno(errp, -total_size, "Could not get image size");
goto out;
goto out;
}
+ aio_context_acquire(ctx);
ret = bdrv_append(bs_snapshot, bs, errp);
+ aio_context_release(ctx);
+
if (ret < 0) {
bs_snapshot = NULL;
goto out;
* The reference parameter may be used to specify an existing block device which
* 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 the main AioContext lock.
*/
-static BlockDriverState *bdrv_open_inherit(const char *filename,
- const char *reference,
- QDict *options, int flags,
- BlockDriverState *parent,
- const BdrvChildClass *child_class,
- BdrvChildRole child_role,
- Error **errp)
+static BlockDriverState * no_coroutine_fn
+bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
+ int flags, BlockDriverState *parent,
+ const BdrvChildClass *child_class, BdrvChildRole child_role,
+ Error **errp)
{
int ret;
BlockBackend *file = NULL;
Error *local_err = NULL;
QDict *snapshot_options = NULL;
int snapshot_flags = 0;
+ AioContext *ctx = qemu_get_aio_context();
assert(!child_class || !flags);
assert(!child_class == !parent);
GLOBAL_STATE_CODE();
+ assert(!qemu_in_coroutine());
if (reference) {
bool options_non_empty = options ? qdict_size(options) : false;
/* Not requesting BLK_PERM_CONSISTENT_READ because we're only
* looking at the header to guess the image format. This works even
* in cases where a guest would not see a consistent state. */
- file = blk_new(bdrv_get_aio_context(file_bs), 0, BLK_PERM_ALL);
+ ctx = bdrv_get_aio_context(file_bs);
+ aio_context_acquire(ctx);
+ file = blk_new(ctx, 0, BLK_PERM_ALL);
blk_insert_bs(file, file_bs, &local_err);
bdrv_unref(file_bs);
+ aio_context_release(ctx);
+
if (local_err) {
goto fail;
}
goto fail;
}
+ /* The AioContext could have changed during bdrv_open_common() */
+ ctx = bdrv_get_aio_context(bs);
+
if (file) {
+ aio_context_acquire(ctx);
blk_unref(file);
+ aio_context_release(ctx);
file = NULL;
}
* (snapshot_bs); thus, we have to drop the strong reference to bs
* (which we obtained by calling bdrv_new()). bs will not be deleted,
* though, because the overlay still has a reference to it. */
+ aio_context_acquire(ctx);
bdrv_unref(bs);
+ aio_context_release(ctx);
bs = snapshot_bs;
}
return bs;
fail:
+ aio_context_acquire(ctx);
blk_unref(file);
qobject_unref(snapshot_options);
qobject_unref(bs->explicit_options);
bs->options = NULL;
bs->explicit_options = NULL;
bdrv_unref(bs);
+ aio_context_release(ctx);
error_propagate(errp, local_err);
return NULL;
close_and_fail:
+ aio_context_acquire(ctx);
bdrv_unref(bs);
+ aio_context_release(ctx);
qobject_unref(snapshot_options);
qobject_unref(options);
error_propagate(errp, local_err);
return NULL;
}
+/* The caller must always hold the main AioContext lock. */
BlockDriverState *bdrv_open(const char *filename, const char *reference,
QDict *options, int flags, Error **errp)
{
* backing BlockDriverState (or NULL).
*
* Return 0 on success, otherwise return < 0 and set @errp.
+ *
+ * The caller must hold the AioContext lock of @reopen_state->bs.
+ * @reopen_state->bs can move to a different AioContext in this function.
+ * Callers must make sure that their AioContext locking is still correct after
+ * this.
*/
static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
bool is_backing, Transaction *tran,
const char *child_name = is_backing ? "backing" : "file";
QObject *value;
const char *str;
+ AioContext *ctx, *old_ctx;
+ int ret;
GLOBAL_STATE_CODE();
reopen_state->old_file_bs = old_child_bs;
}
- return bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
- tran, errp);
+ old_ctx = bdrv_get_aio_context(bs);
+ ctx = bdrv_get_aio_context(new_child_bs);
+ if (old_ctx != ctx) {
+ aio_context_release(old_ctx);
+ aio_context_acquire(ctx);
+ }
+
+ ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
+ tran, errp);
+
+ if (old_ctx != ctx) {
+ aio_context_release(ctx);
+ aio_context_acquire(old_ctx);
+ }
+
+ return ret;
}
/*
* It is the responsibility of the caller to then call the abort() or
* commit() for any other BDS that have been left in a prepare() state
*
+ * The caller must hold the AioContext lock of @reopen_state->bs.
*/
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
BlockReopenQueue *queue,
qdict_del(bs->explicit_options, "backing");
qdict_del(bs->options, "backing");
+ bdrv_graph_rdlock_main_loop();
bdrv_refresh_limits(bs, NULL, NULL);
+ bdrv_graph_rdunlock_main_loop();
+ bdrv_refresh_total_sectors(bs, bs->total_sectors);
}
/*
* child.
*
* This function does not create any image files.
+ *
+ * The caller must hold the AioContext lock for @bs_top.
*/
int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
Error **errp)
int ret;
BdrvChild *child;
Transaction *tran = tran_new();
+ AioContext *old_context, *new_context = NULL;
GLOBAL_STATE_CODE();
assert(!bs_new->backing);
+ old_context = bdrv_get_aio_context(bs_top);
+
child = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
&child_of_bds, bdrv_backing_role(bs_new),
tran, errp);
goto out;
}
+ /*
+ * bdrv_attach_child_noperm could change the AioContext of bs_top.
+ * bdrv_replace_node_noperm calls bdrv_drained_begin, so let's temporarily
+ * hold the new AioContext, since bdrv_drained_begin calls BDRV_POLL_WHILE
+ * that assumes the new lock is taken.
+ */
+ new_context = bdrv_get_aio_context(bs_top);
+
+ if (old_context != new_context) {
+ aio_context_release(old_context);
+ aio_context_acquire(new_context);
+ }
+
ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp);
if (ret < 0) {
goto out;
out:
tran_finalize(tran, ret);
+ bdrv_graph_rdlock_main_loop();
bdrv_refresh_limits(bs_top, NULL, NULL);
+ bdrv_graph_rdunlock_main_loop();
+
+ if (new_context && old_context != new_context) {
+ aio_context_release(new_context);
+ aio_context_acquire(old_context);
+ }
return ret;
}
* 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;
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: ");
}
/**
- * Implementation of BlockDriver.bdrv_get_allocated_file_size() that
+ * Implementation of BlockDriver.bdrv_co_get_allocated_file_size() that
* sums the size of all data-bearing children. (This excludes backing
* children.)
*/
-static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs)
+static int64_t coroutine_fn GRAPH_RDLOCK
+bdrv_sum_allocated_file_size(BlockDriverState *bs)
{
BdrvChild *child;
int64_t child_size, sum = 0;
if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA |
BDRV_CHILD_FILTERED))
{
- child_size = bdrv_get_allocated_file_size(child->bs);
+ child_size = bdrv_co_get_allocated_file_size(child->bs);
if (child_size < 0) {
return child_size;
}
* Length of a allocated file in bytes. Sparse files are counted by actual
* allocated space. Return < 0 if error or unknown.
*/
-int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
+int64_t coroutine_fn bdrv_co_get_allocated_file_size(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
IO_CODE();
+ assert_bdrv_graph_readable();
if (!drv) {
return -ENOMEDIUM;
}
- if (drv->bdrv_get_allocated_file_size) {
- return drv->bdrv_get_allocated_file_size(bs);
+ if (drv->bdrv_co_get_allocated_file_size) {
+ return drv->bdrv_co_get_allocated_file_size(bs);
}
if (drv->bdrv_file_open) {
return -ENOTSUP;
} else if (drv->is_filter) {
/* Filter drivers default to the size of their filtered child */
- return bdrv_get_allocated_file_size(bdrv_filter_bs(bs));
+ return bdrv_co_get_allocated_file_size(bdrv_filter_bs(bs));
} else {
/* Other drivers default to summing their children's sizes */
return bdrv_sum_allocated_file_size(bs);
/**
* Return number of sectors on success, -errno on error.
*/
-int64_t bdrv_nb_sectors(BlockDriverState *bs)
+int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ IO_CODE();
+ assert_bdrv_graph_readable();
+
+ if (!drv)
+ return -ENOMEDIUM;
+
+ if (bs->bl.has_variable_length) {
+ int ret = bdrv_co_refresh_total_sectors(bs, bs->total_sectors);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ return bs->total_sectors;
+}
+
+/*
+ * This wrapper is written by hand because this function is in the hot I/O path,
+ * via blk_get_geometry.
+ */
+int64_t coroutine_mixed_fn bdrv_nb_sectors(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
IO_CODE();
if (!drv)
return -ENOMEDIUM;
- if (drv->has_variable_length) {
- int ret = refresh_total_sectors(bs, bs->total_sectors);
+ if (bs->bl.has_variable_length) {
+ int ret = bdrv_refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) {
return ret;
}
}
+
return bs->total_sectors;
}
* Return length in bytes on success, -errno on error.
* The length is always a multiple of BDRV_SECTOR_SIZE.
*/
-int64_t bdrv_getlength(BlockDriverState *bs)
+int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs)
{
- int64_t ret = bdrv_nb_sectors(bs);
+ int64_t ret;
IO_CODE();
+ assert_bdrv_graph_readable();
+ ret = bdrv_co_nb_sectors(bs);
if (ret < 0) {
return ret;
}
return ret * BDRV_SECTOR_SIZE;
}
-/* return 0 as number of sectors if no device present or error */
-void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
-{
- int64_t nb_sectors = bdrv_nb_sectors(bs);
- IO_CODE();
-
- *nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
-}
-
bool bdrv_is_sg(BlockDriverState *bs)
{
IO_CODE();
pstrcpy(filename, filename_size, bs->backing_file);
}
-int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+int coroutine_fn bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
int ret;
BlockDriver *drv = bs->drv;
IO_CODE();
+ assert_bdrv_graph_readable();
+
/* if bs->drv == NULL, bs is closed, so there's nothing to do here */
if (!drv) {
return -ENOMEDIUM;
}
- if (!drv->bdrv_get_info) {
+ if (!drv->bdrv_co_get_info) {
BlockDriverState *filtered = bdrv_filter_bs(bs);
if (filtered) {
- return bdrv_get_info(filtered, bdi);
+ return bdrv_co_get_info(filtered, bdi);
}
return -ENOTSUP;
}
memset(bdi, 0, sizeof(*bdi));
- ret = drv->bdrv_get_info(bs, bdi);
+ ret = drv->bdrv_co_get_info(bs, bdi);
if (ret < 0) {
return ret;
}
return drv->bdrv_get_specific_stats(bs);
}
-void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event)
+void coroutine_fn bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event)
{
IO_CODE();
- if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) {
+ assert_bdrv_graph_readable();
+
+ if (!bs || !bs->drv || !bs->drv->bdrv_co_debug_event) {
return;
}
- bs->drv->bdrv_debug_event(bs, event);
+ bs->drv->bdrv_co_debug_event(bs, event);
}
static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs)
bdrv_dirty_bitmap_skip_store(bm, false);
}
- ret = refresh_total_sectors(bs, bs->total_sectors);
+ ret = bdrv_refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) {
bs->open_flags |= BDRV_O_INACTIVE;
error_setg_errno(errp, -ret, "Could not refresh total sector count");
/**
* Return TRUE if the media is present
*/
-bool bdrv_is_inserted(BlockDriverState *bs)
+bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
BdrvChild *child;
IO_CODE();
+ assert_bdrv_graph_readable();
if (!drv) {
return false;
}
- if (drv->bdrv_is_inserted) {
- return drv->bdrv_is_inserted(bs);
+ if (drv->bdrv_co_is_inserted) {
+ return drv->bdrv_co_is_inserted(bs);
}
QLIST_FOREACH(child, &bs->children, next) {
- if (!bdrv_is_inserted(child->bs)) {
+ if (!bdrv_co_is_inserted(child->bs)) {
return false;
}
}
/**
* If eject_flag is TRUE, eject the media. Otherwise, close the tray
*/
-void bdrv_eject(BlockDriverState *bs, bool eject_flag)
+void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag)
{
BlockDriver *drv = bs->drv;
IO_CODE();
+ assert_bdrv_graph_readable();
- if (drv && drv->bdrv_eject) {
- drv->bdrv_eject(bs, eject_flag);
+ if (drv && drv->bdrv_co_eject) {
+ drv->bdrv_co_eject(bs, eject_flag);
}
}
* Lock or unlock the media (if it is locked, the user won't be able
* to eject it manually).
*/
-void bdrv_lock_medium(BlockDriverState *bs, bool locked)
+void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked)
{
BlockDriver *drv = bs->drv;
IO_CODE();
+ assert_bdrv_graph_readable();
trace_bdrv_lock_medium(bs, locked);
- if (drv && drv->bdrv_lock_medium) {
- drv->bdrv_lock_medium(bs, locked);
+ if (drv && drv->bdrv_co_lock_medium) {
+ drv->bdrv_co_lock_medium(bs, locked);
}
}
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);
if (!backing_fmt) {
error_setg(&local_err,
"Backing file specified without backing format");
- error_append_hint(&local_err, "Detected format of %s.",
+ error_append_hint(&local_err, "Detected format of %s.\n",
bs->drv->format_name);
goto 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)
}
}
-void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co)
-{
- IO_CODE();
- aio_co_enter(bdrv_get_aio_context(bs), co);
-}
-
static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
{
GLOBAL_STATE_CODE();
bs->drv->bdrv_detach_aio_context(bs);
}
- if (bs->quiesce_counter) {
- aio_enable_external(bs->aio_context);
- }
bs->aio_context = NULL;
}
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) {
return;
}
+ /*
+ * Non-zoned block drivers do not follow zoned storage constraints
+ * (i.e. sequential writes to zones). Refuse mixing zoned and non-zoned
+ * drivers in a graph.
+ */
+ if (!parent_bs->drv->supports_zoned_children &&
+ child_bs->bl.zoned == BLK_Z_HM) {
+ /*
+ * The host-aware model allows zoned storage constraints and random
+ * write. Allow mixing host-aware and non-zoned drivers. Using
+ * host-aware device as a regular device.
+ */
+ error_setg(errp, "Cannot add a %s child to a %s parent",
+ child_bs->bl.zoned == BLK_Z_HM ? "zoned" : "non-zoned",
+ parent_bs->drv->supports_zoned_children ?
+ "support zoned children" : "not support zoned children");
+ return;
+ }
+
if (!QLIST_EMPTY(&child_bs->parents)) {
error_setg(errp, "The node %s already has a parent",
child_bs->node_name);