Sophie

Sophie

distrib > CentOS > 5 > x86_64 > by-pkgid > ea32411352494358b8d75a78402a4713 > files > 4979

kernel-2.6.18-238.19.1.el5.centos.plus.src.rpm

From: Christoph Hellwig <chellwig@redhat.com>
Date: Fri, 7 May 2010 10:31:24 -0400
Subject: [virt] virtio_blk: add support for cache flushes
Message-id: <1273228284-23772-1-git-send-email-chellwig@redhat.com>
Patchwork-id: 24889
O-Subject: virtio_blk: add support for cache flushes
Bugzilla: 571735
RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>

Recent qemu has added a VIRTIO_BLK_F_FLUSH flag to advertise that the
virtual disk has a volatile write cache that needs to be flushed.  In case
we see this feature implement tell the Linux block layer about the fact
and use the new VIRTIO_BLK_T_FLUSH to flush the cache when
required.  This allows for an correct and simple implementation of write
barriers.

Formally this is a backport of:

  commit f1b0ef062602713c2c7cfa12362d5d90ed01c5f6
  Author: Christoph Hellwig <hch@lst.de>
  Date:   Thu Sep 17 19:57:42 2009 +0200

but the code is very different from mainline because the block layer
in 2.6.18 misses the nice Linux internal command type that the cache
flush support is using upstream.  Instead we abuse an ata-internal
command type which is ignored by the block layer and other drivers
for our cache flush command.

BZ: https://bugzilla.redhat.com/show_bug.cgi?id=571735
Signed-off-by: Jarod Wilson <jarod@redhat.com>

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index a102e31..f7eff0c 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -84,7 +84,12 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
 		return false;
 
 	vbr->req = req;
-	if (blk_fs_request(vbr->req)) {
+	if (vbr->req->flags & REQ_DRIVE_TASK) {
+		BUG_ON(vbr->req->cmd[0] != VIRTIO_BLK_T_FLUSH);
+		vbr->out_hdr.type = vbr->req->cmd[0];
+		vbr->out_hdr.sector = 0;
+		vbr->out_hdr.ioprio = vbr->req->ioprio;
+	} else if (blk_fs_request(vbr->req)) {
 		vbr->out_hdr.type = 0;
 		vbr->out_hdr.sector = vbr->req->sector;
 		vbr->out_hdr.ioprio = vbr->req->ioprio;
@@ -148,6 +153,17 @@ static void do_virtblk_request(struct request_queue *q)
 		vblk->vq->vq_ops->kick(vblk->vq);
 }
 
+static void virtblk_prepare_flush(struct request_queue *q, struct request *req)
+{
+	/*
+	 * XXX: abuse the special IDE-internal commands as we don't have the
+	 * generic LINUX_BLOCK commands used for this in mainline available
+	 * on this old kernel.
+	 */
+	req->flags |= REQ_DRIVE_TASK;
+	req->cmd[0] = VIRTIO_BLK_T_FLUSH;
+}
+
 static int virtblk_ioctl(struct inode *inode, struct file *filp,
 			 unsigned cmd, unsigned long data)
 {
@@ -260,7 +276,11 @@ static int virtblk_probe(struct virtio_device *vdev)
 	index++;
 
 	/* If barriers are supported, tell block layer that queue is ordered */
-	if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
+	/* If barriers are supported, tell block layer that queue is ordered */
+	if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
+		blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_DRAIN_FLUSH,
+				  virtblk_prepare_flush);
+	else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
 		blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
 
 	/* If disk is read-only in the host, the guest should obey */
@@ -341,6 +361,7 @@ static struct virtio_device_id id_table[] = {
 static unsigned int features[] = {
 	VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
 	VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
+	VIRTIO_BLK_F_FLUSH
 };
 
 static struct virtio_driver virtio_blk = {
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index c1aef85..4f2f355 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -14,6 +14,7 @@
 #define VIRTIO_BLK_F_GEOMETRY	4	/* Legacy geometry available  */
 #define VIRTIO_BLK_F_RO		5	/* Disk is read-only */
 #define VIRTIO_BLK_F_BLK_SIZE	6	/* Block size of disk is available*/
+#define VIRTIO_BLK_F_FLUSH	9	/* Cache flush command support */
 
 struct virtio_blk_config
 {
@@ -40,6 +41,9 @@ struct virtio_blk_config
 /* This bit says it's a scsi command, not an actual read or write. */
 #define VIRTIO_BLK_T_SCSI_CMD	2
 
+/* Cache flush command */
+#define VIRTIO_BLK_T_FLUSH	4
+
 /* Barrier before this op. */
 #define VIRTIO_BLK_T_BARRIER	0x80000000