diff options
Diffstat (limited to 'block.c')
| -rw-r--r-- | block.c | 90 |
1 files changed, 67 insertions, 23 deletions
diff --git a/block.c b/block.c index 684cb018da..6c8ef98dfa 100644 --- a/block.c +++ b/block.c @@ -261,6 +261,11 @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, return 0; } +/* TODO Remove (deprecated since 2.11) + * Block drivers are not supposed to automatically change bs->read_only. + * Instead, they should just check whether they can provide what the user + * explicitly requested and error out if read-write is requested, but they can + * only provide read-only access. */ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp) { int ret = 0; @@ -715,6 +720,10 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint) { BlockDriver *drv = bs->drv; + if (!drv) { + return -ENOMEDIUM; + } + /* Do not attempt drv->bdrv_getlength() on scsi-generic devices */ if (bdrv_is_sg(bs)) return 0; @@ -998,7 +1007,7 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, ret = bdrv_change_backing_file(parent, filename, base->drv ? base->drv->format_name : ""); if (ret < 0) { - error_setg_errno(errp, ret, "Could not update backing file link"); + error_setg_errno(errp, -ret, "Could not update backing file link"); } if (!(orig_flags & BDRV_O_RDWR)) { @@ -3069,19 +3078,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, const QDictEntry *entry = qdict_first(reopen_state->options); do { - QString *new_obj = qobject_to_qstring(entry->value); - const char *new = qstring_get_str(new_obj); + QObject *new = entry->value; + QObject *old = qdict_get(reopen_state->bs->options, entry->key); + /* - * Caution: while qdict_get_try_str() is fine, getting - * non-string types would require more care. When - * bs->options come from -blockdev or blockdev_add, its - * members are typed according to the QAPI schema, but - * when they come from -drive, they're all QString. + * TODO: When using -drive to specify blockdev options, all values + * will be strings; however, when using -blockdev, blockdev-add or + * filenames using the json:{} pseudo-protocol, they will be + * correctly typed. + * In contrast, reopening options are (currently) always strings + * (because you can only specify them through qemu-io; all other + * callers do not specify any options). + * Therefore, when using anything other than -drive to create a BDS, + * this cannot detect non-string options as unchanged, because + * qobject_is_equal() always returns false for objects of different + * type. In the future, this should be remedied by correctly typing + * all options. For now, this is not too big of an issue because + * the user can simply omit options which cannot be changed anyway, + * so they will stay unchanged. */ - const char *old = qdict_get_try_str(reopen_state->bs->options, - entry->key); - - if (!old || strcmp(new, old)) { + if (!qobject_is_equal(new, old)) { error_setg(errp, "Cannot change the option '%s'", entry->key); ret = -EINVAL; goto error; @@ -3419,6 +3435,10 @@ int bdrv_change_backing_file(BlockDriverState *bs, BlockDriver *drv = bs->drv; int ret; + if (!drv) { + return -ENOMEDIUM; + } + /* Backing file format doesn't make sense without a backing file */ if (backing_fmt && !backing_file) { return -EINVAL; @@ -3904,7 +3924,9 @@ int bdrv_has_zero_init_1(BlockDriverState *bs) int bdrv_has_zero_init(BlockDriverState *bs) { - assert(bs->drv); + if (!bs->drv) { + return 0; + } /* If BS is a copy on write image, it is initialized to the contents of the base image, which may not be zeroes. */ @@ -4169,7 +4191,29 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) } } + /* + * Update permissions, they may differ for inactive nodes. + * + * Note that the required permissions of inactive images are always a + * subset of the permissions required after activating the image. This + * allows us to just get the permissions upfront without restricting + * drv->bdrv_invalidate_cache(). + * + * It also means that in error cases, we don't have to try and revert to + * the old permissions (which is an operation that could fail, too). We can + * just keep the extended permissions for the next time that an activation + * of the image is tried. + */ bs->open_flags &= ~BDRV_O_INACTIVE; + bdrv_get_cumulative_perm(bs, &perm, &shared_perm); + ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &local_err); + if (ret < 0) { + bs->open_flags |= BDRV_O_INACTIVE; + error_propagate(errp, local_err); + return; + } + bdrv_set_perm(bs, perm, shared_perm); + if (bs->drv->bdrv_invalidate_cache) { bs->drv->bdrv_invalidate_cache(bs, &local_err); if (local_err) { @@ -4186,16 +4230,6 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) return; } - /* Update permissions, they may differ for inactive nodes */ - bdrv_get_cumulative_perm(bs, &perm, &shared_perm); - ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &local_err); - if (ret < 0) { - bs->open_flags |= BDRV_O_INACTIVE; - error_propagate(errp, local_err); - return; - } - bdrv_set_perm(bs, perm, shared_perm); - QLIST_FOREACH(parent, &bs->parents, next_parent) { if (parent->role->activate) { parent->role->activate(parent, &local_err); @@ -4221,6 +4255,7 @@ void bdrv_invalidate_cache_all(Error **errp) aio_context_release(aio_context); if (local_err) { error_propagate(errp, local_err); + bdrv_next_cleanup(&it); return; } } @@ -4232,6 +4267,10 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs, BdrvChild *child, *parent; int ret; + if (!bs->drv) { + return -ENOMEDIUM; + } + if (!setting_flag && bs->drv->bdrv_inactivate) { ret = bs->drv->bdrv_inactivate(bs); if (ret < 0) { @@ -4292,6 +4331,7 @@ int bdrv_inactivate_all(void) for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { ret = bdrv_inactivate_recurse(bs, pass); if (ret < 0) { + bdrv_next_cleanup(&it); goto out; } } @@ -4766,6 +4806,9 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs, int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts, BlockDriverAmendStatusCB *status_cb, void *cb_opaque) { + if (!bs->drv) { + return -ENOMEDIUM; + } if (!bs->drv->bdrv_amend_options) { return -ENOTSUP; } @@ -4823,6 +4866,7 @@ bool bdrv_is_first_non_filter(BlockDriverState *candidate) /* candidate is the first non filter */ if (perm) { + bdrv_next_cleanup(&it); return true; } } |