static bool bdrv_backing_overridden(BlockDriverState *bs);
static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx,
- GSList **visited, Transaction *tran,
+ GHashTable *visited, Transaction *tran,
Error **errp);
/* If non-zero, use only whitelisted block drivers */
/* The driver isn't registered, maybe we need to load a module */
for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) {
if (!strcmp(block_driver_modules[i].format_name, format_name)) {
- block_module_load_one(block_driver_modules[i].library_name);
+ Error *local_err = NULL;
+ int rv = block_module_load(block_driver_modules[i].library_name,
+ &local_err);
+ if (rv > 0) {
+ return bdrv_do_find_format(format_name);
+ } else if (rv < 0) {
+ error_report_err(local_err);
+ }
break;
}
}
-
- return bdrv_do_find_format(format_name);
+ return NULL;
}
static int bdrv_format_is_whitelisted(const char *format_name, bool read_only)
bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE);
if (bytes_to_clear) {
- ret = blk_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP);
+ ret = blk_co_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP);
if (ret < 0) {
error_setg_errno(errp, -ret,
"Failed to clear the new image's first sector");
for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) {
if (block_driver_modules[i].protocol_name &&
!strcmp(block_driver_modules[i].protocol_name, protocol)) {
- block_module_load_one(block_driver_modules[i].library_name);
+ int rv = block_module_load(block_driver_modules[i].library_name, errp);
+ if (rv > 0) {
+ drv1 = bdrv_do_find_protocol(protocol);
+ } else if (rv < 0) {
+ return NULL;
+ }
break;
}
}
- drv1 = bdrv_do_find_protocol(protocol);
if (!drv1) {
error_setg(errp, "Unknown protocol '%s'", protocol);
}
return 0;
}
-static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
- GSList **ignore, Error **errp)
-{
- BlockDriverState *bs = child->opaque;
- return bdrv_can_set_aio_context(bs, ctx, ignore, errp);
-}
-
-static void bdrv_child_cb_set_aio_ctx(BdrvChild *child, AioContext *ctx,
- GSList **ignore)
+static bool bdrv_child_cb_change_aio_ctx(BdrvChild *child, AioContext *ctx,
+ GHashTable *visited, Transaction *tran,
+ Error **errp)
{
BlockDriverState *bs = child->opaque;
- return bdrv_set_aio_context_ignore(bs, ctx, ignore);
+ return bdrv_change_aio_context(bs, ctx, visited, tran, errp);
}
/*
.attach = bdrv_child_cb_attach,
.detach = bdrv_child_cb_detach,
.inactivate = bdrv_child_cb_inactivate,
- .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
- .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
+ .change_aio_ctx = bdrv_child_cb_change_aio_ctx,
.update_filename = bdrv_child_cb_update_filename,
.get_parent_aio_context = child_of_bds_get_parent_aio_context,
};
AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c)
{
- GLOBAL_STATE_CODE();
+ IO_CODE();
return c->klass->get_parent_aio_context(c);
}
goto open_failed;
}
+ assert(!(bs->supported_read_flags & ~BDRV_REQ_MASK));
+ assert(!(bs->supported_write_flags & ~BDRV_REQ_MASK));
+
+ /*
+ * Always allow the BDRV_REQ_REGISTERED_BUF optimization hint. This saves
+ * drivers that pass read/write requests through to a child the trouble of
+ * declaring support explicitly.
+ *
+ * Drivers must not propagate this flag accidentally when they initiate I/O
+ * to a bounce buffer. That case should be rare though.
+ */
+ bs->supported_read_flags |= BDRV_REQ_REGISTERED_BUF;
+ bs->supported_write_flags |= BDRV_REQ_REGISTERED_BUF;
+
ret = refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not refresh total sector count");
bdrv_replace_child_noperm(s->child, NULL);
if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
- bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
+ bdrv_try_change_aio_context(bs, s->old_child_ctx, NULL, &error_abort);
}
if (bdrv_child_get_parent_aio_context(s->child) != s->old_parent_ctx) {
- GSList *ignore;
+ Transaction *tran;
+ GHashTable *visited;
+ bool ret;
- /* No need to ignore `child`, because it has been detached already */
- ignore = NULL;
- s->child->klass->can_set_aio_ctx(s->child, s->old_parent_ctx, &ignore,
- &error_abort);
- g_slist_free(ignore);
+ tran = tran_new();
- ignore = NULL;
- s->child->klass->set_aio_ctx(s->child, s->old_parent_ctx, &ignore);
- g_slist_free(ignore);
+ /* No need to visit `child`, because it has been detached already */
+ visited = g_hash_table_new(NULL, NULL);
+ ret = s->child->klass->change_aio_ctx(s->child, s->old_parent_ctx,
+ visited, tran, &error_abort);
+ g_hash_table_destroy(visited);
+
+ /* transaction is supposed to always succeed */
+ assert(ret == true);
+ tran_commit(tran);
}
bdrv_unref(bs);
parent_ctx = bdrv_child_get_parent_aio_context(new_child);
if (child_ctx != parent_ctx) {
Error *local_err = NULL;
- int ret = bdrv_try_set_aio_context(child_bs, parent_ctx, &local_err);
-
- if (ret < 0 && child_class->can_set_aio_ctx) {
- GSList *ignore = g_slist_prepend(NULL, new_child);
- if (child_class->can_set_aio_ctx(new_child, child_ctx, &ignore,
- NULL))
- {
+ int ret = bdrv_try_change_aio_context(child_bs, parent_ctx, NULL,
+ &local_err);
+
+ if (ret < 0 && child_class->change_aio_ctx) {
+ Transaction *tran = tran_new();
+ GHashTable *visited = g_hash_table_new(NULL, NULL);
+ bool ret_child;
+
+ g_hash_table_add(visited, new_child);
+ ret_child = child_class->change_aio_ctx(new_child, child_ctx,
+ visited, tran, NULL);
+ if (ret_child == true) {
error_free(local_err);
ret = 0;
- g_slist_free(ignore);
- ignore = g_slist_prepend(NULL, new_child);
- child_class->set_aio_ctx(new_child, child_ctx, &ignore);
}
- g_slist_free(ignore);
+ tran_finalize(tran, ret_child == true ? 0 : -1);
+ g_hash_table_destroy(visited);
}
if (ret < 0) {
* When the parent requiring a non-default AioContext is removed, the
* node moves back to the main AioContext
*/
- bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL);
+ bdrv_try_change_aio_context(old_bs, qemu_get_aio_context(), NULL, NULL);
}
}
bs->walking_aio_notifiers = false;
}
-/*
- * Changes the AioContext used for fd handlers, timers, and BHs by this
- * BlockDriverState and all its children and parents.
- *
- * Must be called from the main AioContext.
- *
- * The caller must own the AioContext lock for the old AioContext of bs, but it
- * must not own the AioContext lock for new_context (unless new_context is the
- * same as the current context of bs).
- *
- * @ignore will accumulate all visited BdrvChild objects. The caller is
- * responsible for freeing the list afterwards.
- */
-void bdrv_set_aio_context_ignore(BlockDriverState *bs,
- AioContext *new_context, GSList **ignore)
-{
- AioContext *old_context = bdrv_get_aio_context(bs);
- GSList *children_to_process = NULL;
- GSList *parents_to_process = NULL;
- GSList *entry;
- BdrvChild *child, *parent;
-
- g_assert(qemu_get_current_aio_context() == qemu_get_aio_context());
- GLOBAL_STATE_CODE();
-
- if (old_context == new_context) {
- return;
- }
-
- bdrv_drained_begin(bs);
-
- QLIST_FOREACH(child, &bs->children, next) {
- if (g_slist_find(*ignore, child)) {
- continue;
- }
- *ignore = g_slist_prepend(*ignore, child);
- children_to_process = g_slist_prepend(children_to_process, child);
- }
-
- QLIST_FOREACH(parent, &bs->parents, next_parent) {
- if (g_slist_find(*ignore, parent)) {
- continue;
- }
- *ignore = g_slist_prepend(*ignore, parent);
- parents_to_process = g_slist_prepend(parents_to_process, parent);
- }
-
- for (entry = children_to_process;
- entry != NULL;
- entry = g_slist_next(entry)) {
- child = entry->data;
- bdrv_set_aio_context_ignore(child->bs, new_context, ignore);
- }
- g_slist_free(children_to_process);
-
- for (entry = parents_to_process;
- entry != NULL;
- entry = g_slist_next(entry)) {
- parent = entry->data;
- assert(parent->klass->set_aio_ctx);
- parent->klass->set_aio_ctx(parent, new_context, ignore);
- }
- g_slist_free(parents_to_process);
-
- bdrv_detach_aio_context(bs);
-
- /* Acquire the new context, if necessary */
- if (qemu_get_aio_context() != new_context) {
- aio_context_acquire(new_context);
- }
-
- bdrv_attach_aio_context(bs, new_context);
-
- /*
- * If this function was recursively called from
- * bdrv_set_aio_context_ignore(), there may be nodes in the
- * subtree that have not yet been moved to the new AioContext.
- * Release the old one so bdrv_drained_end() can poll them.
- */
- if (qemu_get_aio_context() != old_context) {
- aio_context_release(old_context);
- }
-
- bdrv_drained_end(bs);
-
- if (qemu_get_aio_context() != old_context) {
- aio_context_acquire(old_context);
- }
- if (qemu_get_aio_context() != new_context) {
- aio_context_release(new_context);
- }
-}
-
-static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
- GSList **ignore, Error **errp)
-{
- GLOBAL_STATE_CODE();
- if (g_slist_find(*ignore, c)) {
- return true;
- }
- *ignore = g_slist_prepend(*ignore, c);
-
- /*
- * A BdrvChildClass that doesn't handle AioContext changes cannot
- * tolerate any AioContext changes
- */
- if (!c->klass->can_set_aio_ctx) {
- char *user = bdrv_child_user_desc(c);
- error_setg(errp, "Changing iothreads is not supported by %s", user);
- g_free(user);
- return false;
- }
- if (!c->klass->can_set_aio_ctx(c, ctx, ignore, errp)) {
- assert(!errp || *errp);
- return false;
- }
- return true;
-}
-
typedef struct BdrvStateSetAioContext {
AioContext *new_ctx;
BlockDriverState *bs;
} BdrvStateSetAioContext;
static bool bdrv_parent_change_aio_context(BdrvChild *c, AioContext *ctx,
- GSList **visited, Transaction *tran,
+ GHashTable *visited,
+ Transaction *tran,
Error **errp)
{
GLOBAL_STATE_CODE();
- if (g_slist_find(*visited, c)) {
+ if (g_hash_table_contains(visited, c)) {
return true;
}
- *visited = g_slist_prepend(*visited, c);
+ g_hash_table_add(visited, c);
/*
* A BdrvChildClass that doesn't handle AioContext changes cannot
return true;
}
-bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
- GSList **ignore, Error **errp)
-{
- GLOBAL_STATE_CODE();
- if (g_slist_find(*ignore, c)) {
- return true;
- }
- *ignore = g_slist_prepend(*ignore, c);
- return bdrv_can_set_aio_context(c->bs, ctx, ignore, errp);
-}
-
bool bdrv_child_change_aio_context(BdrvChild *c, AioContext *ctx,
- GSList **visited, Transaction *tran,
+ GHashTable *visited, Transaction *tran,
Error **errp)
{
GLOBAL_STATE_CODE();
- if (g_slist_find(*visited, c)) {
+ if (g_hash_table_contains(visited, c)) {
return true;
}
- *visited = g_slist_prepend(*visited, c);
+ g_hash_table_add(visited, c);
return bdrv_change_aio_context(c->bs, ctx, visited, tran, errp);
}
-/* @ignore will accumulate all visited BdrvChild object. The caller is
- * responsible for freeing the list afterwards. */
-bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
- GSList **ignore, Error **errp)
-{
- BdrvChild *c;
-
- if (bdrv_get_aio_context(bs) == ctx) {
- return true;
- }
-
- GLOBAL_STATE_CODE();
-
- QLIST_FOREACH(c, &bs->parents, next_parent) {
- if (!bdrv_parent_can_set_aio_context(c, ctx, ignore, errp)) {
- return false;
- }
- }
- QLIST_FOREACH(c, &bs->children, next) {
- if (!bdrv_child_can_set_aio_context(c, ctx, ignore, errp)) {
- return false;
- }
- }
-
- return true;
-}
-
static void bdrv_set_aio_context_clean(void *opaque)
{
BdrvStateSetAioContext *state = (BdrvStateSetAioContext *) opaque;
* responsible for freeing the list afterwards.
*/
static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx,
- GSList **visited, Transaction *tran,
+ GHashTable *visited, Transaction *tran,
Error **errp)
{
BdrvChild *c;
return true;
}
-int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
- BdrvChild *ignore_child, Error **errp)
-{
- GSList *ignore;
- bool ret;
-
- GLOBAL_STATE_CODE();
-
- ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
- ret = bdrv_can_set_aio_context(bs, ctx, &ignore, errp);
- g_slist_free(ignore);
-
- if (!ret) {
- return -EPERM;
- }
-
- ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
- bdrv_set_aio_context_ignore(bs, ctx, &ignore);
- g_slist_free(ignore);
-
- return 0;
-}
-
/*
* Change bs's and recursively all of its parents' and children's AioContext
* to the given new context, returning an error if that isn't possible.
* bdrv_drained_end calls BDRV_POLL_WHILE that assumes the lock is taken too.
* Therefore the new AioContext lock must not be taken by the caller.
*/
-int bdrv_child_try_change_aio_context(BlockDriverState *bs, AioContext *ctx,
- BdrvChild *ignore_child, Error **errp)
+int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx,
+ BdrvChild *ignore_child, Error **errp)
{
Transaction *tran;
- GSList *visited;
+ GHashTable *visited;
int ret;
AioContext *old_context = bdrv_get_aio_context(bs);
GLOBAL_STATE_CODE();
* is successful (the transaction itself).
*/
tran = tran_new();
- visited = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
- ret = bdrv_change_aio_context(bs, ctx, &visited, tran, errp);
- g_slist_free(visited);
+ visited = g_hash_table_new(NULL, NULL);
+ if (ignore_child) {
+ g_hash_table_add(visited, ignore_child);
+ }
+ ret = bdrv_change_aio_context(bs, ctx, visited, tran, errp);
+ g_hash_table_destroy(visited);
/*
* Linear phase: go through all callbacks collected in the transaction.
return 0;
}
-int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
- Error **errp)
-{
- GLOBAL_STATE_CODE();
- return bdrv_child_try_set_aio_context(bs, ctx, NULL, errp);
-}
-
void bdrv_add_aio_context_notifier(BlockDriverState *bs,
void (*attached_aio_context)(AioContext *new_context, void *opaque),
void (*detach_aio_context)(void *opaque), void *opaque)