aboutsummaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'block.c')
-rw-r--r--block.c89
1 files changed, 65 insertions, 24 deletions
diff --git a/block.c b/block.c
index afaff93423..493ecf3137 100644
--- a/block.c
+++ b/block.c
@@ -733,6 +733,9 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options,
qdict_set_default_str(child_options, BDRV_OPT_CACHE_DIRECT, "off");
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
+ /* Copy the read-only option from the parent */
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
+
/* aio=native doesn't work for cache.direct=off, so disable it for the
* temporary snapshot */
*child_flags &= ~BDRV_O_NATIVE_AIO;
@@ -755,6 +758,9 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
+ /* Inherit the read-only option from the parent if it's not set */
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_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
* corresponding parent options. */
@@ -808,7 +814,8 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
/* backing files always opened read-only */
- flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
+ qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
+ flags &= ~BDRV_O_COPY_ON_READ;
/* snapshot=on is handled on the top layer */
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
@@ -855,6 +862,14 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
if (qemu_opt_get_bool(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)) {
+ *flags |= BDRV_O_RDWR;
+ }
+
}
static void update_options_from_flags(QDict *options, int flags)
@@ -867,6 +882,10 @@ static void update_options_from_flags(QDict *options, int flags)
qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
qbool_from_bool(flags & BDRV_O_NO_FLUSH));
}
+ if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
+ qdict_put(options, BDRV_OPT_READ_ONLY,
+ qbool_from_bool(!(flags & BDRV_O_RDWR)));
+ }
}
static void bdrv_assign_node_name(BlockDriverState *bs,
@@ -930,6 +949,11 @@ static QemuOptsList bdrv_runtime_opts = {
.type = QEMU_OPT_BOOL,
.help = "Ignore flush requests",
},
+ {
+ .name = BDRV_OPT_READ_ONLY,
+ .type = QEMU_OPT_BOOL,
+ .help = "Node is opened in read-only mode",
+ },
{ /* end of list */ }
},
};
@@ -961,6 +985,8 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
goto fail_opts;
}
+ update_flags_from_options(&bs->open_flags, opts);
+
driver_name = qemu_opt_get(opts, "driver");
drv = bdrv_find_format(driver_name);
assert(drv != NULL);
@@ -1022,9 +1048,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
bs->drv = drv;
bs->opaque = g_malloc0(drv->instance_size);
- /* Apply cache mode options */
- update_flags_from_options(&bs->open_flags, opts);
-
/* Open the image, either directly or using a protocol */
open_flags = bdrv_open_flags(bs, bs->open_flags);
if (drv->bdrv_file_open) {
@@ -1675,6 +1698,25 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
goto fail;
}
+ /* Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags.
+ * FIXME: we're parsing the QDict to avoid having to create a
+ * QemuOpts just for this, but neither option is optimal. */
+ if (g_strcmp0(qdict_get_try_str(options, BDRV_OPT_READ_ONLY), "on") &&
+ !qdict_get_try_bool(options, BDRV_OPT_READ_ONLY, false)) {
+ flags |= (BDRV_O_RDWR | BDRV_O_ALLOW_RDWR);
+ } else {
+ flags &= ~BDRV_O_RDWR;
+ }
+
+ if (flags & BDRV_O_SNAPSHOT) {
+ snapshot_options = qdict_new();
+ bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options,
+ flags, options);
+ /* Let bdrv_backing_options() override "read-only" */
+ qdict_del(options, BDRV_OPT_READ_ONLY);
+ bdrv_backing_options(&flags, options, flags, options);
+ }
+
bs->open_flags = flags;
bs->options = options;
options = qdict_clone_shallow(options);
@@ -1699,18 +1741,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
/* Open image file without format layer */
if ((flags & BDRV_O_PROTOCOL) == 0) {
- if (flags & BDRV_O_RDWR) {
- flags |= BDRV_O_ALLOW_RDWR;
- }
- if (flags & BDRV_O_SNAPSHOT) {
- snapshot_options = qdict_new();
- bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options,
- flags, options);
- bdrv_backing_options(&flags, options, flags, options);
- }
-
- bs->open_flags = flags;
-
file = bdrv_open_child(filename, options, "file", bs,
&child_file, true, &local_err);
if (local_err) {
@@ -1895,6 +1925,13 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
options = qdict_new();
}
+ /* Check if this BlockDriverState is already in the queue */
+ QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
+ if (bs == bs_entry->state.bs) {
+ break;
+ }
+ }
+
/*
* Precedence of options:
* 1. Explicitly passed in options (highest)
@@ -1915,7 +1952,11 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
}
/* Old explicitly set values (don't overwrite by inherited value) */
- old_options = qdict_clone_shallow(bs->explicit_options);
+ if (bs_entry) {
+ old_options = qdict_clone_shallow(bs_entry->state.explicit_options);
+ } else {
+ old_options = qdict_clone_shallow(bs->explicit_options);
+ }
bdrv_join_options(bs, options, old_options);
QDECREF(old_options);
@@ -1954,8 +1995,13 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
child->role, options, flags);
}
- bs_entry = g_new0(BlockReopenQueueEntry, 1);
- QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry);
+ if (!bs_entry) {
+ bs_entry = g_new0(BlockReopenQueueEntry, 1);
+ QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry);
+ } else {
+ QDECREF(bs_entry->state.options);
+ QDECREF(bs_entry->state.explicit_options);
+ }
bs_entry->state.bs = bs;
bs_entry->state.options = options;
@@ -3013,11 +3059,6 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
return false;
}
-int bdrv_is_snapshot(BlockDriverState *bs)
-{
- return !!(bs->open_flags & BDRV_O_SNAPSHOT);
-}
-
/* backing_file can either be relative, or absolute, or a protocol. If it is
* relative, it must be relative to the chain. So, passing in bs->filename
* from a BDS as backing_file should not be done, as that may be relative to