diff --git a/block.c b/block.c index d0d9669b66..1894f1bd62 100644 --- a/block.c +++ b/block.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/qmp/qerror.h" +#include "qapi/qmp/qbool.h" #include "qapi/qmp/qjson.h" #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" @@ -706,9 +707,16 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, /* Enable protocol handling, disable format probing for bs->file */ flags |= BDRV_O_PROTOCOL; + /* If the cache mode isn't explicitly set, inherit direct and no-flush from + * the parent. */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); + /* Our block drivers take care to send flushes and respect unmap policy, - * so we can enable both unconditionally on lower layers. */ - flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP; + * so we can default to enable both on lower layers regardless of the + * corresponding parent options. */ + qdict_set_default_str(child_options, BDRV_OPT_CACHE_WB, "on"); + flags |= BDRV_O_UNMAP; /* Clear flags that only apply to the top layer */ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ); @@ -747,6 +755,11 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options, { int flags = parent_flags; + /* The cache mode is inherited unmodified for backing files */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_WB); + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); + 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); @@ -780,6 +793,42 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) return open_flags; } +static void update_flags_from_options(int *flags, QemuOpts *opts) +{ + *flags &= ~BDRV_O_CACHE_MASK; + + assert(qemu_opt_find(opts, BDRV_OPT_CACHE_WB)); + if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, false)) { + *flags |= BDRV_O_CACHE_WB; + } + + assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH)); + if (qemu_opt_get_bool(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)) { + *flags |= BDRV_O_NOCACHE; + } +} + +static void update_options_from_flags(QDict *options, int flags) +{ + if (!qdict_haskey(options, BDRV_OPT_CACHE_WB)) { + qdict_put(options, BDRV_OPT_CACHE_WB, + qbool_from_bool(flags & BDRV_O_CACHE_WB)); + } + if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) { + qdict_put(options, BDRV_OPT_CACHE_DIRECT, + qbool_from_bool(flags & BDRV_O_NOCACHE)); + } + if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) { + qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH, + qbool_from_bool(flags & BDRV_O_NO_FLUSH)); + } +} + static void bdrv_assign_node_name(BlockDriverState *bs, const char *node_name, Error **errp) @@ -831,6 +880,21 @@ static QemuOptsList bdrv_runtime_opts = { .type = QEMU_OPT_STRING, .help = "Block driver to use for the node", }, + { + .name = BDRV_OPT_CACHE_WB, + .type = QEMU_OPT_BOOL, + .help = "Enable writeback mode", + }, + { + .name = BDRV_OPT_CACHE_DIRECT, + .type = QEMU_OPT_BOOL, + .help = "Bypass software writeback cache on the host", + }, + { + .name = BDRV_OPT_CACHE_NO_FLUSH, + .type = QEMU_OPT_BOOL, + .help = "Ignore flush requests", + }, { /* end of list */ } }, }; @@ -925,7 +989,9 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, bs->drv = drv; bs->opaque = g_malloc0(drv->instance_size); - bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB); + /* Apply cache mode options */ + update_flags_from_options(&bs->open_flags, opts); + bdrv_set_enable_write_cache(bs, bs->open_flags & BDRV_O_CACHE_WB); /* Open the image, either directly or using a protocol */ if (drv->bdrv_file_open) { @@ -1075,6 +1141,9 @@ static int bdrv_fill_options(QDict **options, const char *filename, *flags &= ~BDRV_O_PROTOCOL; } + /* Translate cache options from flags into options */ + update_options_from_flags(*options, *flags); + /* Fetch the file name from the options QDict if necessary */ if (protocol && filename) { if (!qdict_haskey(*options, "filename")) { @@ -1747,12 +1816,22 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, /* * Precedence of options: * 1. Explicitly passed in options (highest) - * 2. TODO Set in flags (only for top level) + * 2. Set in flags (only for top level) * 3. Retained from explicitly set options of bs * 4. Inherited from parent node * 5. Retained from effective options of bs */ + if (!parent_options) { + /* + * Any setting represented by flags is always updated. If the + * corresponding QDict option is set, it takes precedence. Otherwise + * the flag is translated into a QDict option. The old setting of bs is + * not considered. + */ + update_options_from_flags(options, flags); + } + /* Old explicitly set values (don't overwrite by inherited value) */ old_options = qdict_clone_shallow(bs->explicit_options); bdrv_join_options(bs, options, old_options); @@ -1923,6 +2002,19 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, goto error; } + update_flags_from_options(&reopen_state->flags, opts); + + /* If a guest device is attached, it owns WCE */ + if (reopen_state->bs->blk && blk_get_attached_dev(reopen_state->bs->blk)) { + bool old_wce = bdrv_enable_write_cache(reopen_state->bs); + bool new_wce = (reopen_state->flags & BDRV_O_CACHE_WB); + if (old_wce != new_wce) { + error_setg(errp, "Cannot change cache.writeback: Device attached"); + ret = -EINVAL; + goto error; + } + } + /* 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"); diff --git a/blockdev.c b/blockdev.c index 2f88004511..64dbfeb15b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -387,16 +387,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, } } - if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) { - *bdrv_flags |= BDRV_O_CACHE_WB; - } - if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) { - *bdrv_flags |= BDRV_O_NOCACHE; - } - if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) { - *bdrv_flags |= BDRV_O_NO_FLUSH; - } - if ((aio = qemu_opt_get(opts, "aio")) != NULL) { if (!strcmp(aio, "native")) { *bdrv_flags |= BDRV_O_NATIVE_AIO; @@ -569,9 +559,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, } if (snapshot) { - /* always use cache=unsafe with snapshot */ - bdrv_flags &= ~BDRV_O_CACHE_MASK; - bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH); + bdrv_flags |= BDRV_O_SNAPSHOT; } /* init */ @@ -603,6 +591,20 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, file = NULL; } + /* bdrv_open() 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(bs_opts, BDRV_OPT_CACHE_WB, "on"); + qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off"); + qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off"); + + if (snapshot) { + /* always use cache=unsafe with snapshot */ + qdict_put(bs_opts, BDRV_OPT_CACHE_WB, qstring_from_str("on")); + qdict_put(bs_opts, BDRV_OPT_CACHE_DIRECT, qstring_from_str("off")); + qdict_put(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, qstring_from_str("on")); + } + blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags, errp); if (!blk) { @@ -3869,18 +3871,6 @@ QemuOptsList qemu_common_drive_opts = { .name = "discard", .type = QEMU_OPT_STRING, .help = "discard operation (ignore/off, unmap/on)", - },{ - .name = BDRV_OPT_CACHE_WB, - .type = QEMU_OPT_BOOL, - .help = "enables writeback mode for any caches", - },{ - .name = BDRV_OPT_CACHE_DIRECT, - .type = QEMU_OPT_BOOL, - .help = "enables use of O_DIRECT (bypass the host page cache)", - },{ - .name = BDRV_OPT_CACHE_NO_FLUSH, - .type = QEMU_OPT_BOOL, - .help = "ignore any flush requests for the device", },{ .name = "aio", .type = QEMU_OPT_STRING, @@ -3988,18 +3978,6 @@ static QemuOptsList qemu_root_bds_opts = { .name = "discard", .type = QEMU_OPT_STRING, .help = "discard operation (ignore/off, unmap/on)", - },{ - .name = "cache.writeback", - .type = QEMU_OPT_BOOL, - .help = "enables writeback mode for any caches", - },{ - .name = "cache.direct", - .type = QEMU_OPT_BOOL, - .help = "enables use of O_DIRECT (bypass the host page cache)", - },{ - .name = "cache.no-flush", - .type = QEMU_OPT_BOOL, - .help = "ignore any flush requests for the device", },{ .name = "aio", .type = QEMU_OPT_STRING,