Commit f1b0ef06 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Rusty Russell

virtio_blk: add support for cache flush

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.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 3ca4f5ca
...@@ -92,15 +92,26 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, ...@@ -92,15 +92,26 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
return false; return false;
vbr->req = req; vbr->req = req;
if (blk_fs_request(vbr->req)) { switch (req->cmd_type) {
case REQ_TYPE_FS:
vbr->out_hdr.type = 0; vbr->out_hdr.type = 0;
vbr->out_hdr.sector = blk_rq_pos(vbr->req); vbr->out_hdr.sector = blk_rq_pos(vbr->req);
vbr->out_hdr.ioprio = req_get_ioprio(vbr->req); vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
} else if (blk_pc_request(vbr->req)) { break;
case REQ_TYPE_BLOCK_PC:
vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD; vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
vbr->out_hdr.sector = 0; vbr->out_hdr.sector = 0;
vbr->out_hdr.ioprio = req_get_ioprio(vbr->req); vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
} else { break;
case REQ_TYPE_LINUX_BLOCK:
if (req->cmd[0] == REQ_LB_OP_FLUSH) {
vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH;
vbr->out_hdr.sector = 0;
vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
break;
}
/*FALLTHRU*/
default:
/* We don't put anything else in the queue. */ /* We don't put anything else in the queue. */
BUG(); BUG();
} }
...@@ -200,6 +211,12 @@ static int virtblk_identify(struct gendisk *disk, void *argp) ...@@ -200,6 +211,12 @@ static int virtblk_identify(struct gendisk *disk, void *argp)
return err; return err;
} }
static void virtblk_prepare_flush(struct request_queue *q, struct request *req)
{
req->cmd_type = REQ_TYPE_LINUX_BLOCK;
req->cmd[0] = REQ_LB_OP_FLUSH;
}
static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long data) unsigned cmd, unsigned long data)
{ {
...@@ -338,7 +355,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) ...@@ -338,7 +355,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
index++; index++;
/* If barriers are supported, tell block layer that queue is ordered */ /* If barriers are supported, tell block layer that queue is ordered */
if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) 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); blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
/* If disk is read-only in the host, the guest should obey */ /* If disk is read-only in the host, the guest should obey */
...@@ -425,7 +445,7 @@ static struct virtio_device_id id_table[] = { ...@@ -425,7 +445,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = { static unsigned int features[] = {
VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, 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_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY, VIRTIO_BLK_F_FLUSH
}; };
/* /*
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
#define VIRTIO_BLK_F_IDENTIFY 8 /* ATA IDENTIFY supported */ #define VIRTIO_BLK_F_IDENTIFY 8 /* ATA IDENTIFY supported */
#define VIRTIO_BLK_F_FLUSH 9 /* Cache flush command support */
#define VIRTIO_BLK_ID_BYTES (sizeof(__u16[256])) /* IDENTIFY DATA */ #define VIRTIO_BLK_ID_BYTES (sizeof(__u16[256])) /* IDENTIFY DATA */
...@@ -35,6 +36,17 @@ struct virtio_blk_config { ...@@ -35,6 +36,17 @@ struct virtio_blk_config {
__u8 identify[VIRTIO_BLK_ID_BYTES]; __u8 identify[VIRTIO_BLK_ID_BYTES];
} __attribute__((packed)); } __attribute__((packed));
/*
* Command types
*
* Usage is a bit tricky as some bits are used as flags and some are not.
*
* Rules:
* VIRTIO_BLK_T_OUT may be combined with VIRTIO_BLK_T_SCSI_CMD or
* VIRTIO_BLK_T_BARRIER. VIRTIO_BLK_T_FLUSH is a command of its own
* and may not be combined with any of the other flags.
*/
/* These two define direction. */ /* These two define direction. */
#define VIRTIO_BLK_T_IN 0 #define VIRTIO_BLK_T_IN 0
#define VIRTIO_BLK_T_OUT 1 #define VIRTIO_BLK_T_OUT 1
...@@ -42,6 +54,9 @@ struct virtio_blk_config { ...@@ -42,6 +54,9 @@ struct virtio_blk_config {
/* This bit says it's a scsi command, not an actual read or write. */ /* This bit says it's a scsi command, not an actual read or write. */
#define VIRTIO_BLK_T_SCSI_CMD 2 #define VIRTIO_BLK_T_SCSI_CMD 2
/* Cache flush command */
#define VIRTIO_BLK_T_FLUSH 4
/* Barrier before this op. */ /* Barrier before this op. */
#define VIRTIO_BLK_T_BARRIER 0x80000000 #define VIRTIO_BLK_T_BARRIER 0x80000000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment