block: Add "read-only" to the options QDict
This adds the "read-only" option to the QDict. One important effect of this change is that when a child inherits options from its parent, the existing "read-only" mode can be preserved if it was explicitly set previously. This addresses scenarios like this: [E] <- [D] <- [C] <- [B] <- [A] In this case, if we reopen [D] with read-only=off, and later reopen [B], then [D] will not inherit read-only=on from its parent during the bdrv_reopen_queue_child() stage. The BDRV_O_RDWR flag is not removed yet, but its keep in sync with the value of the "read-only" option. Signed-off-by: Alberto Garcia <berto@igalia.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
9b7e869167
commit
f87a0e29a9
38
block.c
38
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_DIRECT, "off");
|
||||||
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
|
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
|
/* aio=native doesn't work for cache.direct=off, so disable it for the
|
||||||
* temporary snapshot */
|
* temporary snapshot */
|
||||||
*child_flags &= ~BDRV_O_NATIVE_AIO;
|
*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_DIRECT);
|
||||||
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
|
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,
|
/* 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
|
* so we can default to enable both on lower layers regardless of the
|
||||||
* corresponding parent options. */
|
* 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);
|
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
|
||||||
|
|
||||||
/* backing files always opened read-only */
|
/* 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 */
|
/* snapshot=on is handled on the top layer */
|
||||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
|
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)) {
|
if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
|
||||||
*flags |= BDRV_O_NOCACHE;
|
*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)
|
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,
|
qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
|
||||||
qbool_from_bool(flags & BDRV_O_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,
|
static void bdrv_assign_node_name(BlockDriverState *bs,
|
||||||
|
@ -930,6 +949,11 @@ static QemuOptsList bdrv_runtime_opts = {
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
.help = "Ignore flush requests",
|
.help = "Ignore flush requests",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = BDRV_OPT_READ_ONLY,
|
||||||
|
.type = QEMU_OPT_BOOL,
|
||||||
|
.help = "Node is opened in read-only mode",
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1674,14 +1698,22 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & BDRV_O_RDWR) {
|
/* Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags.
|
||||||
flags |= BDRV_O_ALLOW_RDWR;
|
* 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) {
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
snapshot_options = qdict_new();
|
snapshot_options = qdict_new();
|
||||||
bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options,
|
bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options,
|
||||||
flags, options);
|
flags, options);
|
||||||
|
/* Let bdrv_backing_options() override "read-only" */
|
||||||
|
qdict_del(options, BDRV_OPT_READ_ONLY);
|
||||||
bdrv_backing_options(&flags, options, flags, options);
|
bdrv_backing_options(&flags, options, flags, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2971,7 +2971,8 @@ static BlockDriver vvfat_write_target = {
|
||||||
static void vvfat_qcow_options(int *child_flags, QDict *child_options,
|
static void vvfat_qcow_options(int *child_flags, QDict *child_options,
|
||||||
int parent_flags, QDict *parent_options)
|
int parent_flags, QDict *parent_options)
|
||||||
{
|
{
|
||||||
*child_flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
|
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
|
||||||
|
*child_flags = BDRV_O_NO_FLUSH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const BdrvChildRole child_vvfat_qcow = {
|
static const BdrvChildRole child_vvfat_qcow = {
|
||||||
|
|
16
blockdev.c
16
blockdev.c
|
@ -360,9 +360,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
|
||||||
const char *aio;
|
const char *aio;
|
||||||
|
|
||||||
if (bdrv_flags) {
|
if (bdrv_flags) {
|
||||||
if (!qemu_opt_get_bool(opts, "read-only", false)) {
|
|
||||||
*bdrv_flags |= BDRV_O_RDWR;
|
|
||||||
}
|
|
||||||
if (qemu_opt_get_bool(opts, "copy-on-read", false)) {
|
if (qemu_opt_get_bool(opts, "copy-on-read", false)) {
|
||||||
*bdrv_flags |= BDRV_O_COPY_ON_READ;
|
*bdrv_flags |= BDRV_O_COPY_ON_READ;
|
||||||
}
|
}
|
||||||
|
@ -471,7 +468,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||||
int bdrv_flags = 0;
|
int bdrv_flags = 0;
|
||||||
int on_read_error, on_write_error;
|
int on_read_error, on_write_error;
|
||||||
bool account_invalid, account_failed;
|
bool account_invalid, account_failed;
|
||||||
bool writethrough;
|
bool writethrough, read_only;
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
ThrottleConfig cfg;
|
ThrottleConfig cfg;
|
||||||
|
@ -567,6 +564,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||||
bdrv_flags |= BDRV_O_SNAPSHOT;
|
bdrv_flags |= BDRV_O_SNAPSHOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read_only = qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false);
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
if ((!file || !*file) && !qdict_size(bs_opts)) {
|
if ((!file || !*file) && !qdict_size(bs_opts)) {
|
||||||
BlockBackendRootState *blk_rs;
|
BlockBackendRootState *blk_rs;
|
||||||
|
@ -574,7 +573,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||||
blk = blk_new();
|
blk = blk_new();
|
||||||
blk_rs = blk_get_root_state(blk);
|
blk_rs = blk_get_root_state(blk);
|
||||||
blk_rs->open_flags = bdrv_flags;
|
blk_rs->open_flags = bdrv_flags;
|
||||||
blk_rs->read_only = !(bdrv_flags & BDRV_O_RDWR);
|
blk_rs->read_only = read_only;
|
||||||
blk_rs->detect_zeroes = detect_zeroes;
|
blk_rs->detect_zeroes = detect_zeroes;
|
||||||
|
|
||||||
QDECREF(bs_opts);
|
QDECREF(bs_opts);
|
||||||
|
@ -588,6 +587,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||||
* Apply the defaults here instead. */
|
* Apply the defaults here instead. */
|
||||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
|
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
|
||||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
|
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
|
||||||
|
qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY,
|
||||||
|
read_only ? "on" : "off");
|
||||||
assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
|
assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
|
||||||
|
|
||||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||||
|
@ -682,6 +683,7 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
|
||||||
* Apply the defaults here instead. */
|
* Apply the defaults here instead. */
|
||||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
|
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
|
||||||
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
|
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
|
||||||
|
qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY, "off");
|
||||||
|
|
||||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||||
bdrv_flags |= BDRV_O_INACTIVE;
|
bdrv_flags |= BDRV_O_INACTIVE;
|
||||||
|
@ -4158,10 +4160,6 @@ static QemuOptsList qemu_root_bds_opts = {
|
||||||
.name = "aio",
|
.name = "aio",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "host AIO implementation (threads, native)",
|
.help = "host AIO implementation (threads, native)",
|
||||||
},{
|
|
||||||
.name = "read-only",
|
|
||||||
.type = QEMU_OPT_BOOL,
|
|
||||||
.help = "open drive file as read-only",
|
|
||||||
},{
|
},{
|
||||||
.name = "copy-on-read",
|
.name = "copy-on-read",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
|
|
|
@ -107,6 +107,7 @@ typedef struct HDGeometry {
|
||||||
#define BDRV_OPT_CACHE_WB "cache.writeback"
|
#define BDRV_OPT_CACHE_WB "cache.writeback"
|
||||||
#define BDRV_OPT_CACHE_DIRECT "cache.direct"
|
#define BDRV_OPT_CACHE_DIRECT "cache.direct"
|
||||||
#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
|
#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
|
||||||
|
#define BDRV_OPT_READ_ONLY "read-only"
|
||||||
|
|
||||||
|
|
||||||
#define BDRV_SECTOR_BITS 9
|
#define BDRV_SECTOR_BITS 9
|
||||||
|
|
Loading…
Reference in New Issue