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 /drivers | |
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
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/virtio_blk.c | 115 | ||||
-rw-r--r-- | drivers/char/hw_random/virtio-rng.c | 37 |
2 files changed, 127 insertions, 25 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) |