X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;ds=sidebyside;f=block.c;h=a2caadf0a07ac8ac8e5abe35bac603a3aae9d3fd;hb=da9f80fbad21319194e73355dea8a1cff6a574e4;hp=a8da4f2b2558f96ea0c6fda37e6eb5ec076d9e6e;hpb=799044b6a3a0fc63e1e020e4d9266786a2dc7a0b;p=mirror_qemu.git diff --git a/block.c b/block.c index a8da4f2b25..a2caadf0a0 100644 --- a/block.c +++ b/block.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu/osdep.h" #include "block/trace.h" #include "block/block_int.h" @@ -29,17 +30,20 @@ #include "qemu/error-report.h" #include "module_block.h" #include "qemu/module.h" -#include "qapi/qmp/qerror.h" -#include "qapi/qmp/qbool.h" +#include "qapi/error.h" +#include "qapi/qmp/qdict.h" #include "qapi/qmp/qjson.h" +#include "qapi/qmp/qnull.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qobject-output-visitor.h" +#include "qapi/qapi-visit-block-core.h" #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "qemu/notify.h" +#include "qemu/option.h" #include "qemu/coroutine.h" #include "block/qapi.h" -#include "qmp-commands.h" #include "qemu/timer.h" -#include "qapi-event.h" #include "qemu/cutils.h" #include "qemu/id.h" @@ -367,7 +371,7 @@ BlockDriver *bdrv_find_format(const char *format_name) return bdrv_do_find_format(format_name); } -static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) +int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) { static const char *whitelist_rw[] = { CONFIG_BDRV_RW_WHITELIST @@ -417,7 +421,7 @@ static void coroutine_fn bdrv_create_co_entry(void *opaque) CreateCo *cco = opaque; assert(cco->drv); - ret = cco->drv->bdrv_create(cco->filename, cco->opts, &local_err); + ret = cco->drv->bdrv_co_create_opts(cco->filename, cco->opts, &local_err); error_propagate(&cco->err, local_err); cco->ret = ret; } @@ -436,7 +440,7 @@ int bdrv_create(BlockDriver *drv, const char* filename, .err = NULL, }; - if (!drv->bdrv_create) { + if (!drv->bdrv_co_create_opts) { error_setg(errp, "Driver '%s' does not support image creation", drv->format_name); ret = -ENOTSUP; goto out; @@ -1454,7 +1458,7 @@ static QDict *parse_json_filename(const char *filename, Error **errp) return NULL; } - options = qobject_to_qdict(options_obj); + options = qobject_to(QDict, options_obj); if (!options) { qobject_decref(options_obj); error_setg(errp, "Invalid JSON object given"); @@ -2405,6 +2409,51 @@ BdrvChild *bdrv_open_child(const char *filename, return c; } +/* TODO Future callers may need to specify parent/child_role in order for + * option inheritance to work. Existing callers use it for the root node. */ +BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) +{ + BlockDriverState *bs = NULL; + Error *local_err = NULL; + QObject *obj = NULL; + QDict *qdict = NULL; + const char *reference = NULL; + Visitor *v = NULL; + + if (ref->type == QTYPE_QSTRING) { + reference = ref->u.reference; + } else { + BlockdevOptions *options = &ref->u.definition; + assert(ref->type == QTYPE_QDICT); + + v = qobject_output_visitor_new(&obj); + visit_type_BlockdevOptions(v, NULL, &options, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto fail; + } + visit_complete(v, &obj); + + qdict = qobject_to(QDict, obj); + qdict_flatten(qdict); + + /* bdrv_open_inherit() defaults to the values in bdrv_flags (for + * compatibility with other callers) rather than what we want as the + * real defaults. Apply the defaults here instead. */ + qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); + qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); + qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off"); + } + + bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp); + obj = NULL; + +fail: + qobject_decref(obj); + visit_free(v); + return bs; +} + static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, QDict *snapshot_options, @@ -2597,7 +2646,13 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, /* See cautionary note on accessing @options above */ backing = qdict_get_try_str(options, "backing"); - if (backing && *backing == '\0') { + if (qobject_to(QNull, qdict_get(options, "backing")) != NULL || + (backing && *backing == '\0')) + { + if (backing) { + warn_report("Use of \"backing\": \"\" is deprecated; " + "use \"backing\": null instead"); + } flags |= BDRV_O_NO_BACKING; qdict_del(options, "backing"); } @@ -2835,8 +2890,16 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, /* Inherit from parent node */ if (parent_options) { + QemuOpts *opts; + QDict *options_copy; assert(!flags); role->inherit_options(&flags, options, parent_flags, parent_options); + options_copy = qdict_clone_shallow(options); + opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); + qemu_opts_absorb_qdict(opts, options_copy, NULL); + update_flags_from_options(&flags, opts); + qemu_opts_del(opts); + QDECREF(options_copy); } /* Old values are used for options that aren't set yet */ @@ -3454,17 +3517,54 @@ static void bdrv_delete(BlockDriverState *bs) * free of errors) or -errno when an internal error occurred. The results of the * check are stored in res. */ -int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix) +static int coroutine_fn bdrv_co_check(BlockDriverState *bs, + BdrvCheckResult *res, BdrvCheckMode fix) { if (bs->drv == NULL) { return -ENOMEDIUM; } - if (bs->drv->bdrv_check == NULL) { + if (bs->drv->bdrv_co_check == NULL) { return -ENOTSUP; } memset(res, 0, sizeof(*res)); - return bs->drv->bdrv_check(bs, res, fix); + return bs->drv->bdrv_co_check(bs, res, fix); +} + +typedef struct CheckCo { + BlockDriverState *bs; + BdrvCheckResult *res; + BdrvCheckMode fix; + int ret; +} CheckCo; + +static void bdrv_check_co_entry(void *opaque) +{ + CheckCo *cco = opaque; + cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix); +} + +int bdrv_check(BlockDriverState *bs, + BdrvCheckResult *res, BdrvCheckMode fix) +{ + Coroutine *co; + CheckCo cco = { + .bs = bs, + .res = res, + .ret = -EINPROGRESS, + .fix = fix, + }; + + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + bdrv_check_co_entry(&cco); + } else { + co = qemu_coroutine_create(bdrv_check_co_entry, &cco); + qemu_coroutine_enter(co); + BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS); + } + + return cco.ret; } /* @@ -3586,12 +3686,12 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, GSList *ignore_children = g_slist_prepend(NULL, c); bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm, ignore_children, &local_err); + g_slist_free(ignore_children); if (local_err) { ret = -EPERM; error_report_err(local_err); goto exit; } - g_slist_free(ignore_children); /* If so, update the backing file path in the image file */ if (c->role->update_filename) { @@ -3634,6 +3734,11 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, error_setg(errp, "No medium inserted"); return -ENOMEDIUM; } + if (offset < 0) { + error_setg(errp, "Image size cannot be negative"); + return -EINVAL; + } + if (!drv->bdrv_truncate) { if (bs->file && drv->is_filter) { return bdrv_truncate(bs->file, offset, prealloc, errp); @@ -4007,17 +4112,11 @@ bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs) bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs) { - BlockDriverInfo bdi; - if (!(bs->open_flags & BDRV_O_UNMAP)) { return false; } - if (bdrv_get_info(bs, &bdi) == 0) { - return bdi.can_write_zeroes_with_unmap; - } - - return false; + return bs->supported_zero_flags & BDRV_REQ_MAY_UNMAP; } const char *bdrv_get_encrypted_filename(BlockDriverState *bs) @@ -4214,7 +4313,8 @@ void bdrv_init_with_whitelist(void) bdrv_init(); } -void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) +static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, + Error **errp) { BdrvChild *child, *parent; uint64_t perm, shared_perm; @@ -4230,7 +4330,7 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) } QLIST_FOREACH(child, &bs->children, next) { - bdrv_invalidate_cache(child->bs, &local_err); + bdrv_co_invalidate_cache(child->bs, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -4260,8 +4360,8 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) } bdrv_set_perm(bs, perm, shared_perm); - if (bs->drv->bdrv_invalidate_cache) { - bs->drv->bdrv_invalidate_cache(bs, &local_err); + if (bs->drv->bdrv_co_invalidate_cache) { + bs->drv->bdrv_co_invalidate_cache(bs, &local_err); if (local_err) { bs->open_flags |= BDRV_O_INACTIVE; error_propagate(errp, local_err); @@ -4287,6 +4387,38 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) } } +typedef struct InvalidateCacheCo { + BlockDriverState *bs; + Error **errp; + bool done; +} InvalidateCacheCo; + +static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque) +{ + InvalidateCacheCo *ico = opaque; + bdrv_co_invalidate_cache(ico->bs, ico->errp); + ico->done = true; +} + +void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) +{ + Coroutine *co; + InvalidateCacheCo ico = { + .bs = bs, + .done = false, + .errp = errp + }; + + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + bdrv_invalidate_cache_co_entry(&ico); + } else { + co = qemu_coroutine_create(bdrv_invalidate_cache_co_entry, &ico); + qemu_coroutine_enter(co); + BDRV_POLL_WHILE(bs, !ico.done); + } +} + void bdrv_invalidate_cache_all(Error **errp) { BlockDriverState *bs; @@ -4716,7 +4848,12 @@ out: AioContext *bdrv_get_aio_context(BlockDriverState *bs) { - return bs->aio_context; + return bs ? bs->aio_context : qemu_get_aio_context(); +} + +AioWait *bdrv_get_aio_wait(BlockDriverState *bs) +{ + return bs ? &bs->wait : NULL; } void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co)