New command "block_set_hostcache" added for dynamically changing host pagecache setting of a block device.
Usage: block_set_hostcache <device> <option> <device> = block device <option> = on/off Example: (qemu) block_set_hostcache ide0-hd0 off Signed-off-by: Supriya Kannery <supri...@linux.vnet.ibm.com> --- block.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ block.h | 2 ++ blockdev.c | 26 ++++++++++++++++++++++++++ blockdev.h | 2 ++ hmp-commands.hx | 14 ++++++++++++++ qmp-commands.hx | 27 +++++++++++++++++++++++++++ 6 files changed, 125 insertions(+) Index: qemu/block.c =================================================================== --- qemu.orig/block.c +++ qemu/block.c @@ -702,6 +702,34 @@ unlink_and_fail: return ret; } +int bdrv_reopen(BlockDriverState *bs, int bdrv_flags) +{ + BlockDriver *drv = bs->drv; + int ret = 0, open_flags; + + /* Quiesce IO for the given block device */ + qemu_aio_flush(); + if (bdrv_flush(bs)) { + qerror_report(QERR_DATA_SYNC_FAILED, bs->device_name); + return ret; + } + open_flags = bs->open_flags; + bdrv_close(bs); + + ret = bdrv_open(bs, bs->filename, bdrv_flags, drv); + if (ret < 0) { + /* Reopen failed. Try to open with original flags */ + qerror_report(QERR_REOPEN_FILE_FAILED, bs->filename); + ret = bdrv_open(bs, bs->filename, open_flags, drv); + if (ret < 0) { + /* Reopen failed with orig and modified flags */ + abort(); + } + } + + return ret; +} + void bdrv_close(BlockDriverState *bs) { if (bs->drv) { @@ -739,6 +767,32 @@ void bdrv_close_all(void) } } +int bdrv_change_hostcache(BlockDriverState *bs, bool enable_host_cache) +{ + int bdrv_flags = bs->open_flags; + + /* set hostcache flags (without changing WCE/flush bits) */ + if (enable_host_cache) { + bdrv_flags &= ~BDRV_O_NOCACHE; + } else { + bdrv_flags |= BDRV_O_NOCACHE; + } + + /* If no change in flags, no need to reopen */ + if (bdrv_flags == bs->open_flags) { + return 0; + } + + if (bdrv_is_inserted(bs)) { + /* Reopen file with changed set of flags */ + return bdrv_reopen(bs, bdrv_flags); + } else { + /* Save hostcache change for future use */ + bs->open_flags = bdrv_flags; + return 0; + } +} + /* make a BlockDriverState anonymous by removing from bdrv_state list. Also, NULL terminate the device_name to prevent double remove */ void bdrv_make_anon(BlockDriverState *bs) Index: qemu/block.h =================================================================== --- qemu.orig/block.h +++ qemu/block.h @@ -99,6 +99,7 @@ int bdrv_parse_cache_flags(const char *m int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); int bdrv_open(BlockDriverState *bs, const char *filename, int flags, BlockDriver *drv); +int bdrv_reopen(BlockDriverState *bs, int bdrv_flags); void bdrv_close(BlockDriverState *bs); int bdrv_attach_dev(BlockDriverState *bs, void *dev); void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev); @@ -133,6 +134,7 @@ void bdrv_commit_all(void); int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt); void bdrv_register(BlockDriver *bdrv); +int bdrv_change_hostcache(BlockDriverState *bs, bool enable_host_cache); typedef struct BdrvCheckResult { Index: qemu/blockdev.c =================================================================== --- qemu.orig/blockdev.c +++ qemu/blockdev.c @@ -776,3 +776,29 @@ int do_block_resize(Monitor *mon, const return 0; } + + +/* + * Change host page cache setting while guest is running. +*/ +int do_block_set_hostcache(Monitor *mon, const QDict *qdict, + QObject **ret_data) +{ + BlockDriverState *bs = NULL; + int enable; + const char *device; + + /* Validate device */ + device = qdict_get_str(qdict, "device"); + bs = bdrv_find(device); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, device); + return -1; + } + + /* Read hostcache setting */ + enable = qdict_get_bool(qdict, "option"); + return bdrv_change_hostcache(bs, enable); + +} + Index: qemu/blockdev.h =================================================================== --- qemu.orig/blockdev.h +++ qemu/blockdev.h @@ -65,5 +65,7 @@ int do_change_block(Monitor *mon, const 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_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data); +int do_block_set_hostcache(Monitor *mon, const QDict *qdict, + QObject **ret_data); #endif Index: qemu/hmp-commands.hx =================================================================== --- qemu.orig/hmp-commands.hx +++ qemu/hmp-commands.hx @@ -70,6 +70,20 @@ but should be used with extreme caution. resizes image files, it can not resize block devices like LVM volumes. ETEXI + { + .name = "block_set_hostcache", + .args_type = "device:B,option:b", + .params = "device on|off", + .help = "Change setting of host pagecache", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_block_set_hostcache, + }, +STEXI +@item block_set_hostcache @var{device} @var{setting} +@findex block_set_hostcache +Change host pagecache setting of a block device while guest is running. +ETEXI + { .name = "eject", Index: qemu/qmp-commands.hx =================================================================== --- qemu.orig/qmp-commands.hx +++ qemu/qmp-commands.hx @@ -718,7 +718,34 @@ Example: EQMP + { + .name = "block_set_hostcache", + .args_type = "device:B,option:b", + .params = "device on|off", + .help = "Change setting of host pagecache (true|false)", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_block_set_hostcache, + }, + +SQMP +block_set_hostcache +------------------- + +Change host pagecache setting of a block device (on|off) + +Arguments: + +- "device": the device's ID, must be unique (json-string) +- "option": hostcache setting (json-bool) + +Example: +-> { "execute": "block_set_hostcache", "arguments": { "device": "ide0-hd0", "option": false } } +<- { "return": {} } + +EQMP + + { .name = "balloon", .args_type = "value:M", .params = "target",