aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/virtio_blk.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-07-03 09:19:37 -0400
committerRusty Russell <rusty@rustcorp.com.au>2012-07-30 00:00:52 -0400
commitcd5d503862b0d0d927c56ef2e34d3ededac88039 (patch)
tree73d31dddd2d63ab2fce0880ee77e9525065a4027 /drivers/block/virtio_blk.c
parent2c95a3290919541b846bee3e0fbaa75860929f53 (diff)
virtio-blk: allow toggling host cache between writeback and writethrough
This patch adds support for the new VIRTIO_BLK_F_CONFIG_WCE feature, which exposes the cache mode in the configuration space and lets the driver modify it. The cache mode is exposed via sysfs. Even if the host does not support the new feature, the cache mode is visible (thanks to the existing VIRTIO_BLK_F_WCE), but not modifiable. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/block/virtio_blk.c')
-rw-r--r--drivers/block/virtio_blk.c90
1 files changed, 87 insertions, 3 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 774c31dce7c0..c0bbeb470754 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -395,6 +395,83 @@ static int virtblk_name_format(char *prefix, int index, char *buf, int buflen)
395 return 0; 395 return 0;
396} 396}
397 397
398static int virtblk_get_cache_mode(struct virtio_device *vdev)
399{
400 u8 writeback;
401 int err;
402
403 err = virtio_config_val(vdev, VIRTIO_BLK_F_CONFIG_WCE,
404 offsetof(struct virtio_blk_config, wce),
405 &writeback);
406 if (err)
407 writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE);
408
409 return writeback;
410}
411
412static void virtblk_update_cache_mode(struct virtio_device *vdev)
413{
414 u8 writeback = virtblk_get_cache_mode(vdev);
415 struct virtio_blk *vblk = vdev->priv;
416
417 if (writeback)
418 blk_queue_flush(vblk->disk->queue, REQ_FLUSH);
419 else
420 blk_queue_flush(vblk->disk->queue, 0);
421
422 revalidate_disk(vblk->disk);
423}
424
425static const char *const virtblk_cache_types[] = {
426 "write through", "write back"
427};
428
429static ssize_t
430virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
431 const char *buf, size_t count)
432{
433 struct gendisk *disk = dev_to_disk(dev);
434 struct virtio_blk *vblk = disk->private_data;
435 struct virtio_device *vdev = vblk->vdev;
436 int i;
437 u8 writeback;
438
439 BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE));
440 for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; )
441 if (sysfs_streq(buf, virtblk_cache_types[i]))
442 break;
443
444 if (i < 0)
445 return -EINVAL;
446
447 writeback = i;
448 vdev->config->set(vdev,
449 offsetof(struct virtio_blk_config, wce),
450 &writeback, sizeof(writeback));
451
452 virtblk_update_cache_mode(vdev);
453 return count;
454}
455
456static ssize_t
457virtblk_cache_type_show(struct device *dev, struct device_attribute *attr,
458 char *buf)
459{
460 struct gendisk *disk = dev_to_disk(dev);
461 struct virtio_blk *vblk = disk->private_data;
462 u8 writeback = virtblk_get_cache_mode(vblk->vdev);
463
464 BUG_ON(writeback >= ARRAY_SIZE(virtblk_cache_types));
465 return snprintf(buf, 40, "%s\n", virtblk_cache_types[writeback]);
466}
467
468static const struct device_attribute dev_attr_cache_type_ro =
469 __ATTR(cache_type, S_IRUGO,
470 virtblk_cache_type_show, NULL);
471static const struct device_attribute dev_attr_cache_type_rw =
472 __ATTR(cache_type, S_IRUGO|S_IWUSR,
473 virtblk_cache_type_show, virtblk_cache_type_store);
474
398static int __devinit virtblk_probe(struct virtio_device *vdev) 475static int __devinit virtblk_probe(struct virtio_device *vdev)
399{ 476{
400 struct virtio_blk *vblk; 477 struct virtio_blk *vblk;
@@ -471,8 +548,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
471 vblk->index = index; 548 vblk->index = index;
472 549
473 /* configure queue flush support */ 550 /* configure queue flush support */
474 if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) 551 virtblk_update_cache_mode(vdev);
475 blk_queue_flush(q, REQ_FLUSH);
476 552
477 /* If disk is read-only in the host, the guest should obey */ 553 /* If disk is read-only in the host, the guest should obey */
478 if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) 554 if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -550,6 +626,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
550 if (err) 626 if (err)
551 goto out_del_disk; 627 goto out_del_disk;
552 628
629 if (virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE))
630 err = device_create_file(disk_to_dev(vblk->disk),
631 &dev_attr_cache_type_rw);
632 else
633 err = device_create_file(disk_to_dev(vblk->disk),
634 &dev_attr_cache_type_ro);
635 if (err)
636 goto out_del_disk;
553 return 0; 637 return 0;
554 638
555out_del_disk: 639out_del_disk:
@@ -642,7 +726,7 @@ static const struct virtio_device_id id_table[] = {
642static unsigned int features[] = { 726static unsigned int features[] = {
643 VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, 727 VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
644 VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI, 728 VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI,
645 VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY 729 VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE
646}; 730};
647 731
648/* 732/*