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)
+/*
+ * Called by a driver that can only provide a read-only image.
+ *
+ * Returns 0 if the node is already read-only or it could switch the node to
+ * read-only because BDRV_O_AUTO_RDONLY is set.
+ *
+ * Returns -EACCES if the node is read-write and BDRV_O_AUTO_RDONLY is not set
+ * or bdrv_can_set_read_only() forbids making the node read-only. If @errmsg
+ * is not NULL, it is used as the error message for the Error object.
+ */
+int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
+ Error **errp)
{
int ret = 0;
- ret = bdrv_can_set_read_only(bs, read_only, false, errp);
+ if (!(bs->open_flags & BDRV_O_RDWR)) {
+ return 0;
+ }
+ if (!(bs->open_flags & BDRV_O_AUTO_RDONLY)) {
+ goto fail;
+ }
+
+ ret = bdrv_can_set_read_only(bs, true, false, NULL);
if (ret < 0) {
- return ret;
+ goto fail;
}
- bs->read_only = read_only;
+ bs->read_only = true;
+ bs->open_flags &= ~BDRV_O_RDWR;
+
return 0;
+
+fail:
+ error_setg(errp, "%s", errmsg ?: "Image is read-only");
+ return -EACCES;
}
void bdrv_get_full_backing_filename_from_filename(const char *backed,
}
}
+static BlockdevDetectZeroesOptions bdrv_parse_detect_zeroes(QemuOpts *opts,
+ int open_flags,
+ Error **errp)
+{
+ Error *local_err = NULL;
+ char *value = qemu_opt_get_del(opts, "detect-zeroes");
+ BlockdevDetectZeroesOptions detect_zeroes =
+ qapi_enum_parse(&BlockdevDetectZeroesOptions_lookup, value,
+ BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF, &local_err);
+ g_free(value);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return detect_zeroes;
+ }
+
+ if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
+ !(open_flags & BDRV_O_UNMAP))
+ {
+ error_setg(errp, "setting detect-zeroes to unmap is not allowed "
+ "without setting discard operation to unmap");
+ }
+
+ return detect_zeroes;
+}
+
/**
* Set open flags for a given discard mode
*
/* Inherit the read-only option from the parent if it's not set */
qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY);
/* Our block drivers take care to send flushes and respect unmap policy,
* so we can default to enable both on lower layers regardless of the
/* backing files always opened read-only */
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
+ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
flags &= ~BDRV_O_COPY_ON_READ;
/* snapshot=on is handled on the top layer */
*flags &= ~BDRV_O_CACHE_MASK;
assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
- if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
+ if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
*flags |= BDRV_O_NO_FLUSH;
}
assert(qemu_opt_find(opts, BDRV_OPT_CACHE_DIRECT));
- if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
+ if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_DIRECT, false)) {
*flags |= BDRV_O_NOCACHE;
}
*flags &= ~BDRV_O_RDWR;
assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY));
- if (!qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false)) {
+ if (!qemu_opt_get_bool_del(opts, BDRV_OPT_READ_ONLY, false)) {
*flags |= BDRV_O_RDWR;
}
+ assert(qemu_opt_find(opts, BDRV_OPT_AUTO_READ_ONLY));
+ if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
+ *flags |= BDRV_O_AUTO_RDONLY;
+ }
}
static void update_options_from_flags(QDict *options, int flags)
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
}
+ if (!qdict_haskey(options, BDRV_OPT_AUTO_READ_ONLY)) {
+ qdict_put_bool(options, BDRV_OPT_AUTO_READ_ONLY,
+ flags & BDRV_O_AUTO_RDONLY);
+ }
}
static void bdrv_assign_node_name(BlockDriverState *bs,
.type = QEMU_OPT_BOOL,
.help = "Node is opened in read-only mode",
},
+ {
+ .name = BDRV_OPT_AUTO_READ_ONLY,
+ .type = QEMU_OPT_BOOL,
+ .help = "Node can become read-only if opening read-write fails",
+ },
{
.name = "detect-zeroes",
.type = QEMU_OPT_STRING,
.help = "try to optimize zero writes (off, on, unmap)",
},
{
- .name = "discard",
+ .name = BDRV_OPT_DISCARD,
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
},
const char *driver_name = NULL;
const char *node_name = NULL;
const char *discard;
- const char *detect_zeroes;
QemuOpts *opts;
BlockDriver *drv;
Error *local_err = NULL;
}
}
- discard = qemu_opt_get(opts, "discard");
+ discard = qemu_opt_get(opts, BDRV_OPT_DISCARD);
if (discard != NULL) {
if (bdrv_parse_discard_flags(discard, &bs->open_flags) != 0) {
error_setg(errp, "Invalid discard option");
}
}
- detect_zeroes = qemu_opt_get(opts, "detect-zeroes");
- if (detect_zeroes) {
- BlockdevDetectZeroesOptions value =
- qapi_enum_parse(&BlockdevDetectZeroesOptions_lookup,
- detect_zeroes,
- BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
- &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- ret = -EINVAL;
- goto fail_opts;
- }
-
- if (value == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
- !(bs->open_flags & BDRV_O_UNMAP))
- {
- error_setg(errp, "setting detect-zeroes to unmap is not allowed "
- "without setting discard operation to unmap");
- ret = -EINVAL;
- goto fail_opts;
- }
-
- bs->detect_zeroes = value;
+ bs->detect_zeroes =
+ bdrv_parse_detect_zeroes(opts, bs->open_flags, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto fail_opts;
}
if (filename != NULL) {
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");
+ qdict_set_default_str(qdict, BDRV_OPT_AUTO_READ_ONLY, "off");
+
}
bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
BlockDriver *drv;
QemuOpts *opts;
QDict *orig_reopen_opts;
- const char *value;
+ char *discard = NULL;
bool read_only;
assert(reopen_state != NULL);
update_flags_from_options(&reopen_state->flags, opts);
- /* node-name and driver must be unchanged. Put them back into the QDict, so
- * that they are checked at the end of this function. */
- value = qemu_opt_get(opts, "node-name");
- if (value) {
- qdict_put_str(reopen_state->options, "node-name", value);
+ discard = qemu_opt_get_del(opts, BDRV_OPT_DISCARD);
+ if (discard != NULL) {
+ if (bdrv_parse_discard_flags(discard, &reopen_state->flags) != 0) {
+ error_setg(errp, "Invalid discard option");
+ ret = -EINVAL;
+ goto error;
+ }
}
- value = qemu_opt_get(opts, "driver");
- if (value) {
- qdict_put_str(reopen_state->options, "driver", value);
+ reopen_state->detect_zeroes =
+ bdrv_parse_detect_zeroes(opts, reopen_state->flags, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto error;
}
+ /* All other options (including node-name and driver) must be unchanged.
+ * Put them back into the QDict, so that they are checked at the end
+ * of this function. */
+ qemu_opts_to_qdict(opts, reopen_state->options);
+
/* If we are to stay read-only, do not allow permission change
* to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is
* not set, or if the BDS still has copy_on_read enabled */
error:
qemu_opts_del(opts);
qobject_unref(orig_reopen_opts);
+ g_free(discard);
return ret;
}
bs->options = reopen_state->options;
bs->open_flags = reopen_state->flags;
bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
+ bs->detect_zeroes = reopen_state->detect_zeroes;
/* Remove child references from bs->options and bs->explicit_options.
* Child options were already removed in bdrv_reopen_queue_child() */
uint64_t perm, shared_perm;
Error *local_err = NULL;
int ret;
+ BdrvDirtyBitmap *bm;
if (!bs->drv) {
return;
}
}
+ for (bm = bdrv_dirty_bitmap_next(bs, NULL); bm;
+ bm = bdrv_dirty_bitmap_next(bs, bm))
+ {
+ bdrv_dirty_bitmap_set_migration(bm, false);
+ }
+
ret = refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) {
bs->open_flags |= BDRV_O_INACTIVE;
}
}
- /* At this point persistent bitmaps should be already stored by the format
- * driver */
- bdrv_release_persistent_dirty_bitmaps(bs);
-
return 0;
}
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
if (!QLIST_EMPTY(&bs->op_blockers[op])) {
blocker = QLIST_FIRST(&bs->op_blockers[op]);
- error_propagate(errp, error_copy(blocker->reason));
- error_prepend(errp, "Node '%s' is busy: ",
- bdrv_get_device_or_node_name(bs));
+ error_propagate_prepend(errp, error_copy(blocker->reason),
+ "Node '%s' is busy: ",
+ bdrv_get_device_or_node_name(bs));
return true;
}
return false;
if (options) {
qemu_opts_do_parse(opts, options, NULL, &local_err);
if (local_err) {
- error_report_err(local_err);
- local_err = NULL;
- error_setg(errp, "Invalid options for file format '%s'", fmt);
goto out;
}
}