|
|
298366 |
From c8adc0db7e76e804692372a06ca02cc5a80b67d5 Mon Sep 17 00:00:00 2001
|
|
|
298366 |
From: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
298366 |
Date: Fri, 20 Sep 2013 17:31:55 +0200
|
|
|
298366 |
Subject: [PATCH] virtio-blk: do not relay a previous driver's WCE
|
|
|
298366 |
configuration to the current
|
|
|
298366 |
|
|
|
298366 |
The following sequence happens:
|
|
|
298366 |
- the SeaBIOS virtio-blk driver does not support the WCE feature, which
|
|
|
298366 |
causes QEMU to disable writeback caching
|
|
|
298366 |
|
|
|
298366 |
- the Linux virtio-blk driver resets the device, finds WCE is available
|
|
|
298366 |
but writeback caching is disabled; tells block layer to not send cache
|
|
|
298366 |
flush commands
|
|
|
298366 |
|
|
|
298366 |
- the Linux virtio-blk driver sets the DRIVER_OK bit, which causes
|
|
|
298366 |
writeback caching to be re-enabled, but the Linux virtio-blk driver does
|
|
|
298366 |
not know of this side effect and cache flushes remain disabled
|
|
|
298366 |
|
|
|
298366 |
The bug is at the third step. If the guest does know about CONFIG_WCE,
|
|
|
298366 |
QEMU should ignore the WCE feature's state. The guest will control the
|
|
|
298366 |
cache mode solely using configuration space. This change makes Linux
|
|
|
298366 |
do flushes correctly, but Linux will keep SeaBIOS's writethrough mode.
|
|
|
298366 |
|
|
|
298366 |
Hence, whenever the guest is reset, the cache mode of the disk should
|
|
|
298366 |
be reset to whatever was specified in the "-drive" option. With this
|
|
|
298366 |
change, the Linux virtio-blk driver finds that writeback caching is
|
|
|
298366 |
enabled, and tells the block layer to send cache flush commands
|
|
|
298366 |
appropriately.
|
|
|
298366 |
|
|
|
298366 |
Reported-by: Rusty Russell
|
|
|
298366 |
Cc: qemu-stable@nongnu.org
|
|
|
298366 |
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
298366 |
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
298366 |
(cherry picked from commit ef5bc96268ceec64769617dc53b0ac3a20ff351c)
|
|
|
298366 |
|
|
|
298366 |
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
|
|
|
298366 |
---
|
|
|
298366 |
hw/block/virtio-blk.c | 24 ++++++++++++++++++++++--
|
|
|
298366 |
include/hw/virtio/virtio-blk.h | 1 +
|
|
|
298366 |
2 files changed, 23 insertions(+), 2 deletions(-)
|
|
|
298366 |
|
|
|
298366 |
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
|
|
|
298366 |
index e2f55cc..49a23c3 100644
|
|
|
298366 |
--- a/hw/block/virtio-blk.c
|
|
|
298366 |
+++ b/hw/block/virtio-blk.c
|
|
|
298366 |
@@ -460,9 +460,9 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running,
|
|
|
298366 |
|
|
|
298366 |
static void virtio_blk_reset(VirtIODevice *vdev)
|
|
|
298366 |
{
|
|
|
298366 |
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
|
298366 |
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
|
|
298366 |
|
|
|
298366 |
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
|
298366 |
if (s->dataplane) {
|
|
|
298366 |
virtio_blk_data_plane_stop(s->dataplane);
|
|
|
298366 |
}
|
|
|
298366 |
@@ -473,6 +473,7 @@ static void virtio_blk_reset(VirtIODevice *vdev)
|
|
|
298366 |
* are per-device request lists.
|
|
|
298366 |
*/
|
|
|
298366 |
bdrv_drain_all();
|
|
|
298366 |
+ bdrv_set_enable_write_cache(s->bs, s->original_wce);
|
|
|
298366 |
}
|
|
|
298366 |
|
|
|
298366 |
/* coalesce internal state, copy to pci i/o region 0
|
|
|
298366 |
@@ -564,7 +565,25 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
|
|
298366 |
}
|
|
|
298366 |
|
|
|
298366 |
features = vdev->guest_features;
|
|
|
298366 |
- bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
|
|
|
298366 |
+
|
|
|
298366 |
+ /* A guest that supports VIRTIO_BLK_F_CONFIG_WCE must be able to send
|
|
|
298366 |
+ * cache flushes. Thus, the "auto writethrough" behavior is never
|
|
|
298366 |
+ * necessary for guests that support the VIRTIO_BLK_F_CONFIG_WCE feature.
|
|
|
298366 |
+ * Leaving it enabled would break the following sequence:
|
|
|
298366 |
+ *
|
|
|
298366 |
+ * Guest started with "-drive cache=writethrough"
|
|
|
298366 |
+ * Guest sets status to 0
|
|
|
298366 |
+ * Guest sets DRIVER bit in status field
|
|
|
298366 |
+ * Guest reads host features (WCE=0, CONFIG_WCE=1)
|
|
|
298366 |
+ * Guest writes guest features (WCE=0, CONFIG_WCE=1)
|
|
|
298366 |
+ * Guest writes 1 to the WCE configuration field (writeback mode)
|
|
|
298366 |
+ * Guest sets DRIVER_OK bit in status field
|
|
|
298366 |
+ *
|
|
|
298366 |
+ * s->bs would erroneously be placed in writethrough mode.
|
|
|
298366 |
+ */
|
|
|
298366 |
+ if (!(features & (1 << VIRTIO_BLK_F_CONFIG_WCE))) {
|
|
|
298366 |
+ bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
|
|
|
298366 |
+ }
|
|
|
298366 |
}
|
|
|
298366 |
|
|
|
298366 |
static void virtio_blk_save(QEMUFile *f, void *opaque)
|
|
|
298366 |
@@ -674,6 +693,7 @@ static int virtio_blk_device_init(VirtIODevice *vdev)
|
|
|
298366 |
}
|
|
|
298366 |
|
|
|
298366 |
blkconf_serial(&blk->conf, &blk->serial);
|
|
|
298366 |
+ s->original_wce = bdrv_enable_write_cache(blk->conf.bs);
|
|
|
298366 |
if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) {
|
|
|
298366 |
return -1;
|
|
|
298366 |
}
|
|
|
298366 |
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
|
|
|
298366 |
index b87cf49..41885da 100644
|
|
|
298366 |
--- a/include/hw/virtio/virtio-blk.h
|
|
|
298366 |
+++ b/include/hw/virtio/virtio-blk.h
|
|
|
298366 |
@@ -123,6 +123,7 @@ typedef struct VirtIOBlock {
|
|
|
298366 |
BlockConf *conf;
|
|
|
298366 |
VirtIOBlkConf blk;
|
|
|
298366 |
unsigned short sector_mask;
|
|
|
298366 |
+ bool original_wce;
|
|
|
298366 |
VMChangeStateEntry *change;
|
|
|
298366 |
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
|
298366 |
Notifier migration_state_notifier;
|