From 91a097e7478940483e76d52217f05bc05b98d5a5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 17:49:53 +0200 Subject: block: Move cache options into options QDict This adds the cache mode options to the QDict, so that they can be specified for child nodes (e.g. backing.cache.direct=off). The cache modes are not removed from the flags at this point; instead, options and flags are kept in sync. If the user specifies both flags and options, the options take precedence. Child node inherit cache modes as options now, they don't use flags any more. Note that this forbids specifying the cache mode for empty drives. It didn't make sense anyway to specify it there, because it didn't have any effect. blockdev_init() considers the cache options now bdrv_open() options and therefore doesn't create an empty drive any more but calls into bdrv_open(). This in turn will fail with no driver and filename specified. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 4 deletions(-) (limited to 'block.c') 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"); -- cgit v1.2.3