diff --git a/block.c b/block.c index 59a18a3a66..b4107fcd4c 100644 --- a/block.c +++ b/block.c @@ -55,8 +55,6 @@ #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ -struct BdrvStates bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states); - static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states = QTAILQ_HEAD_INITIALIZER(graph_bdrv_states); @@ -226,10 +224,7 @@ void bdrv_register(BlockDriver *bdrv) BlockDriverState *bdrv_new_root(void) { - BlockDriverState *bs = bdrv_new(); - - QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list); - return bs; + return bdrv_new(); } BlockDriverState *bdrv_new(void) @@ -1180,10 +1175,9 @@ static int bdrv_fill_options(QDict **options, const char *filename, return 0; } -static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, - BlockDriverState *child_bs, - const char *child_name, - const BdrvChildRole *child_role) +BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, + const char *child_name, + const BdrvChildRole *child_role) { BdrvChild *child = g_new(BdrvChild, 1); *child = (BdrvChild) { @@ -1192,24 +1186,43 @@ static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, .role = child_role, }; - QLIST_INSERT_HEAD(&parent_bs->children, child, next); QLIST_INSERT_HEAD(&child_bs->parents, child, next_parent); return child; } +static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, + BlockDriverState *child_bs, + const char *child_name, + const BdrvChildRole *child_role) +{ + BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role); + QLIST_INSERT_HEAD(&parent_bs->children, child, next); + return child; +} + static void bdrv_detach_child(BdrvChild *child) { - QLIST_REMOVE(child, next); + if (child->next.le_prev) { + QLIST_REMOVE(child, next); + child->next.le_prev = NULL; + } QLIST_REMOVE(child, next_parent); g_free(child->name); g_free(child); } -void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) +void bdrv_root_unref_child(BdrvChild *child) { BlockDriverState *child_bs; + child_bs = child->bs; + bdrv_detach_child(child); + bdrv_unref(child_bs); +} + +void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) +{ if (child == NULL) { return; } @@ -1218,9 +1231,7 @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) child->bs->inherits_from = NULL; } - child_bs = child->bs; - bdrv_detach_child(child); - bdrv_unref(child_bs); + bdrv_root_unref_child(child); } /* @@ -1671,9 +1682,9 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, error_setg(errp, "Block protocol '%s' doesn't support the option " "'%s'", drv->format_name, entry->key); } else { - error_setg(errp, "Block format '%s' used by device '%s' doesn't " - "support the option '%s'", drv->format_name, - bdrv_get_device_name(bs), entry->key); + error_setg(errp, + "Block format '%s' does not support the option '%s'", + drv->format_name, entry->key); } ret = -EINVAL; @@ -2230,26 +2241,10 @@ void bdrv_close_all(void) } } -/* Note that bs->device_list.tqe_prev is initially null, - * and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish - * the useful invariant "bs in bdrv_states iff bs->tqe_prev" by - * resetting it to null on remove. */ -void bdrv_device_remove(BlockDriverState *bs) -{ - QTAILQ_REMOVE(&bdrv_states, bs, device_list); - bs->device_list.tqe_prev = NULL; -} - -/* make a BlockDriverState anonymous by removing from bdrv_state and - * graph_bdrv_state list. - Also, NULL terminate the device_name to prevent double remove */ +/* make a BlockDriverState anonymous by removing from graph_bdrv_state list. + * Also, NULL terminate the device_name to prevent double remove */ void bdrv_make_anon(BlockDriverState *bs) { - /* Take care to remove bs from bdrv_states only when it's actually - * in it. */ - if (bs->device_list.tqe_prev) { - bdrv_device_remove(bs); - } if (bs->node_name[0] != '\0') { QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list); } @@ -2276,6 +2271,14 @@ static void change_parent_backing_link(BlockDriverState *from, { BdrvChild *c, *next; + if (from->blk) { + /* FIXME We bypass blk_set_bs(), so we need to make these updates + * manually. The root problem is not in this change function, but the + * existence of BlockDriverState.blk. */ + to->blk = from->blk; + from->blk = NULL; + } + QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { assert(c->role != &child_backing); c->bs = to; @@ -2284,13 +2287,6 @@ static void change_parent_backing_link(BlockDriverState *from, bdrv_ref(to); bdrv_unref(from); } - if (from->blk) { - blk_set_bs(from->blk, to); - if (!to->device_list.tqe_prev) { - QTAILQ_INSERT_BEFORE(from, to, device_list); - } - bdrv_device_remove(from); - } } static void swap_feature_fields(BlockDriverState *bs_top, @@ -2521,26 +2517,6 @@ ro_cleanup: return ret; } -int bdrv_commit_all(void) -{ - BlockDriverState *bs; - - QTAILQ_FOREACH(bs, &bdrv_states, device_list) { - AioContext *aio_context = bdrv_get_aio_context(bs); - - aio_context_acquire(aio_context); - if (bs->drv && bs->backing) { - int ret = bdrv_commit(bs); - if (ret < 0) { - aio_context_release(aio_context); - return ret; - } - } - aio_context_release(aio_context); - } - return 0; -} - /* * Return values: * 0 - success @@ -2989,12 +2965,23 @@ BlockDriverState *bdrv_next_node(BlockDriverState *bs) return QTAILQ_NEXT(bs, node_list); } +/* Iterates over all top-level BlockDriverStates, i.e. BDSs that are owned by + * the monitor or attached to a BlockBackend */ BlockDriverState *bdrv_next(BlockDriverState *bs) { - if (!bs) { - return QTAILQ_FIRST(&bdrv_states); + if (!bs || bs->blk) { + bs = blk_next_root_bs(bs); + if (bs) { + return bs; + } } - return QTAILQ_NEXT(bs, device_list); + + /* Ignore all BDSs that are attached to a BlockBackend here; they have been + * handled by the above block already */ + do { + bs = bdrv_next_monitor_owned(bs); + } while (bs && bs->blk); + return bs; } const char *bdrv_get_node_name(const BlockDriverState *bs) @@ -3302,10 +3289,10 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) void bdrv_invalidate_cache_all(Error **errp) { - BlockDriverState *bs; + BlockDriverState *bs = NULL; Error *local_err = NULL; - QTAILQ_FOREACH(bs, &bdrv_states, device_list) { + while ((bs = bdrv_next(bs)) != NULL) { AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); @@ -3335,10 +3322,10 @@ static int bdrv_inactivate(BlockDriverState *bs) int bdrv_inactivate_all(void) { - BlockDriverState *bs; + BlockDriverState *bs = NULL; int ret; - QTAILQ_FOREACH(bs, &bdrv_states, device_list) { + while ((bs = bdrv_next(bs)) != NULL) { AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); @@ -3844,10 +3831,10 @@ bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs, */ bool bdrv_is_first_non_filter(BlockDriverState *candidate) { - BlockDriverState *bs; + BlockDriverState *bs = NULL; /* walk down the bs forest recursively */ - QTAILQ_FOREACH(bs, &bdrv_states, device_list) { + while ((bs = bdrv_next(bs)) != NULL) { bool perm; /* try to recurse in this top level bs */ diff --git a/block/block-backend.c b/block/block-backend.c index 03e71b4368..dca21d1eeb 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -22,14 +22,17 @@ /* Number of coroutines to reserve per attached device model */ #define COROUTINE_POOL_RESERVATION 64 +#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ + static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb); struct BlockBackend { char *name; int refcnt; - BlockDriverState *bs; + BdrvChild *root; DriveInfo *legacy_dinfo; /* null unless created by drive_new() */ - QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */ + QTAILQ_ENTRY(BlockBackend) link; /* for block_backends */ + QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */ void *dev; /* attached device model, if any */ /* TODO change to DeviceState when all users are qdevified */ @@ -69,43 +72,40 @@ static const AIOCBInfo block_backend_aiocb_info = { static void drive_info_del(DriveInfo *dinfo); -/* All the BlockBackends (except for hidden ones) */ -static QTAILQ_HEAD(, BlockBackend) blk_backends = - QTAILQ_HEAD_INITIALIZER(blk_backends); +/* All BlockBackends */ +static QTAILQ_HEAD(, BlockBackend) block_backends = + QTAILQ_HEAD_INITIALIZER(block_backends); + +/* All BlockBackends referenced by the monitor and which are iterated through by + * blk_next() */ +static QTAILQ_HEAD(, BlockBackend) monitor_block_backends = + QTAILQ_HEAD_INITIALIZER(monitor_block_backends); + +static void blk_root_inherit_options(int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options) +{ + /* We're not supposed to call this function for root nodes */ + abort(); +} + +static const BdrvChildRole child_root = { + .inherit_options = blk_root_inherit_options, +}; /* - * Create a new BlockBackend with @name, with a reference count of one. - * @name must not be null or empty. - * Fail if a BlockBackend with this name already exists. + * Create a new BlockBackend with a reference count of one. * Store an error through @errp on failure, unless it's null. * Return the new BlockBackend on success, null on failure. */ -BlockBackend *blk_new(const char *name, Error **errp) +BlockBackend *blk_new(Error **errp) { BlockBackend *blk; - assert(name && name[0]); - if (!id_wellformed(name)) { - error_setg(errp, "Invalid device name"); - return NULL; - } - if (blk_by_name(name)) { - error_setg(errp, "Device with id '%s' already exists", name); - return NULL; - } - if (bdrv_find_node(name)) { - error_setg(errp, - "Device name '%s' conflicts with an existing node name", - name); - return NULL; - } - blk = g_new0(BlockBackend, 1); - blk->name = g_strdup(name); blk->refcnt = 1; notifier_list_init(&blk->remove_bs_notifiers); notifier_list_init(&blk->insert_bs_notifiers); - QTAILQ_INSERT_TAIL(&blk_backends, blk, link); + QTAILQ_INSERT_TAIL(&block_backends, blk, link); return blk; } @@ -113,18 +113,18 @@ BlockBackend *blk_new(const char *name, Error **errp) * Create a new BlockBackend with a new BlockDriverState attached. * Otherwise just like blk_new(), which see. */ -BlockBackend *blk_new_with_bs(const char *name, Error **errp) +BlockBackend *blk_new_with_bs(Error **errp) { BlockBackend *blk; BlockDriverState *bs; - blk = blk_new(name, errp); + blk = blk_new(errp); if (!blk) { return NULL; } bs = bdrv_new_root(); - blk->bs = bs; + blk->root = bdrv_root_attach_child(bs, "root", &child_root); bs->blk = blk; return blk; } @@ -141,20 +141,19 @@ BlockBackend *blk_new_with_bs(const char *name, Error **errp) * though, so callers of this function have to be able to specify @filename and * @flags. */ -BlockBackend *blk_new_open(const char *name, const char *filename, - const char *reference, QDict *options, int flags, - Error **errp) +BlockBackend *blk_new_open(const char *filename, const char *reference, + QDict *options, int flags, Error **errp) { BlockBackend *blk; int ret; - blk = blk_new_with_bs(name, errp); + blk = blk_new_with_bs(errp); if (!blk) { QDECREF(options); return NULL; } - ret = bdrv_open(&blk->bs, filename, reference, options, flags, errp); + ret = bdrv_open(&blk->root->bs, filename, reference, options, flags, errp); if (ret < 0) { blk_unref(blk); return NULL; @@ -166,8 +165,9 @@ BlockBackend *blk_new_open(const char *name, const char *filename, static void blk_delete(BlockBackend *blk) { assert(!blk->refcnt); + assert(!blk->name); assert(!blk->dev); - if (blk->bs) { + if (blk->root) { blk_remove_bs(blk); } assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers)); @@ -176,11 +176,7 @@ static void blk_delete(BlockBackend *blk) g_free(blk->root_state.throttle_group); throttle_group_unref(blk->root_state.throttle_state); } - /* Avoid double-remove after blk_hide_on_behalf_of_hmp_drive_del() */ - if (blk->name[0]) { - QTAILQ_REMOVE(&blk_backends, blk, link); - } - g_free(blk->name); + QTAILQ_REMOVE(&block_backends, blk, link); drive_info_del(blk->legacy_dinfo); block_acct_cleanup(&blk->stats); g_free(blk); @@ -225,15 +221,25 @@ void blk_unref(BlockBackend *blk) } } +/* + * Behaves similarly to blk_next() but iterates over all BlockBackends, even the + * ones which are hidden (i.e. are not referenced by the monitor). + */ +static BlockBackend *blk_all_next(BlockBackend *blk) +{ + return blk ? QTAILQ_NEXT(blk, link) + : QTAILQ_FIRST(&block_backends); +} + void blk_remove_all_bs(void) { - BlockBackend *blk; + BlockBackend *blk = NULL; - QTAILQ_FOREACH(blk, &blk_backends, link) { + while ((blk = blk_all_next(blk)) != NULL) { AioContext *ctx = blk_get_aio_context(blk); aio_context_acquire(ctx); - if (blk->bs) { + if (blk->root) { blk_remove_bs(blk); } aio_context_release(ctx); @@ -241,7 +247,7 @@ void blk_remove_all_bs(void) } /* - * Return the BlockBackend after @blk. + * Return the monitor-owned BlockBackend after @blk. * If @blk is null, return the first one. * Else, return @blk's next sibling, which may be null. * @@ -252,17 +258,91 @@ void blk_remove_all_bs(void) */ BlockBackend *blk_next(BlockBackend *blk) { - return blk ? QTAILQ_NEXT(blk, link) : QTAILQ_FIRST(&blk_backends); + return blk ? QTAILQ_NEXT(blk, monitor_link) + : QTAILQ_FIRST(&monitor_block_backends); +} + +/* + * Iterates over all BlockDriverStates which are attached to a BlockBackend. + * This function is for use by bdrv_next(). + * + * @bs must be NULL or a BDS that is attached to a BB. + */ +BlockDriverState *blk_next_root_bs(BlockDriverState *bs) +{ + BlockBackend *blk; + + if (bs) { + assert(bs->blk); + blk = bs->blk; + } else { + blk = NULL; + } + + do { + blk = blk_all_next(blk); + } while (blk && !blk->root); + + return blk ? blk->root->bs : NULL; +} + +/* + * Add a BlockBackend into the list of backends referenced by the monitor, with + * the given @name acting as the handle for the monitor. + * Strictly for use by blockdev.c. + * + * @name must not be null or empty. + * + * Returns true on success and false on failure. In the latter case, an Error + * object is returned through @errp. + */ +bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp) +{ + assert(!blk->name); + assert(name && name[0]); + + if (!id_wellformed(name)) { + error_setg(errp, "Invalid device name"); + return false; + } + if (blk_by_name(name)) { + error_setg(errp, "Device with id '%s' already exists", name); + return false; + } + if (bdrv_find_node(name)) { + error_setg(errp, + "Device name '%s' conflicts with an existing node name", + name); + return false; + } + + blk->name = g_strdup(name); + QTAILQ_INSERT_TAIL(&monitor_block_backends, blk, monitor_link); + return true; +} + +/* + * Remove a BlockBackend from the list of backends referenced by the monitor. + * Strictly for use by blockdev.c. + */ +void monitor_remove_blk(BlockBackend *blk) +{ + if (!blk->name) { + return; + } + + QTAILQ_REMOVE(&monitor_block_backends, blk, monitor_link); + g_free(blk->name); + blk->name = NULL; } /* * Return @blk's name, a non-null string. - * Wart: the name is empty iff @blk has been hidden with - * blk_hide_on_behalf_of_hmp_drive_del(). + * Returns an empty string iff @blk is not referenced by the monitor. */ const char *blk_name(BlockBackend *blk) { - return blk->name; + return blk->name ?: ""; } /* @@ -271,10 +351,10 @@ const char *blk_name(BlockBackend *blk) */ BlockBackend *blk_by_name(const char *name) { - BlockBackend *blk; + BlockBackend *blk = NULL; assert(name); - QTAILQ_FOREACH(blk, &blk_backends, link) { + while ((blk = blk_next(blk)) != NULL) { if (!strcmp(name, blk->name)) { return blk; } @@ -287,7 +367,7 @@ BlockBackend *blk_by_name(const char *name) */ BlockDriverState *blk_bs(BlockBackend *blk) { - return blk->bs; + return blk->root ? blk->root->bs : NULL; } /* @@ -297,13 +377,13 @@ void blk_set_bs(BlockBackend *blk, BlockDriverState *bs) { bdrv_ref(bs); - if (blk->bs) { - blk->bs->blk = NULL; - bdrv_unref(blk->bs); + if (blk->root) { + blk->root->bs->blk = NULL; + bdrv_root_unref_child(blk->root); } assert(bs->blk == NULL); - blk->bs = bs; + blk->root = bdrv_root_attach_child(bs, "root", &child_root); bs->blk = blk; } @@ -332,9 +412,9 @@ DriveInfo *blk_set_legacy_dinfo(BlockBackend *blk, DriveInfo *dinfo) */ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo) { - BlockBackend *blk; + BlockBackend *blk = NULL; - QTAILQ_FOREACH(blk, &blk_backends, link) { + while ((blk = blk_next(blk)) != NULL) { if (blk->legacy_dinfo == dinfo) { return blk; } @@ -342,38 +422,20 @@ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo) abort(); } -/* - * Hide @blk. - * @blk must not have been hidden already. - * Make attached BlockDriverState, if any, anonymous. - * Once hidden, @blk is invisible to all functions that don't receive - * it as argument. For example, blk_by_name() won't return it. - * Strictly for use by do_drive_del(). - * TODO get rid of it! - */ -void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk) -{ - QTAILQ_REMOVE(&blk_backends, blk, link); - blk->name[0] = 0; - if (blk->bs) { - bdrv_make_anon(blk->bs); - } -} - /* * Disassociates the currently associated BlockDriverState from @blk. */ void blk_remove_bs(BlockBackend *blk) { - assert(blk->bs->blk == blk); + assert(blk->root->bs->blk == blk); notifier_list_notify(&blk->remove_bs_notifiers, blk); blk_update_root_state(blk); - blk->bs->blk = NULL; - bdrv_unref(blk->bs); - blk->bs = NULL; + blk->root->bs->blk = NULL; + bdrv_root_unref_child(blk->root); + blk->root = NULL; } /* @@ -381,9 +443,9 @@ void blk_remove_bs(BlockBackend *blk) */ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs) { - assert(!blk->bs && !bs->blk); + assert(!blk->root && !bs->blk); bdrv_ref(bs); - blk->bs = bs; + blk->root = bdrv_root_attach_child(bs, "root", &child_root); bs->blk = blk; notifier_list_notify(&blk->insert_bs_notifiers, blk); @@ -565,9 +627,10 @@ void blk_iostatus_disable(BlockBackend *blk) 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 (blk->bs && blk->bs->job) { - block_job_iostatus_reset(blk->bs->job); + if (bs && bs->job) { + block_job_iostatus_reset(bs->job); } } } @@ -632,48 +695,138 @@ static int blk_check_request(BlockBackend *blk, int64_t sector_num, nb_sectors * BDRV_SECTOR_SIZE); } -int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf, - int nb_sectors) +static int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, + unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) { - int ret = blk_check_request(blk, sector_num, nb_sectors); + int ret = blk_check_byte_request(blk, offset, bytes); if (ret < 0) { return ret; } - return bdrv_read(blk->bs, sector_num, buf, nb_sectors); + return bdrv_co_do_preadv(blk_bs(blk), offset, bytes, qiov, flags); +} + +static int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, + unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) +{ + int ret = blk_check_byte_request(blk, offset, bytes); + if (ret < 0) { + return ret; + } + + return bdrv_co_do_pwritev(blk_bs(blk), offset, bytes, qiov, flags); +} + +typedef struct BlkRwCo { + BlockBackend *blk; + int64_t offset; + QEMUIOVector *qiov; + int ret; + BdrvRequestFlags flags; +} BlkRwCo; + +static void blk_read_entry(void *opaque) +{ + BlkRwCo *rwco = opaque; + + rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, rwco->qiov->size, + rwco->qiov, rwco->flags); +} + +static void blk_write_entry(void *opaque) +{ + BlkRwCo *rwco = opaque; + + rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, rwco->qiov->size, + rwco->qiov, rwco->flags); +} + +static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, + int64_t bytes, CoroutineEntry co_entry, + BdrvRequestFlags flags) +{ + AioContext *aio_context; + QEMUIOVector qiov; + struct iovec iov; + Coroutine *co; + BlkRwCo rwco; + + iov = (struct iovec) { + .iov_base = buf, + .iov_len = bytes, + }; + qemu_iovec_init_external(&qiov, &iov, 1); + + rwco = (BlkRwCo) { + .blk = blk, + .offset = offset, + .qiov = &qiov, + .flags = flags, + .ret = NOT_DONE, + }; + + co = qemu_coroutine_create(co_entry); + qemu_coroutine_enter(co, &rwco); + + aio_context = blk_get_aio_context(blk); + while (rwco.ret == NOT_DONE) { + aio_poll(aio_context, true); + } + + return rwco.ret; +} + +static int blk_rw(BlockBackend *blk, int64_t sector_num, uint8_t *buf, + int nb_sectors, CoroutineEntry co_entry, + BdrvRequestFlags flags) +{ + if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { + return -EINVAL; + } + + return blk_prw(blk, sector_num << BDRV_SECTOR_BITS, buf, + nb_sectors << BDRV_SECTOR_BITS, co_entry, flags); +} + +int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf, + int nb_sectors) +{ + return blk_rw(blk, sector_num, buf, nb_sectors, blk_read_entry, 0); } int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf, int nb_sectors) { - int ret = blk_check_request(blk, sector_num, nb_sectors); + BlockDriverState *bs = blk_bs(blk); + bool enabled; + int ret; + + ret = blk_check_request(blk, sector_num, nb_sectors); if (ret < 0) { return ret; } - return bdrv_read_unthrottled(blk->bs, sector_num, buf, nb_sectors); + enabled = bs->io_limits_enabled; + bs->io_limits_enabled = false; + ret = blk_read(blk, sector_num, buf, nb_sectors); + bs->io_limits_enabled = enabled; + return ret; } int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - int ret = blk_check_request(blk, sector_num, nb_sectors); - if (ret < 0) { - return ret; - } - - return bdrv_write(blk->bs, sector_num, buf, nb_sectors); + return blk_rw(blk, sector_num, (uint8_t*) buf, nb_sectors, + blk_write_entry, 0); } int blk_write_zeroes(BlockBackend *blk, int64_t sector_num, int nb_sectors, BdrvRequestFlags flags) { - int ret = blk_check_request(blk, sector_num, nb_sectors); - if (ret < 0) { - return ret; - } - - return bdrv_write_zeroes(blk->bs, sector_num, nb_sectors, flags); + return blk_rw(blk, sector_num, NULL, nb_sectors, blk_write_entry, + BDRV_REQ_ZERO_WRITE); } static void error_callback_bh(void *opaque) @@ -702,37 +855,114 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, return &acb->common; } +typedef struct BlkAioEmAIOCB { + BlockAIOCB common; + BlkRwCo rwco; + bool has_returned; + QEMUBH* bh; +} BlkAioEmAIOCB; + +static const AIOCBInfo blk_aio_em_aiocb_info = { + .aiocb_size = sizeof(BlkAioEmAIOCB), +}; + +static void blk_aio_complete(BlkAioEmAIOCB *acb) +{ + if (acb->bh) { + assert(acb->has_returned); + qemu_bh_delete(acb->bh); + } + if (acb->has_returned) { + acb->common.cb(acb->common.opaque, acb->rwco.ret); + qemu_aio_unref(acb); + } +} + +static void blk_aio_complete_bh(void *opaque) +{ + blk_aio_complete(opaque); +} + +static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, + QEMUIOVector *qiov, CoroutineEntry co_entry, + BdrvRequestFlags flags, + BlockCompletionFunc *cb, void *opaque) +{ + BlkAioEmAIOCB *acb; + Coroutine *co; + + acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque); + acb->rwco = (BlkRwCo) { + .blk = blk, + .offset = offset, + .qiov = qiov, + .flags = flags, + .ret = NOT_DONE, + }; + acb->bh = NULL; + acb->has_returned = false; + + co = qemu_coroutine_create(co_entry); + qemu_coroutine_enter(co, acb); + + acb->has_returned = true; + if (acb->rwco.ret != NOT_DONE) { + acb->bh = aio_bh_new(blk_get_aio_context(blk), blk_aio_complete_bh, acb); + qemu_bh_schedule(acb->bh); + } + + return &acb->common; +} + +static void blk_aio_read_entry(void *opaque) +{ + BlkAioEmAIOCB *acb = opaque; + BlkRwCo *rwco = &acb->rwco; + + rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, rwco->qiov->size, + rwco->qiov, rwco->flags); + blk_aio_complete(acb); +} + +static void blk_aio_write_entry(void *opaque) +{ + BlkAioEmAIOCB *acb = opaque; + BlkRwCo *rwco = &acb->rwco; + + rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, + rwco->qiov ? rwco->qiov->size : 0, + rwco->qiov, rwco->flags); + blk_aio_complete(acb); +} + BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num, int nb_sectors, BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque) { - int ret = blk_check_request(blk, sector_num, nb_sectors); - if (ret < 0) { - return blk_abort_aio_request(blk, cb, opaque, ret); + if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { + return blk_abort_aio_request(blk, cb, opaque, -EINVAL); } - return bdrv_aio_write_zeroes(blk->bs, sector_num, nb_sectors, flags, - cb, opaque); + return blk_aio_prwv(blk, sector_num << BDRV_SECTOR_BITS, NULL, + blk_aio_write_entry, BDRV_REQ_ZERO_WRITE, cb, opaque); } int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count) { - int ret = blk_check_byte_request(blk, offset, count); + int ret = blk_prw(blk, offset, buf, count, blk_read_entry, 0); if (ret < 0) { return ret; } - - return bdrv_pread(blk->bs, offset, buf, count); + return count; } int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count) { - int ret = blk_check_byte_request(blk, offset, count); + int ret = blk_prw(blk, offset, (void*) buf, count, blk_write_entry, 0); if (ret < 0) { return ret; } - - return bdrv_pwrite(blk->bs, offset, buf, count); + return count; } int64_t blk_getlength(BlockBackend *blk) @@ -741,15 +971,15 @@ int64_t blk_getlength(BlockBackend *blk) return -ENOMEDIUM; } - return bdrv_getlength(blk->bs); + return bdrv_getlength(blk_bs(blk)); } void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) { - if (!blk->bs) { + if (!blk_bs(blk)) { *nb_sectors_ptr = 0; } else { - bdrv_get_geometry(blk->bs, nb_sectors_ptr); + bdrv_get_geometry(blk_bs(blk), nb_sectors_ptr); } } @@ -759,31 +989,31 @@ int64_t blk_nb_sectors(BlockBackend *blk) return -ENOMEDIUM; } - return bdrv_nb_sectors(blk->bs); + return bdrv_nb_sectors(blk_bs(blk)); } BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num, QEMUIOVector *iov, int nb_sectors, BlockCompletionFunc *cb, void *opaque) { - int ret = blk_check_request(blk, sector_num, nb_sectors); - if (ret < 0) { - return blk_abort_aio_request(blk, cb, opaque, ret); + if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { + return blk_abort_aio_request(blk, cb, opaque, -EINVAL); } - return bdrv_aio_readv(blk->bs, sector_num, iov, nb_sectors, cb, opaque); + return blk_aio_prwv(blk, sector_num << BDRV_SECTOR_BITS, iov, + blk_aio_read_entry, 0, cb, opaque); } BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num, QEMUIOVector *iov, int nb_sectors, BlockCompletionFunc *cb, void *opaque) { - int ret = blk_check_request(blk, sector_num, nb_sectors); - if (ret < 0) { - return blk_abort_aio_request(blk, cb, opaque, ret); + if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { + return blk_abort_aio_request(blk, cb, opaque, -EINVAL); } - return bdrv_aio_writev(blk->bs, sector_num, iov, nb_sectors, cb, opaque); + return blk_aio_prwv(blk, sector_num << BDRV_SECTOR_BITS, iov, + blk_aio_write_entry, 0, cb, opaque); } BlockAIOCB *blk_aio_flush(BlockBackend *blk, @@ -793,7 +1023,7 @@ BlockAIOCB *blk_aio_flush(BlockBackend *blk, return blk_abort_aio_request(blk, cb, opaque, -ENOMEDIUM); } - return bdrv_aio_flush(blk->bs, cb, opaque); + return bdrv_aio_flush(blk_bs(blk), cb, opaque); } BlockAIOCB *blk_aio_discard(BlockBackend *blk, @@ -805,7 +1035,7 @@ BlockAIOCB *blk_aio_discard(BlockBackend *blk, return blk_abort_aio_request(blk, cb, opaque, ret); } - return bdrv_aio_discard(blk->bs, sector_num, nb_sectors, cb, opaque); + return bdrv_aio_discard(blk_bs(blk), sector_num, nb_sectors, cb, opaque); } void blk_aio_cancel(BlockAIOCB *acb) @@ -829,7 +1059,7 @@ int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs) } } - return bdrv_aio_multiwrite(blk->bs, reqs, num_reqs); + return bdrv_aio_multiwrite(blk_bs(blk), reqs, num_reqs); } int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf) @@ -838,7 +1068,7 @@ int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf) return -ENOMEDIUM; } - return bdrv_ioctl(blk->bs, req, buf); + return bdrv_ioctl(blk_bs(blk), req, buf); } BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, @@ -848,7 +1078,7 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, return blk_abort_aio_request(blk, cb, opaque, -ENOMEDIUM); } - return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque); + return bdrv_aio_ioctl(blk_bs(blk), req, buf, cb, opaque); } int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors) @@ -858,7 +1088,7 @@ int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors) return ret; } - return bdrv_co_discard(blk->bs, sector_num, nb_sectors); + return bdrv_co_discard(blk_bs(blk), sector_num, nb_sectors); } int blk_co_flush(BlockBackend *blk) @@ -867,7 +1097,7 @@ int blk_co_flush(BlockBackend *blk) return -ENOMEDIUM; } - return bdrv_co_flush(blk->bs); + return bdrv_co_flush(blk_bs(blk)); } int blk_flush(BlockBackend *blk) @@ -876,18 +1106,13 @@ int blk_flush(BlockBackend *blk) return -ENOMEDIUM; } - return bdrv_flush(blk->bs); -} - -int blk_flush_all(void) -{ - return bdrv_flush_all(); + return bdrv_flush(blk_bs(blk)); } void blk_drain(BlockBackend *blk) { - if (blk->bs) { - bdrv_drain(blk->bs); + if (blk_bs(blk)) { + bdrv_drain(blk_bs(blk)); } } @@ -975,8 +1200,10 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, int blk_is_read_only(BlockBackend *blk) { - if (blk->bs) { - return bdrv_is_read_only(blk->bs); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + return bdrv_is_read_only(bs); } else { return blk->root_state.read_only; } @@ -984,17 +1211,21 @@ int blk_is_read_only(BlockBackend *blk) int blk_is_sg(BlockBackend *blk) { - if (!blk->bs) { + BlockDriverState *bs = blk_bs(blk); + + if (!bs) { return 0; } - return bdrv_is_sg(blk->bs); + return bdrv_is_sg(bs); } int blk_enable_write_cache(BlockBackend *blk) { - if (blk->bs) { - return bdrv_enable_write_cache(blk->bs); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + return bdrv_enable_write_cache(bs); } else { return !!(blk->root_state.open_flags & BDRV_O_CACHE_WB); } @@ -1002,8 +1233,10 @@ int blk_enable_write_cache(BlockBackend *blk) void blk_set_enable_write_cache(BlockBackend *blk, bool wce) { - if (blk->bs) { - bdrv_set_enable_write_cache(blk->bs, wce); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_set_enable_write_cache(bs, wce); } else { if (wce) { blk->root_state.open_flags |= BDRV_O_CACHE_WB; @@ -1015,17 +1248,21 @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce) void blk_invalidate_cache(BlockBackend *blk, Error **errp) { - if (!blk->bs) { + BlockDriverState *bs = blk_bs(blk); + + if (!bs) { error_setg(errp, "Device '%s' has no medium", blk->name); return; } - bdrv_invalidate_cache(blk->bs, errp); + bdrv_invalidate_cache(bs, errp); } bool blk_is_inserted(BlockBackend *blk) { - return blk->bs && bdrv_is_inserted(blk->bs); + BlockDriverState *bs = blk_bs(blk); + + return bs && bdrv_is_inserted(bs); } bool blk_is_available(BlockBackend *blk) @@ -1035,22 +1272,28 @@ bool blk_is_available(BlockBackend *blk) void blk_lock_medium(BlockBackend *blk, bool locked) { - if (blk->bs) { - bdrv_lock_medium(blk->bs, locked); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_lock_medium(bs, locked); } } void blk_eject(BlockBackend *blk, bool eject_flag) { - if (blk->bs) { - bdrv_eject(blk->bs, eject_flag); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_eject(bs, eject_flag); } } int blk_get_flags(BlockBackend *blk) { - if (blk->bs) { - return bdrv_get_flags(blk->bs); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + return bdrv_get_flags(bs); } else { return blk->root_state.open_flags; } @@ -1058,8 +1301,10 @@ int blk_get_flags(BlockBackend *blk) int blk_get_max_transfer_length(BlockBackend *blk) { - if (blk->bs) { - return blk->bs->bl.max_transfer_length; + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + return bs->bl.max_transfer_length; } else { return 0; } @@ -1067,7 +1312,7 @@ int blk_get_max_transfer_length(BlockBackend *blk) int blk_get_max_iov(BlockBackend *blk) { - return blk->bs->bl.max_iov; + return blk->root->bs->bl.max_iov; } void blk_set_guest_block_size(BlockBackend *blk, int align) @@ -1077,48 +1322,58 @@ void blk_set_guest_block_size(BlockBackend *blk, int align) void *blk_try_blockalign(BlockBackend *blk, size_t size) { - return qemu_try_blockalign(blk ? blk->bs : NULL, size); + return qemu_try_blockalign(blk ? blk_bs(blk) : NULL, size); } void *blk_blockalign(BlockBackend *blk, size_t size) { - return qemu_blockalign(blk ? blk->bs : NULL, size); + return qemu_blockalign(blk ? blk_bs(blk) : NULL, size); } bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp) { - if (!blk->bs) { + BlockDriverState *bs = blk_bs(blk); + + if (!bs) { return false; } - return bdrv_op_is_blocked(blk->bs, op, errp); + return bdrv_op_is_blocked(bs, op, errp); } void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason) { - if (blk->bs) { - bdrv_op_unblock(blk->bs, op, reason); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_op_unblock(bs, op, reason); } } void blk_op_block_all(BlockBackend *blk, Error *reason) { - if (blk->bs) { - bdrv_op_block_all(blk->bs, reason); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_op_block_all(bs, reason); } } void blk_op_unblock_all(BlockBackend *blk, Error *reason) { - if (blk->bs) { - bdrv_op_unblock_all(blk->bs, reason); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_op_unblock_all(bs, reason); } } AioContext *blk_get_aio_context(BlockBackend *blk) { - if (blk->bs) { - return bdrv_get_aio_context(blk->bs); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + return bdrv_get_aio_context(bs); } else { return qemu_get_aio_context(); } @@ -1132,8 +1387,10 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb) void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) { - if (blk->bs) { - bdrv_set_aio_context(blk->bs, new_context); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_set_aio_context(bs, new_context); } } @@ -1141,8 +1398,10 @@ 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) { - if (blk->bs) { - bdrv_add_aio_context_notifier(blk->bs, attached_aio_context, + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_add_aio_context_notifier(bs, attached_aio_context, detach_aio_context, opaque); } } @@ -1153,8 +1412,10 @@ void blk_remove_aio_context_notifier(BlockBackend *blk, void (*detach_aio_context)(void *), void *opaque) { - if (blk->bs) { - bdrv_remove_aio_context_notifier(blk->bs, attached_aio_context, + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_remove_aio_context_notifier(bs, attached_aio_context, detach_aio_context, opaque); } } @@ -1171,15 +1432,19 @@ void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify) void blk_io_plug(BlockBackend *blk) { - if (blk->bs) { - bdrv_io_plug(blk->bs); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_io_plug(bs); } } void blk_io_unplug(BlockBackend *blk) { - if (blk->bs) { - bdrv_io_unplug(blk->bs); + BlockDriverState *bs = blk_bs(blk); + + if (bs) { + bdrv_io_unplug(bs); } } @@ -1197,12 +1462,13 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num, int nb_sectors, BdrvRequestFlags flags) { - int ret = blk_check_request(blk, sector_num, nb_sectors); - if (ret < 0) { - return ret; + if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { + return -EINVAL; } - return bdrv_co_write_zeroes(blk->bs, sector_num, nb_sectors, flags); + return blk_co_pwritev(blk, sector_num << BDRV_SECTOR_BITS, + nb_sectors << BDRV_SECTOR_BITS, NULL, + BDRV_REQ_ZERO_WRITE); } int blk_write_compressed(BlockBackend *blk, int64_t sector_num, @@ -1213,7 +1479,7 @@ int blk_write_compressed(BlockBackend *blk, int64_t sector_num, return ret; } - return bdrv_write_compressed(blk->bs, sector_num, buf, nb_sectors); + return bdrv_write_compressed(blk_bs(blk), sector_num, buf, nb_sectors); } int blk_truncate(BlockBackend *blk, int64_t offset) @@ -1222,7 +1488,7 @@ int blk_truncate(BlockBackend *blk, int64_t offset) return -ENOMEDIUM; } - return bdrv_truncate(blk->bs, offset); + return bdrv_truncate(blk_bs(blk), offset); } int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors) @@ -1232,7 +1498,7 @@ int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors) return ret; } - return bdrv_discard(blk->bs, sector_num, nb_sectors); + return bdrv_discard(blk_bs(blk), sector_num, nb_sectors); } int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, @@ -1242,7 +1508,7 @@ int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, return -ENOMEDIUM; } - return bdrv_save_vmstate(blk->bs, buf, pos, size); + return bdrv_save_vmstate(blk_bs(blk), buf, pos, size); } int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size) @@ -1251,7 +1517,7 @@ int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size) return -ENOMEDIUM; } - return bdrv_load_vmstate(blk->bs, buf, pos, size); + return bdrv_load_vmstate(blk_bs(blk), buf, pos, size); } int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz) @@ -1260,7 +1526,7 @@ int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz) return -ENOMEDIUM; } - return bdrv_probe_blocksizes(blk->bs, bsz); + return bdrv_probe_blocksizes(blk_bs(blk), bsz); } int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo) @@ -1269,7 +1535,7 @@ int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo) return -ENOMEDIUM; } - return bdrv_probe_geometry(blk->bs, geo); + return bdrv_probe_geometry(blk_bs(blk), geo); } /* @@ -1278,18 +1544,18 @@ int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo) */ void blk_update_root_state(BlockBackend *blk) { - assert(blk->bs); + assert(blk->root); - blk->root_state.open_flags = blk->bs->open_flags; - blk->root_state.read_only = blk->bs->read_only; - blk->root_state.detect_zeroes = blk->bs->detect_zeroes; + blk->root_state.open_flags = blk->root->bs->open_flags; + blk->root_state.read_only = blk->root->bs->read_only; + blk->root_state.detect_zeroes = blk->root->bs->detect_zeroes; if (blk->root_state.throttle_group) { g_free(blk->root_state.throttle_group); throttle_group_unref(blk->root_state.throttle_state); } - if (blk->bs->throttle_state) { - const char *name = throttle_group_get_name(blk->bs); + if (blk->root->bs->throttle_state) { + const char *name = throttle_group_get_name(blk->root->bs); blk->root_state.throttle_group = g_strdup(name); blk->root_state.throttle_state = throttle_group_incref(name); } else { @@ -1329,3 +1595,45 @@ BlockBackendRootState *blk_get_root_state(BlockBackend *blk) { return &blk->root_state; } + +int blk_commit_all(void) +{ + BlockBackend *blk = NULL; + + while ((blk = blk_all_next(blk)) != NULL) { + AioContext *aio_context = blk_get_aio_context(blk); + + aio_context_acquire(aio_context); + if (blk_is_inserted(blk) && blk->root->bs->backing) { + int ret = bdrv_commit(blk->root->bs); + if (ret < 0) { + aio_context_release(aio_context); + return ret; + } + } + aio_context_release(aio_context); + } + return 0; +} + +int blk_flush_all(void) +{ + BlockBackend *blk = NULL; + int result = 0; + + while ((blk = blk_all_next(blk)) != NULL) { + AioContext *aio_context = blk_get_aio_context(blk); + int ret; + + aio_context_acquire(aio_context); + if (blk_is_inserted(blk)) { + ret = blk_flush(blk); + if (ret < 0 && !result) { + result = ret; + } + } + aio_context_release(aio_context); + } + + return result; +} diff --git a/block/io.c b/block/io.c index a69bfc4197..41d954cad2 100644 --- a/block/io.c +++ b/block/io.c @@ -44,12 +44,6 @@ static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs, static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *iov); -static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs, - int64_t offset, unsigned int bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags); -static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, - int64_t offset, unsigned int bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags); static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, @@ -621,20 +615,6 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false, 0); } -/* Just like bdrv_read(), but with I/O throttling temporarily disabled */ -int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors) -{ - bool enabled; - int ret; - - enabled = bs->io_limits_enabled; - bs->io_limits_enabled = false; - ret = bdrv_read(bs, sector_num, buf, nb_sectors); - bs->io_limits_enabled = enabled; - return ret; -} - /* Return < 0 if error. Important errors are: -EIO generic I/O error (may happen for all errors) -ENOMEDIUM No media inserted. @@ -939,7 +919,7 @@ out: /* * Handle a read request in coroutine context */ -static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs, +int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) { @@ -1284,7 +1264,7 @@ fail: /* * Handle a write request in coroutine context */ -static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, +int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) { @@ -1445,26 +1425,6 @@ int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, BDRV_REQ_ZERO_WRITE | flags); } -int bdrv_flush_all(void) -{ - BlockDriverState *bs = NULL; - int result = 0; - - while ((bs = bdrv_next(bs))) { - AioContext *aio_context = bdrv_get_aio_context(bs); - int ret; - - aio_context_acquire(aio_context); - ret = bdrv_flush(bs); - if (ret < 0 && !result) { - result = ret; - } - aio_context_release(aio_context); - } - - return result; -} - typedef struct BdrvCoGetBlockStatusData { BlockDriverState *bs; BlockDriverState *base; diff --git a/block/parallels.c b/block/parallels.c index 0d1a60c972..b322d05c08 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -478,7 +478,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp) return ret; } - file = blk_new_open("image", filename, NULL, NULL, + file = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (file == NULL) { diff --git a/block/qcow.c b/block/qcow.c index 2fd5ee65d4..73cf8a7081 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -121,11 +121,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } if (header.version != QCOW_VERSION) { - char version[64]; - snprintf(version, sizeof(version), "QCOW version %" PRIu32, - header.version); - error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, - bdrv_get_device_or_node_name(bs), "qcow", version); + error_setg(errp, "Unsupported qcow version %" PRIu32, header.version); ret = -ENOTSUP; goto fail; } @@ -797,7 +793,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) goto cleanup; } - qcow_blk = blk_new_open("image", filename, NULL, NULL, + qcow_blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (qcow_blk == NULL) { diff --git a/block/qcow2.c b/block/qcow2.c index 1ce6264011..5f4fea6a55 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -198,22 +198,8 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs) } } -static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs, - Error **errp, const char *fmt, ...) -{ - char msg[64]; - va_list ap; - - va_start(ap, fmt); - vsnprintf(msg, sizeof(msg), fmt, ap); - va_end(ap); - - error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, - bdrv_get_device_or_node_name(bs), "qcow2", msg); -} - -static void report_unsupported_feature(BlockDriverState *bs, - Error **errp, Qcow2Feature *table, uint64_t mask) +static void report_unsupported_feature(Error **errp, Qcow2Feature *table, + uint64_t mask) { char *features = g_strdup(""); char *old; @@ -238,7 +224,7 @@ static void report_unsupported_feature(BlockDriverState *bs, g_free(old); } - report_unsupported(bs, errp, "%s", features); + error_setg(errp, "Unsupported qcow2 feature(s): %s", features); g_free(features); } @@ -855,7 +841,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } if (header.version < 2 || header.version > 3) { - report_unsupported(bs, errp, "QCOW version %" PRIu32, header.version); + error_setg(errp, "Unsupported qcow2 version %" PRIu32, header.version); ret = -ENOTSUP; goto fail; } @@ -935,7 +921,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, void *feature_table = NULL; qcow2_read_extensions(bs, header.header_length, ext_end, &feature_table, NULL); - report_unsupported_feature(bs, errp, feature_table, + report_unsupported_feature(errp, feature_table, s->incompatible_features & ~QCOW2_INCOMPAT_MASK); ret = -ENOTSUP; @@ -2173,7 +2159,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, return ret; } - blk = blk_new_open("image", filename, NULL, NULL, + blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (blk == NULL) { @@ -2238,7 +2224,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, */ options = qdict_new(); qdict_put(options, "driver", qstring_from_str("qcow2")); - blk = blk_new_open("image-qcow2", filename, NULL, options, + blk = blk_new_open(filename, NULL, options, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, &local_err); if (blk == NULL) { @@ -2300,7 +2286,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */ options = qdict_new(); qdict_put(options, "driver", qstring_from_str("qcow2")); - blk = blk_new_open("image-flush", filename, NULL, options, + blk = blk_new_open(filename, NULL, options, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING, &local_err); if (blk == NULL) { diff --git a/block/qed.c b/block/qed.c index 5a58856ecd..5b24a9783f 100644 --- a/block/qed.c +++ b/block/qed.c @@ -400,11 +400,8 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, } if (s->header.features & ~QED_FEATURE_MASK) { /* image uses unsupported feature bits */ - char buf[64]; - snprintf(buf, sizeof(buf), "%" PRIx64, - s->header.features & ~QED_FEATURE_MASK); - error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, - bdrv_get_device_or_node_name(bs), "QED", buf); + error_setg(errp, "Unsupported QED features: %" PRIx64, + s->header.features & ~QED_FEATURE_MASK); return -ENOTSUP; } if (!qed_is_cluster_size_valid(s->header.cluster_size)) { @@ -577,7 +574,7 @@ static int qed_create(const char *filename, uint32_t cluster_size, return ret; } - blk = blk_new_open("image", filename, NULL, NULL, + blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (blk == NULL) { diff --git a/block/quorum.c b/block/quorum.c index 3d473515a8..da15465a9a 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -284,9 +284,17 @@ static void quorum_aio_cb(void *opaque, int ret) QuorumChildRequest *sacb = opaque; QuorumAIOCB *acb = sacb->parent; BDRVQuorumState *s = acb->common.bs->opaque; - QuorumOpType type; bool rewrite = false; + if (ret == 0) { + acb->success_count++; + } else { + QuorumOpType type; + type = acb->is_read ? QUORUM_OP_TYPE_READ : QUORUM_OP_TYPE_WRITE; + quorum_report_bad(type, acb->sector_num, acb->nb_sectors, + sacb->aiocb->bs->node_name, ret); + } + if (acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO) { /* We try to read next child in FIFO order if we fail to read */ if (ret < 0 && (acb->child_iter + 1) < s->num_children) { @@ -303,15 +311,8 @@ static void quorum_aio_cb(void *opaque, int ret) return; } - type = acb->is_read ? QUORUM_OP_TYPE_READ : QUORUM_OP_TYPE_WRITE; sacb->ret = ret; acb->count++; - if (ret == 0) { - acb->success_count++; - } else { - quorum_report_bad(type, acb->sector_num, acb->nb_sectors, - sacb->aiocb->bs->node_name, ret); - } assert(acb->count <= s->num_children); assert(acb->success_count <= s->num_children); if (acb->count < s->num_children) { diff --git a/block/sheepdog.c b/block/sheepdog.c index 06ae3bac62..a3aeae4a67 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1646,7 +1646,7 @@ static int sd_prealloc(const char *filename, Error **errp) void *buf = NULL; int ret; - blk = blk_new_open("image-prealloc", filename, NULL, NULL, + blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, errp); if (blk == NULL) { @@ -1843,7 +1843,7 @@ static int sd_create(const char *filename, QemuOpts *opts, goto out; } - blk = blk_new_open("backing", backing_file, NULL, NULL, + blk = blk_new_open(backing_file, NULL, NULL, BDRV_O_PROTOCOL | BDRV_O_CACHE_WB, errp); if (blk == NULL) { ret = -EIO; diff --git a/block/vdi.c b/block/vdi.c index 662d14b74e..df9fa47db1 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -768,7 +768,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp) goto exit; } - blk = blk_new_open("image", filename, NULL, NULL, + blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (blk == NULL) { diff --git a/block/vhdx.c b/block/vhdx.c index e15020c9be..78fe56ca04 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1838,7 +1838,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp) goto exit; } - blk = blk_new_open("image", filename, NULL, NULL, + blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (blk == NULL) { diff --git a/block/vmdk.c b/block/vmdk.c index 23bd57e20e..80f033835e 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -661,11 +661,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, compressed = le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; if (le32_to_cpu(header.version) > 3) { - char buf[64]; - snprintf(buf, sizeof(buf), "VMDK version %" PRId32, - le32_to_cpu(header.version)); - error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, - bdrv_get_device_or_node_name(bs), "vmdk", buf); + error_setg(errp, "Unsupported VMDK version %" PRIu32, + le32_to_cpu(header.version)); return -ENOTSUP; } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR) && !compressed) { @@ -1664,7 +1661,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, goto exit; } - blk = blk_new_open("extent", filename, NULL, NULL, + blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (blk == NULL) { @@ -1949,7 +1946,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) goto exit; } - blk = blk_new_open("backing", full_backing, NULL, NULL, + blk = blk_new_open(full_backing, NULL, NULL, BDRV_O_NO_BACKING | BDRV_O_CACHE_WB, errp); g_free(full_backing); if (blk == NULL) { @@ -2021,7 +2018,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) } } - new_blk = blk_new_open("descriptor", filename, NULL, NULL, + new_blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (new_blk == NULL) { diff --git a/block/vpc.c b/block/vpc.c index 0d1524d6f6..8435205a0c 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -888,7 +888,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp) goto out; } - blk = blk_new_open("image", filename, NULL, NULL, + blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, &local_err); if (blk == NULL) { diff --git a/blockdev.c b/blockdev.c index 322ca03908..85dee5787b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -147,6 +147,7 @@ void blockdev_auto_del(BlockBackend *blk) DriveInfo *dinfo = blk_legacy_dinfo(blk); if (dinfo && dinfo->auto_del) { + monitor_remove_blk(blk); blk_unref(blk); } } @@ -561,7 +562,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, if ((!file || !*file) && !qdict_size(bs_opts)) { BlockBackendRootState *blk_rs; - blk = blk_new(qemu_opts_id(opts), errp); + blk = blk_new(errp); if (!blk) { goto early_err; } @@ -597,8 +598,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, bdrv_flags |= BDRV_O_INACTIVE; } - blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags, - errp); + blk = blk_new_open(file, NULL, bs_opts, bdrv_flags, errp); if (!blk) { goto err_no_bs_opts; } @@ -630,6 +630,12 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, blk_set_on_error(blk, on_read_error, on_write_error); + if (!monitor_add_blk(blk, qemu_opts_id(opts), errp)) { + blk_unref(blk); + blk = NULL; + goto err_no_bs_opts; + } + err_no_bs_opts: qemu_opts_del(opts); QDECREF(interval_dict); @@ -717,6 +723,13 @@ void blockdev_close_all_bdrv_states(void) } } +/* Iterates over the list of monitor-owned BlockDriverStates */ +BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs) +{ + return bs ? QTAILQ_NEXT(bs, monitor_list) + : QTAILQ_FIRST(&monitor_bdrv_states); +} + static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to, Error **errp) { @@ -1173,7 +1186,7 @@ void hmp_commit(Monitor *mon, const QDict *qdict) int ret; if (!strcmp(device, "all")) { - ret = bdrv_commit_all(); + ret = blk_commit_all(); } else { BlockDriverState *bs; AioContext *aio_context; @@ -2413,11 +2426,6 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp) goto out; } - /* This follows the convention established by bdrv_make_anon() */ - if (bs->device_list.tqe_prev) { - bdrv_device_remove(bs); - } - blk_remove_bs(blk); if (!blk_dev_has_tray(blk)) { @@ -2465,8 +2473,6 @@ static void qmp_blockdev_insert_anon_medium(const char *device, blk_insert_bs(blk, bs); - QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list); - if (!blk_dev_has_tray(blk)) { /* For tray-less devices, blockdev-close-tray is a no-op (or may not be * called at all); therefore, the medium needs to be pushed into the @@ -2859,13 +2865,16 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) blk_remove_bs(blk); } - /* if we have a device attached to this BlockDriverState - * then we need to make the drive anonymous until the device - * can be removed. If this is a drive with no device backing - * then we can just get rid of the block driver state right here. + /* Make the BlockBackend and the attached BlockDriverState anonymous */ + monitor_remove_blk(blk); + if (blk_bs(blk)) { + bdrv_make_anon(blk_bs(blk)); + } + + /* If this BlockBackend has a device attached to it, its refcount will be + * decremented when the device is removed; otherwise we have to do so here. */ if (blk_get_attached_dev(blk)) { - blk_hide_on_behalf_of_hmp_drive_del(blk); /* Further I/O must not pause the guest */ blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT); @@ -3898,6 +3907,7 @@ void hmp_drive_add_node(Monitor *mon, const char *optstr) qdict = qemu_opts_to_qdict(opts, NULL); if (!qdict_get_try_str(qdict, "node-name")) { + QDECREF(qdict); error_report("'node-name' needs to be specified"); goto out; } @@ -3975,6 +3985,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) if (bs && bdrv_key_required(bs)) { if (blk) { + monitor_remove_blk(blk); blk_unref(blk); } else { QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); @@ -4004,6 +4015,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id, } if (has_id) { + /* blk_by_name() never returns a BB that is not owned by the monitor */ blk = blk_by_name(id); if (!blk) { error_setg(errp, "Cannot find block backend %s", id); @@ -4051,6 +4063,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id, } if (blk) { + monitor_remove_blk(blk); blk_unref(blk); } else { QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); @@ -4221,7 +4234,7 @@ QemuOptsList qemu_common_drive_opts = { static QemuOptsList qemu_root_bds_opts = { .name = "root-bds", - .head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head), + .head = QTAILQ_HEAD_INITIALIZER(qemu_root_bds_opts.head), .desc = { { .name = "discard", diff --git a/cpus.c b/cpus.c index 4052be525f..23cf7aad76 100644 --- a/cpus.c +++ b/cpus.c @@ -29,6 +29,7 @@ #include "qapi/qmp/qerror.h" #include "qemu/error-report.h" #include "sysemu/sysemu.h" +#include "sysemu/block-backend.h" #include "exec/gdbstub.h" #include "sysemu/dma.h" #include "sysemu/kvm.h" @@ -734,7 +735,7 @@ static int do_vm_stop(RunState state) } bdrv_drain_all(); - ret = bdrv_flush_all(); + ret = blk_flush_all(); return ret; } @@ -1433,7 +1434,7 @@ int vm_stop_force_state(RunState state) bdrv_drain_all(); /* Make sure to return an error if the flush in a previous vm_stop() * failed. */ - return bdrv_flush_all(); + return blk_flush_all(); } } diff --git a/device-hotplug.c b/device-hotplug.c index 3e5cdaad10..126f73c676 100644 --- a/device-hotplug.c +++ b/device-hotplug.c @@ -84,6 +84,8 @@ void hmp_drive_add(Monitor *mon, const QDict *qdict) err: if (dinfo) { - blk_unref(blk_by_legacy_dinfo(dinfo)); + BlockBackend *blk = blk_by_legacy_dinfo(dinfo); + monitor_remove_blk(blk); + blk_unref(blk); } } diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 7bd5bdefd3..635328fa69 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -917,7 +917,7 @@ static int blk_connect(struct XenDevice *xendev) /* setup via xenbus -> create new block driver instance */ xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); - blkdev->blk = blk_new_open(blkdev->dev, blkdev->filename, NULL, options, + blkdev->blk = blk_new_open(blkdev->filename, NULL, options, qflags, &local_err); if (!blkdev->blk) { xen_be_printf(&blkdev->xendev, 0, "error: %s\n", diff --git a/include/block/block.h b/include/block/block.h index eaa64262d9..01349efad5 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -201,7 +201,6 @@ int bdrv_create(BlockDriver *drv, const char* filename, int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); BlockDriverState *bdrv_new_root(void); BlockDriverState *bdrv_new(void); -void bdrv_device_remove(BlockDriverState *bs); void bdrv_make_anon(BlockDriverState *bs); void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); void bdrv_replace_in_backing_chain(BlockDriverState *old, @@ -230,8 +229,6 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state); void bdrv_reopen_abort(BDRVReopenState *reopen_state); int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); -int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors); int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num, @@ -274,7 +271,6 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); void bdrv_refresh_limits(BlockDriverState *bs, Error **errp); int bdrv_commit(BlockDriverState *bs); -int bdrv_commit_all(void); int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt); void bdrv_register(BlockDriver *bdrv); @@ -373,7 +369,6 @@ int bdrv_inactivate_all(void); /* Ensure contents are flushed to disk. */ int bdrv_flush(BlockDriverState *bs); int coroutine_fn bdrv_co_flush(BlockDriverState *bs); -int bdrv_flush_all(void); void bdrv_close_all(void); void bdrv_drain(BlockDriverState *bs); void bdrv_drain_all(void); @@ -414,6 +409,7 @@ BlockDriverState *bdrv_lookup_bs(const char *device, bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base); BlockDriverState *bdrv_next_node(BlockDriverState *bs); BlockDriverState *bdrv_next(BlockDriverState *bs); +BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); int bdrv_is_encrypted(BlockDriverState *bs); int bdrv_key_required(BlockDriverState *bs); int bdrv_set_key(BlockDriverState *bs, const char *key); diff --git a/include/block/block_int.h b/include/block/block_int.h index dda5ba0927..ba6e9ac696 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -442,8 +442,6 @@ struct BlockDriverState { char node_name[32]; /* element of the list of named nodes building the graph */ QTAILQ_ENTRY(BlockDriverState) node_list; - /* element of the list of "drives" the guest sees */ - QTAILQ_ENTRY(BlockDriverState) device_list; /* element of the list of all BlockDriverStates (all_bdrv_states) */ QTAILQ_ENTRY(BlockDriverState) bs_list; /* element of the list of monitor-owned BDS */ @@ -501,8 +499,6 @@ extern BlockDriver bdrv_file; extern BlockDriver bdrv_raw; extern BlockDriver bdrv_qcow2; -extern QTAILQ_HEAD(BdrvStates, BlockDriverState) bdrv_states; - /** * bdrv_setup_io_funcs: * @@ -512,6 +508,13 @@ extern QTAILQ_HEAD(BdrvStates, BlockDriverState) bdrv_states; */ void bdrv_setup_io_funcs(BlockDriver *bdrv); +int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs, + int64_t offset, unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags); +int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, + int64_t offset, unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags); + int get_tmp_filename(char *filename, int size); BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, const char *filename); @@ -696,6 +699,11 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, void hmp_drive_add_node(Monitor *mon, const char *optstr); +BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, + const char *child_name, + const BdrvChildRole *child_role); +void bdrv_root_unref_child(BdrvChild *child); + void blk_set_bs(BlockBackend *blk, BlockDriverState *bs); void blk_dev_change_media_cb(BlockBackend *blk, bool load); diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h index f60149978a..d08652aaa5 100644 --- a/include/qapi/qmp/qerror.h +++ b/include/qapi/qmp/qerror.h @@ -100,9 +100,6 @@ #define QERR_UNDEFINED_ERROR \ "An undefined error has occurred" -#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \ - "'%s' uses a %s feature which is not supported by this qemu version: %s" - #define QERR_UNSUPPORTED \ "this feature or command is not currently supported" diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 00d69baa07..d839bffeb0 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -59,11 +59,10 @@ typedef struct BlockDevOps { void (*resize_cb)(void *opaque); } BlockDevOps; -BlockBackend *blk_new(const char *name, Error **errp); -BlockBackend *blk_new_with_bs(const char *name, Error **errp); -BlockBackend *blk_new_open(const char *name, const char *filename, - const char *reference, QDict *options, int flags, - Error **errp); +BlockBackend *blk_new(Error **errp); +BlockBackend *blk_new_with_bs(Error **errp); +BlockBackend *blk_new_open(const char *filename, const char *reference, + QDict *options, int flags, Error **errp); int blk_get_refcnt(BlockBackend *blk); void blk_ref(BlockBackend *blk); void blk_unref(BlockBackend *blk); @@ -71,13 +70,14 @@ void blk_remove_all_bs(void); const char *blk_name(BlockBackend *blk); BlockBackend *blk_by_name(const char *name); BlockBackend *blk_next(BlockBackend *blk); +BlockDriverState *blk_next_root_bs(BlockDriverState *bs); +bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp); +void monitor_remove_blk(BlockBackend *blk); BlockDriverState *blk_bs(BlockBackend *blk); void blk_remove_bs(BlockBackend *blk); void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs); -void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk); - void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow); void blk_iostatus_enable(BlockBackend *blk); bool blk_iostatus_is_enabled(const BlockBackend *blk); @@ -127,6 +127,7 @@ int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors); int blk_co_flush(BlockBackend *blk); int blk_flush(BlockBackend *blk); int blk_flush_all(void); +int blk_commit_all(void); void blk_drain(BlockBackend *blk); void blk_drain_all(void); void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, diff --git a/monitor.c b/monitor.c index 894f862dd3..4c02f0f18f 100644 --- a/monitor.c +++ b/monitor.c @@ -42,6 +42,7 @@ #include "ui/console.h" #include "ui/input.h" #include "sysemu/blockdev.h" +#include "sysemu/block-backend.h" #include "audio/audio.h" #include "disas/disas.h" #include "sysemu/balloon.h" @@ -3483,7 +3484,7 @@ static void monitor_find_completion_by_table(Monitor *mon, int i; const char *ptype, *str, *name; const mon_cmd_t *cmd; - BlockDriverState *bs; + BlockBackend *blk = NULL; if (nb_args <= 1) { /* command completion */ @@ -3538,8 +3539,8 @@ static void monitor_find_completion_by_table(Monitor *mon, case 'B': /* block device name completion */ readline_set_completion_index(mon->rs, strlen(str)); - for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { - name = bdrv_get_device_name(bs); + while ((blk = blk_next(blk)) != NULL) { + name = blk_name(blk); if (str[0] == '\0' || !strncmp(name, str, strlen(str))) { readline_add_completion(mon->rs, name); diff --git a/qemu-char.c b/qemu-char.c index 0a14e57839..bfcf80dd10 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -25,6 +25,7 @@ #include "qemu-common.h" #include "monitor/monitor.h" #include "sysemu/sysemu.h" +#include "sysemu/block-backend.h" #include "qemu/error-report.h" #include "qemu/timer.h" #include "sysemu/char.h" @@ -628,7 +629,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) break; } case 's': - bdrv_commit_all(); + blk_commit_all(); break; case 'b': qemu_chr_be_event(chr, CHR_EVENT_BREAK); diff --git a/qemu-img.c b/qemu-img.c index 3103150717..29eae2a24b 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -245,8 +245,7 @@ static int img_open_password(BlockBackend *blk, const char *filename, } -static BlockBackend *img_open_opts(const char *id, - const char *optstr, +static BlockBackend *img_open_opts(const char *optstr, QemuOpts *opts, int flags, bool require_io, bool quiet) { @@ -254,7 +253,7 @@ static BlockBackend *img_open_opts(const char *id, Error *local_err = NULL; BlockBackend *blk; options = qemu_opts_to_qdict(opts, NULL); - blk = blk_new_open(id, NULL, NULL, options, flags, &local_err); + blk = blk_new_open(NULL, NULL, options, flags, &local_err); if (!blk) { error_reportf_err(local_err, "Could not open '%s'", optstr); return NULL; @@ -267,7 +266,7 @@ static BlockBackend *img_open_opts(const char *id, return blk; } -static BlockBackend *img_open_file(const char *id, const char *filename, +static BlockBackend *img_open_file(const char *filename, const char *fmt, int flags, bool require_io, bool quiet) { @@ -280,7 +279,7 @@ static BlockBackend *img_open_file(const char *id, const char *filename, qdict_put(options, "driver", qstring_from_str(fmt)); } - blk = blk_new_open(id, filename, NULL, options, flags, &local_err); + blk = blk_new_open(filename, NULL, options, flags, &local_err); if (!blk) { error_reportf_err(local_err, "Could not open '%s': ", filename); return NULL; @@ -294,8 +293,7 @@ static BlockBackend *img_open_file(const char *id, const char *filename, } -static BlockBackend *img_open(const char *id, - bool image_opts, +static BlockBackend *img_open(bool image_opts, const char *filename, const char *fmt, int flags, bool require_io, bool quiet) @@ -312,9 +310,9 @@ static BlockBackend *img_open(const char *id, if (!opts) { return NULL; } - blk = img_open_opts(id, filename, opts, flags, true, quiet); + blk = img_open_opts(filename, opts, flags, true, quiet); } else { - blk = img_open_file(id, filename, fmt, flags, true, quiet); + blk = img_open_file(filename, fmt, flags, true, quiet); } return blk; } @@ -686,7 +684,7 @@ static int img_check(int argc, char **argv) return 1; } - blk = img_open("image", image_opts, filename, fmt, flags, true, quiet); + blk = img_open(image_opts, filename, fmt, flags, true, quiet); if (!blk) { return 1; } @@ -878,7 +876,7 @@ static int img_commit(int argc, char **argv) return 1; } - blk = img_open("image", image_opts, filename, fmt, flags, true, quiet); + blk = img_open(image_opts, filename, fmt, flags, true, quiet); if (!blk) { return 1; } @@ -1212,13 +1210,13 @@ static int img_compare(int argc, char **argv) goto out3; } - blk1 = img_open("image_1", image_opts, filename1, fmt1, flags, true, quiet); + blk1 = img_open(image_opts, filename1, fmt1, flags, true, quiet); if (!blk1) { ret = 2; goto out3; } - blk2 = img_open("image_2", image_opts, filename2, fmt2, flags, true, quiet); + blk2 = img_open(image_opts, filename2, fmt2, flags, true, quiet); if (!blk2) { ret = 2; goto out2; @@ -1899,11 +1897,8 @@ static int img_convert(int argc, char **argv) total_sectors = 0; for (bs_i = 0; bs_i < bs_n; bs_i++) { - char *id = bs_n > 1 ? g_strdup_printf("source_%d", bs_i) - : g_strdup("source"); - blk[bs_i] = img_open(id, image_opts, argv[optind + bs_i], + blk[bs_i] = img_open(image_opts, argv[optind + bs_i], fmt, src_flags, true, quiet); - g_free(id); if (!blk[bs_i]) { ret = -1; goto out; @@ -2048,8 +2043,7 @@ static int img_convert(int argc, char **argv) * the bdrv_create() call which takes different params. * Not critical right now, so fix can wait... */ - out_blk = img_open_file("target", out_filename, - out_fmt, flags, true, quiet); + out_blk = img_open_file(out_filename, out_fmt, flags, true, quiet); if (!out_blk) { ret = -1; goto out; @@ -2240,7 +2234,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, } g_hash_table_insert(filenames, (gpointer)filename, NULL); - blk = img_open("image", image_opts, filename, fmt, + blk = img_open(image_opts, filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false); if (!blk) { @@ -2572,8 +2566,7 @@ static int img_map(int argc, char **argv) return 1; } - blk = img_open("image", image_opts, filename, fmt, - BDRV_O_FLAGS, true, false); + blk = img_open(image_opts, filename, fmt, BDRV_O_FLAGS, true, false); if (!blk) { return 1; } @@ -2718,8 +2711,7 @@ static int img_snapshot(int argc, char **argv) } /* Open the image */ - blk = img_open("image", image_opts, filename, NULL, - bdrv_oflags, true, quiet); + blk = img_open(image_opts, filename, NULL, bdrv_oflags, true, quiet); if (!blk) { return 1; } @@ -2890,7 +2882,7 @@ static int img_rebase(int argc, char **argv) * Ignore the old backing file for unsafe rebase in case we want to correct * the reference to a renamed or moved backing file. */ - blk = img_open("image", image_opts, filename, fmt, flags, true, quiet); + blk = img_open(image_opts, filename, fmt, flags, true, quiet); if (!blk) { ret = -1; goto out; @@ -2916,7 +2908,7 @@ static int img_rebase(int argc, char **argv) } bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); - blk_old_backing = blk_new_open("old_backing", backing_name, NULL, + blk_old_backing = blk_new_open(backing_name, NULL, options, src_flags, &local_err); if (!blk_old_backing) { error_reportf_err(local_err, @@ -2933,7 +2925,7 @@ static int img_rebase(int argc, char **argv) options = NULL; } - blk_new_backing = blk_new_open("new_backing", out_baseimg, NULL, + blk_new_backing = blk_new_open(out_baseimg, NULL, options, src_flags, &local_err); if (!blk_new_backing) { error_reportf_err(local_err, @@ -3227,7 +3219,7 @@ static int img_resize(int argc, char **argv) n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0); qemu_opts_del(param); - blk = img_open("image", image_opts, filename, fmt, + blk = img_open(image_opts, filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); if (!blk) { ret = -1; @@ -3387,7 +3379,7 @@ static int img_amend(int argc, char **argv) goto out; } - blk = img_open("image", image_opts, filename, fmt, flags, true, quiet); + blk = img_open(image_opts, filename, fmt, flags, true, quiet); if (!blk) { ret = -1; goto out; diff --git a/qemu-io.c b/qemu-io.c index 8c31257ac4..d7c2f26bbb 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -61,7 +61,7 @@ static int openfile(char *name, int flags, QDict *opts) return 1; } - qemuio_blk = blk_new_open("hda", name, NULL, opts, flags, &local_err); + qemuio_blk = blk_new_open(name, NULL, opts, flags, &local_err); if (!qemuio_blk) { error_reportf_err(local_err, "can't open%s%s: ", name ? " device " : "", name ?: ""); diff --git a/qemu-nbd.c b/qemu-nbd.c index a5c1d95344..d5f847386f 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -831,13 +831,13 @@ int main(int argc, char **argv) } options = qemu_opts_to_qdict(opts, NULL); qemu_opts_reset(&file_opts); - blk = blk_new_open("hda", NULL, NULL, options, flags, &local_err); + blk = blk_new_open(NULL, NULL, options, flags, &local_err); } else { if (fmt) { options = qdict_new(); qdict_put(options, "driver", qstring_from_str(fmt)); } - blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err); + blk = blk_new_open(srcpath, NULL, options, flags, &local_err); } if (!blk) { diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index e922de982f..b6d1e650db 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -1,5 +1,6 @@ stub-obj-y += arch-query-cpu-def.o -stub-obj-y += bdrv-commit-all.o +stub-obj-y += bdrv-next-monitor-owned.o +stub-obj-y += blk-commit-all.o stub-obj-y += blockdev-close-all-bdrv-states.o stub-obj-y += clock-warp.o stub-obj-y += cpu-get-clock.o diff --git a/stubs/bdrv-next-monitor-owned.c b/stubs/bdrv-next-monitor-owned.c new file mode 100644 index 0000000000..2acf6c3ec0 --- /dev/null +++ b/stubs/bdrv-next-monitor-owned.c @@ -0,0 +1,8 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "block/block.h" + +BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs) +{ + return NULL; +} diff --git a/stubs/bdrv-commit-all.c b/stubs/blk-commit-all.c similarity index 53% rename from stubs/bdrv-commit-all.c rename to stubs/blk-commit-all.c index bf84a1d85a..c82fb7f5f8 100644 --- a/stubs/bdrv-commit-all.c +++ b/stubs/blk-commit-all.c @@ -1,8 +1,8 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "block/block.h" +#include "sysemu/block-backend.h" -int bdrv_commit_all(void) +int blk_commit_all(void) { return 0; } diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out index f443635b25..9b009b8c15 100644 --- a/tests/qemu-iotests/036.out +++ b/tests/qemu-iotests/036.out @@ -22,18 +22,18 @@ autoclear_features 0x0 refcount_order 4 header_length 104 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: 8000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Unknown incompatible feature: 8000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature === Image with multiple incompatible feature bits === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: e000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: 6000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: c000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, Unknown incompatible feature: 8000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, test3 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test2, Unknown incompatible feature: a000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Unknown incompatible feature: e000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature, Unknown incompatible feature: 6000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature, Unknown incompatible feature: c000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): test1, test2, Unknown incompatible feature: 8000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): test1, test2, test3 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): test2, Unknown incompatible feature: a000000000000000 === Create image with unknown autoclear feature bit === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 0f8a8d3562..c1291ff317 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -5,16 +5,16 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/ === Unknown option === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0: Block format 'qcow2' used by device 'drive0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0: Block format 'qcow2' used by device 'drive0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0: Block format 'qcow2' used by device 'drive0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0: Block format 'qcow2' used by device 'drive0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' === Unknown protocol option === diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index 85fc05d05a..73cc15adeb 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -5,16 +5,16 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/ === Unknown option === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0: Block format 'qcow2' used by device 'drive0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0: Block format 'qcow2' used by device 'drive0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0: Block format 'qcow2' used by device 'drive0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0: Block format 'qcow2' used by device 'drive0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' === Unknown protocol option === diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index 7d62cd5840..d0662f95e8 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -21,7 +21,7 @@ QMP_VERSION {"error": {"class": "GenericError", "desc": "Device name 'test-node' conflicts with an existing node name"}} {"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}} {"error": {"class": "GenericError", "desc": "Duplicate node name"}} -{"error": {"class": "GenericError", "desc": "node-name=disk3 is conflicting with a device id"}} +{"error": {"class": "GenericError", "desc": "Device name 'disk3' conflicts with an existing node name"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} diff --git a/tests/qemu-iotests/148 b/tests/qemu-iotests/148 index 30bc37958e..d066ec3e41 100644 --- a/tests/qemu-iotests/148 +++ b/tests/qemu-iotests/148 @@ -35,6 +35,7 @@ sector_size = 512 offset = 10 class TestQuorumEvents(iotests.QMPTestCase): + read_pattern = 'quorum' def create_blkdebug_file(self, blkdebug_file, bad_sector): file = open(blkdebug_file, 'w') @@ -48,6 +49,7 @@ sector = "%d" def setUp(self): driveopts = ['driver=quorum', 'vote-threshold=2'] + driveopts.append('read-pattern=%s' % self.read_pattern) for i in range(len(imgs)): iotests.qemu_img('create', '-f', iotests.imgfmt, imgs[i], '1M') self.create_blkdebug_file(img_conf[i], i + offset) @@ -112,7 +114,11 @@ sector = "%d" self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % ((offset + i) * sector_size, sector_size)) self.vm.qtest("clock_step %d" % delay) - self.do_check_event('img%d' % i, offset + i) + # In fifo mode only errors in the first child are detected + if i > 0 and self.read_pattern == 'fifo': + self.do_check_event(None) + else: + self.do_check_event('img%d' % i, offset + i) # I/O errors in different children: all events are emitted delay = 2 * event_rate @@ -120,10 +126,17 @@ sector = "%d" self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % ((offset + i) * sector_size, sector_size)) self.vm.qtest("clock_step %d" % delay) - self.do_check_event('img%d' % i, offset + i) + # In fifo mode only errors in the first child are detected + if i > 0 and self.read_pattern == 'fifo': + self.do_check_event(None) + else: + self.do_check_event('img%d' % i, offset + i) # No more pending events self.do_check_event(None) +class TestFifoQuorumEvents(TestQuorumEvents): + read_pattern = 'fifo' + if __name__ == '__main__': iotests.main(supported_fmts=["raw"]) diff --git a/tests/qemu-iotests/148.out b/tests/qemu-iotests/148.out index ae1213e6f8..fbc63e62f8 100644 --- a/tests/qemu-iotests/148.out +++ b/tests/qemu-iotests/148.out @@ -1,5 +1,5 @@ -. +.. ---------------------------------------------------------------------- -Ran 1 tests +Ran 2 tests OK