Usage : (qemu) set_cache DEVICE CACHE-MODE where CACHE-MODE can be one of writeback/ writethrough/ none.
At present, the image file is closed and re-opened with appropriate flags. It might potentially cause problems if the underlying image is deleted while a running qemu instance is using it. A change in cache operations will cause the image file to be closed, and a deleted file will be gone. Suggestions to fix this ? --- blockdev.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ blockdev.h | 1 + hmp-commands.hx | 13 +++++++++ 3 files changed, 90 insertions(+), 0 deletions(-) diff --git a/blockdev.c b/blockdev.c index 0690cc8..6735205 100644 --- a/blockdev.c +++ b/blockdev.c @@ -636,6 +636,82 @@ out: return ret; } +int do_set_cache(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *device = qdict_get_str(qdict, "device"); + const char *cache = qdict_get_str(qdict, "cache"); + BlockDriverState *bs; + BlockDriver *drv; + int ret = 0; + int bdrv_flags = 0; + + if (!cache) { + /* TODO: in the absence of a change request, + simply display current cache setting. + Currently one needs 'info block' to query this */ + qerror_report(QERR_MISSING_PARAMETER, "cache"); + return -1; + } + + bs = bdrv_find(device); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, device); + return -1; + } + + /* Clear old flags */ + bdrv_flags = bs->open_flags; + if (bdrv_flags & BDRV_O_CACHE_MASK) { + bdrv_flags &= ~BDRV_O_CACHE_MASK; + } + + /* Determine flags for requested cache setting */ + if (!strcmp(cache, "none")) { + bdrv_flags |= BDRV_O_NOCACHE; + } else if (!strcmp(cache, "writeback")) { + bdrv_flags |= BDRV_O_CACHE_WB; + } else if (!strcmp(cache, "unsafe")) { + /* TODO : Support unsafe mode */ + qerror_report(QERR_INVALID_PARAMETER_VALUE, cache, + "writeback, writethrough, none"); + return -1; + } else if (!strcmp(cache, "writethrough")) { + /* Default setting */ + } else { + qerror_report(QERR_INVALID_PARAMETER_VALUE, cache, + "'cache' must be one of writeback, writethrough, none"); + return -1; + } + + /* Verify that the cache setting specified is different from current. + * Does NOT call for error return, since the 'request' is already + * honoured. + */ + if (bdrv_flags == bs->open_flags) { + qerror_report(QERR_PROPERTY_VALUE_IN_USE, device, "cache", cache); + return 0; + } + + /* Quiesce IO for the given block device */ + qemu_aio_flush(); + bdrv_flush(bs); + + /* Change cache value and restart IO on the block device */ + printf("Setting cache=%s for device %s [ filename %s ]", cache, device, + bs->filename ); + drv = bs->drv; + bdrv_close(bs); + ret = bdrv_open(bs, bs->filename, bdrv_flags, drv); + /* + * A failed attempt to reopen the image file must lead to 'abort()' + */ + if (ret != 0) { + abort(); + } + + return ret; +} + static int eject_device(Monitor *mon, BlockDriverState *bs, int force) { if (!force) { diff --git a/blockdev.h b/blockdev.h index 2c9e780..9f35817 100644 --- a/blockdev.h +++ b/blockdev.h @@ -63,6 +63,7 @@ int do_change_block(Monitor *mon, const char *device, const char *filename, const char *fmt); int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data); +int do_set_cache(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data); #endif diff --git a/hmp-commands.hx b/hmp-commands.hx index 372bef4..18761cf 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1066,7 +1066,20 @@ STEXI @findex watchdog_action Change watchdog action. ETEXI + { + .name = "set_cache", + .args_type = "device:B,cache:s", + .params = "device writeback|writethrough|none", + .help = "change cache settings for device", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_set_cache, + }, +STEXI +@item set_cache +@findex set_cache +Set cache options for a block device. +ETEXI { .name = "acl_show", .args_type = "aclname:s", -- 1.7.2.3 -- Prerna Saxena Linux Technology Centre, IBM Systems and Technology Lab, Bangalore, India