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: Christoph Hellwig <hch@lst.de> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Rusty Russell
parent
3ca4f5ca73
commit
f1b0ef0626
@@ -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 @@ out:
|
|||||||
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)
|
|||||||
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[] = {
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
__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 {
|
|||||||
/* 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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user