diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 16:24:37 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 16:24:37 -0400 |
| commit | 95b18e69950ca7fd9acfa55964e929f58bec9379 (patch) | |
| tree | 5168f81b49cdfa2bcf363e4bd86cbfd669493ebd | |
| parent | 6d8a97af63222c5cbc7fe63ae19345e74e153e90 (diff) | |
| parent | 6a743897144500fb4c4566ced3a498d5180fbb5b (diff) | |
Merge tag 'virtio-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
Pull virtio update from Rusty Russell:
"Virtio patches, mainly hotplugging fixes."
* tag 'virtio-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus:
virtio-blk: return VIRTIO_BLK_F_FLUSH to header.
virtio-blk: allow toggling host cache between writeback and writethrough
virtio-blk: Use block layer provided spinlock
virtio-blk: Reset device after blk_cleanup_queue()
virtio-blk: Call del_gendisk() before disable guest kick
virtio: rng: s3/s4 support
virtio: rng: split out common code in probe / remove for s3/s4 ops
virtio: rng: don't wait on host when module is going away
virtio: rng: allow tasks to be killed that are waiting for rng input
virtio ids: fix comment for virtio-rng
| -rw-r--r-- | drivers/block/virtio_blk.c | 115 | ||||
| -rw-r--r-- | drivers/char/hw_random/virtio-rng.c | 37 | ||||
| -rw-r--r-- | include/linux/virtio_blk.h | 10 | ||||
| -rw-r--r-- | include/linux/virtio_ids.h | 2 |
4 files changed, 137 insertions, 27 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 693187df7601..c0bbeb470754 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
| @@ -21,8 +21,6 @@ struct workqueue_struct *virtblk_wq; | |||
| 21 | 21 | ||
| 22 | struct virtio_blk | 22 | struct virtio_blk |
| 23 | { | 23 | { |
| 24 | spinlock_t lock; | ||
| 25 | |||
| 26 | struct virtio_device *vdev; | 24 | struct virtio_device *vdev; |
| 27 | struct virtqueue *vq; | 25 | struct virtqueue *vq; |
| 28 | 26 | ||
| @@ -65,7 +63,7 @@ static void blk_done(struct virtqueue *vq) | |||
| 65 | unsigned int len; | 63 | unsigned int len; |
| 66 | unsigned long flags; | 64 | unsigned long flags; |
| 67 | 65 | ||
| 68 | spin_lock_irqsave(&vblk->lock, flags); | 66 | spin_lock_irqsave(vblk->disk->queue->queue_lock, flags); |
| 69 | while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) { | 67 | while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) { |
| 70 | int error; | 68 | int error; |
| 71 | 69 | ||
| @@ -99,7 +97,7 @@ static void blk_done(struct virtqueue *vq) | |||
| 99 | } | 97 | } |
| 100 | /* In case queue is stopped waiting for more buffers. */ | 98 | /* In case queue is stopped waiting for more buffers. */ |
| 101 | blk_start_queue(vblk->disk->queue); | 99 | blk_start_queue(vblk->disk->queue); |
| 102 | spin_unlock_irqrestore(&vblk->lock, flags); | 100 | spin_unlock_irqrestore(vblk->disk->queue->queue_lock, flags); |
| 103 | } | 101 | } |
| 104 | 102 | ||
| 105 | static bool do_req(struct request_queue *q, struct virtio_blk *vblk, | 103 | static bool do_req(struct request_queue *q, struct virtio_blk *vblk, |
| @@ -397,6 +395,83 @@ static int virtblk_name_format(char *prefix, int index, char *buf, int buflen) | |||
| 397 | return 0; | 395 | return 0; |
| 398 | } | 396 | } |
| 399 | 397 | ||
| 398 | static 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 | |||
| 412 | static 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 | |||
| 425 | static const char *const virtblk_cache_types[] = { | ||
| 426 | "write through", "write back" | ||
| 427 | }; | ||
| 428 | |||
| 429 | static ssize_t | ||
| 430 | virtblk_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 | |||
| 456 | static ssize_t | ||
| 457 | virtblk_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 | |||
| 468 | static const struct device_attribute dev_attr_cache_type_ro = | ||
| 469 | __ATTR(cache_type, S_IRUGO, | ||
| 470 | virtblk_cache_type_show, NULL); | ||
| 471 | static 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 | |||
| 400 | static int __devinit virtblk_probe(struct virtio_device *vdev) | 475 | static int __devinit virtblk_probe(struct virtio_device *vdev) |
| 401 | { | 476 | { |
| 402 | struct virtio_blk *vblk; | 477 | struct virtio_blk *vblk; |
| @@ -431,7 +506,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
| 431 | goto out_free_index; | 506 | goto out_free_index; |
| 432 | } | 507 | } |
| 433 | 508 | ||
| 434 | spin_lock_init(&vblk->lock); | ||
| 435 | vblk->vdev = vdev; | 509 | vblk->vdev = vdev; |
| 436 | vblk->sg_elems = sg_elems; | 510 | vblk->sg_elems = sg_elems; |
| 437 | sg_init_table(vblk->sg, vblk->sg_elems); | 511 | sg_init_table(vblk->sg, vblk->sg_elems); |
| @@ -456,7 +530,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
| 456 | goto out_mempool; | 530 | goto out_mempool; |
| 457 | } | 531 | } |
| 458 | 532 | ||
| 459 | q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock); | 533 | q = vblk->disk->queue = blk_init_queue(do_virtblk_request, NULL); |
| 460 | if (!q) { | 534 | if (!q) { |
| 461 | err = -ENOMEM; | 535 | err = -ENOMEM; |
| 462 | goto out_put_disk; | 536 | goto out_put_disk; |
| @@ -474,8 +548,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
| 474 | vblk->index = index; | 548 | vblk->index = index; |
| 475 | 549 | ||
| 476 | /* configure queue flush support */ | 550 | /* configure queue flush support */ |
| 477 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) | 551 | virtblk_update_cache_mode(vdev); |
| 478 | blk_queue_flush(q, REQ_FLUSH); | ||
| 479 | 552 | ||
| 480 | /* 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 */ |
| 481 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) | 554 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) |
| @@ -553,6 +626,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
| 553 | if (err) | 626 | if (err) |
| 554 | goto out_del_disk; | 627 | goto out_del_disk; |
| 555 | 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; | ||
| 556 | return 0; | 637 | return 0; |
| 557 | 638 | ||
| 558 | out_del_disk: | 639 | out_del_disk: |
| @@ -576,30 +657,20 @@ static void __devexit virtblk_remove(struct virtio_device *vdev) | |||
| 576 | { | 657 | { |
| 577 | struct virtio_blk *vblk = vdev->priv; | 658 | struct virtio_blk *vblk = vdev->priv; |
| 578 | int index = vblk->index; | 659 | int index = vblk->index; |
| 579 | struct virtblk_req *vbr; | ||
| 580 | unsigned long flags; | ||
| 581 | 660 | ||
| 582 | /* Prevent config work handler from accessing the device. */ | 661 | /* Prevent config work handler from accessing the device. */ |
| 583 | mutex_lock(&vblk->config_lock); | 662 | mutex_lock(&vblk->config_lock); |
| 584 | vblk->config_enable = false; | 663 | vblk->config_enable = false; |
| 585 | mutex_unlock(&vblk->config_lock); | 664 | mutex_unlock(&vblk->config_lock); |
| 586 | 665 | ||
| 666 | del_gendisk(vblk->disk); | ||
| 667 | blk_cleanup_queue(vblk->disk->queue); | ||
| 668 | |||
| 587 | /* Stop all the virtqueues. */ | 669 | /* Stop all the virtqueues. */ |
| 588 | vdev->config->reset(vdev); | 670 | vdev->config->reset(vdev); |
| 589 | 671 | ||
| 590 | flush_work(&vblk->config_work); | 672 | flush_work(&vblk->config_work); |
| 591 | 673 | ||
| 592 | del_gendisk(vblk->disk); | ||
| 593 | |||
| 594 | /* Abort requests dispatched to driver. */ | ||
| 595 | spin_lock_irqsave(&vblk->lock, flags); | ||
| 596 | while ((vbr = virtqueue_detach_unused_buf(vblk->vq))) { | ||
| 597 | __blk_end_request_all(vbr->req, -EIO); | ||
| 598 | mempool_free(vbr, vblk->pool); | ||
| 599 | } | ||
| 600 | spin_unlock_irqrestore(&vblk->lock, flags); | ||
| 601 | |||
| 602 | blk_cleanup_queue(vblk->disk->queue); | ||
| 603 | put_disk(vblk->disk); | 674 | put_disk(vblk->disk); |
| 604 | mempool_destroy(vblk->pool); | 675 | mempool_destroy(vblk->pool); |
| 605 | vdev->config->del_vqs(vdev); | 676 | vdev->config->del_vqs(vdev); |
| @@ -655,7 +726,7 @@ static const struct virtio_device_id id_table[] = { | |||
| 655 | static unsigned int features[] = { | 726 | static unsigned int features[] = { |
| 656 | 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, |
| 657 | 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, |
| 658 | VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY | 729 | VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE |
| 659 | }; | 730 | }; |
| 660 | 731 | ||
| 661 | /* | 732 | /* |
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 723725bbb96b..5708299507d0 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c | |||
| @@ -55,6 +55,7 @@ static void register_buffer(u8 *buf, size_t size) | |||
| 55 | 55 | ||
| 56 | static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait) | 56 | static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait) |
| 57 | { | 57 | { |
| 58 | int ret; | ||
| 58 | 59 | ||
| 59 | if (!busy) { | 60 | if (!busy) { |
| 60 | busy = true; | 61 | busy = true; |
| @@ -65,7 +66,9 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait) | |||
| 65 | if (!wait) | 66 | if (!wait) |
| 66 | return 0; | 67 | return 0; |
| 67 | 68 | ||
| 68 | wait_for_completion(&have_data); | 69 | ret = wait_for_completion_killable(&have_data); |
| 70 | if (ret < 0) | ||
| 71 | return ret; | ||
| 69 | 72 | ||
| 70 | busy = false; | 73 | busy = false; |
| 71 | 74 | ||
| @@ -85,7 +88,7 @@ static struct hwrng virtio_hwrng = { | |||
| 85 | .read = virtio_read, | 88 | .read = virtio_read, |
| 86 | }; | 89 | }; |
| 87 | 90 | ||
| 88 | static int virtrng_probe(struct virtio_device *vdev) | 91 | static int probe_common(struct virtio_device *vdev) |
| 89 | { | 92 | { |
| 90 | int err; | 93 | int err; |
| 91 | 94 | ||
| @@ -103,13 +106,37 @@ static int virtrng_probe(struct virtio_device *vdev) | |||
| 103 | return 0; | 106 | return 0; |
| 104 | } | 107 | } |
| 105 | 108 | ||
| 106 | static void __devexit virtrng_remove(struct virtio_device *vdev) | 109 | static void remove_common(struct virtio_device *vdev) |
| 107 | { | 110 | { |
| 108 | vdev->config->reset(vdev); | 111 | vdev->config->reset(vdev); |
| 112 | busy = false; | ||
| 109 | hwrng_unregister(&virtio_hwrng); | 113 | hwrng_unregister(&virtio_hwrng); |
| 110 | vdev->config->del_vqs(vdev); | 114 | vdev->config->del_vqs(vdev); |
| 111 | } | 115 | } |
| 112 | 116 | ||
| 117 | static int virtrng_probe(struct virtio_device *vdev) | ||
| 118 | { | ||
| 119 | return probe_common(vdev); | ||
| 120 | } | ||
| 121 | |||
| 122 | static void __devexit virtrng_remove(struct virtio_device *vdev) | ||
| 123 | { | ||
| 124 | remove_common(vdev); | ||
| 125 | } | ||
| 126 | |||
| 127 | #ifdef CONFIG_PM | ||
| 128 | static int virtrng_freeze(struct virtio_device *vdev) | ||
| 129 | { | ||
| 130 | remove_common(vdev); | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int virtrng_restore(struct virtio_device *vdev) | ||
| 135 | { | ||
| 136 | return probe_common(vdev); | ||
| 137 | } | ||
| 138 | #endif | ||
| 139 | |||
| 113 | static struct virtio_device_id id_table[] = { | 140 | static struct virtio_device_id id_table[] = { |
| 114 | { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID }, | 141 | { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID }, |
| 115 | { 0 }, | 142 | { 0 }, |
| @@ -121,6 +148,10 @@ static struct virtio_driver virtio_rng_driver = { | |||
| 121 | .id_table = id_table, | 148 | .id_table = id_table, |
| 122 | .probe = virtrng_probe, | 149 | .probe = virtrng_probe, |
| 123 | .remove = __devexit_p(virtrng_remove), | 150 | .remove = __devexit_p(virtrng_remove), |
| 151 | #ifdef CONFIG_PM | ||
| 152 | .freeze = virtrng_freeze, | ||
| 153 | .restore = virtrng_restore, | ||
| 154 | #endif | ||
| 124 | }; | 155 | }; |
| 125 | 156 | ||
| 126 | static int __init init(void) | 157 | static int __init init(void) |
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h index e0edb40ca7aa..6d8e61c48563 100644 --- a/include/linux/virtio_blk.h +++ b/include/linux/virtio_blk.h | |||
| @@ -37,8 +37,14 @@ | |||
| 37 | #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ | 37 | #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ |
| 38 | #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ | 38 | #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ |
| 39 | #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ | 39 | #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ |
| 40 | #define VIRTIO_BLK_F_FLUSH 9 /* Cache flush command support */ | 40 | #define VIRTIO_BLK_F_WCE 9 /* Writeback mode enabled after reset */ |
| 41 | #define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */ | 41 | #define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */ |
| 42 | #define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */ | ||
| 43 | |||
| 44 | #ifndef __KERNEL__ | ||
| 45 | /* Old (deprecated) name for VIRTIO_BLK_F_WCE. */ | ||
| 46 | #define VIRTIO_BLK_F_FLUSH VIRTIO_BLK_F_WCE | ||
| 47 | #endif | ||
| 42 | 48 | ||
| 43 | #define VIRTIO_BLK_ID_BYTES 20 /* ID string length */ | 49 | #define VIRTIO_BLK_ID_BYTES 20 /* ID string length */ |
| 44 | 50 | ||
| @@ -69,6 +75,8 @@ struct virtio_blk_config { | |||
| 69 | /* optimal sustained I/O size in logical blocks. */ | 75 | /* optimal sustained I/O size in logical blocks. */ |
| 70 | __u32 opt_io_size; | 76 | __u32 opt_io_size; |
| 71 | 77 | ||
| 78 | /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */ | ||
| 79 | __u8 wce; | ||
| 72 | } __attribute__((packed)); | 80 | } __attribute__((packed)); |
| 73 | 81 | ||
| 74 | /* | 82 | /* |
diff --git a/include/linux/virtio_ids.h b/include/linux/virtio_ids.h index 7529b854b7fd..270fb22c5811 100644 --- a/include/linux/virtio_ids.h +++ b/include/linux/virtio_ids.h | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | #define VIRTIO_ID_NET 1 /* virtio net */ | 32 | #define VIRTIO_ID_NET 1 /* virtio net */ |
| 33 | #define VIRTIO_ID_BLOCK 2 /* virtio block */ | 33 | #define VIRTIO_ID_BLOCK 2 /* virtio block */ |
| 34 | #define VIRTIO_ID_CONSOLE 3 /* virtio console */ | 34 | #define VIRTIO_ID_CONSOLE 3 /* virtio console */ |
| 35 | #define VIRTIO_ID_RNG 4 /* virtio ring */ | 35 | #define VIRTIO_ID_RNG 4 /* virtio rng */ |
| 36 | #define VIRTIO_ID_BALLOON 5 /* virtio balloon */ | 36 | #define VIRTIO_ID_BALLOON 5 /* virtio balloon */ |
| 37 | #define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */ | 37 | #define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */ |
| 38 | #define VIRTIO_ID_SCSI 8 /* virtio scsi */ | 38 | #define VIRTIO_ID_SCSI 8 /* virtio scsi */ |
