Patchwork [RFC,1/2] Add monitor command 'set-cache' to change cache settings for a block device.

login
register
mail settings
Submitter Prerna Saxena
Date Feb. 28, 2011, 12:07 p.m.
Message ID <20110228173757.7c34fd06@zephyr>
Download mbox | patch
Permalink /patch/84823/
State New
Headers show

Comments

Prerna Saxena - Feb. 28, 2011, 12:07 p.m.
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(-)

Patch

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",