aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2011-02-01 15:43:48 -0500
committerRusty Russell <rusty@rustcorp.com.au>2011-05-29 21:44:13 -0400
commit7a7c924cf03da2a76ea4dc0aac1a788cf95a9c29 (patch)
tree717aba1aab456d252c684abf256afa8e92b7dd96 /drivers/block
parent990c91f0af46c57f0291060d928c7ab82f9d5667 (diff)
virtio_blk: allow re-reading config space at runtime
Wire up the virtio_driver config_changed method to get notified about config changes raised by the host. For now we just re-read the device size to support online resizing of devices, but once we add more attributes that might be changeable they could be added as well. Note that the config_changed method is called from irq context, so we'll have to use the workqueue infrastructure to provide us a proper user context for our changes. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/virtio_blk.c88
1 files changed, 78 insertions, 10 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 6ecf89cdf006..33a48a80c7e8 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -6,10 +6,12 @@
6#include <linux/virtio.h> 6#include <linux/virtio.h>
7#include <linux/virtio_blk.h> 7#include <linux/virtio_blk.h>
8#include <linux/scatterlist.h> 8#include <linux/scatterlist.h>
9#include <linux/string_helpers.h>
9 10
10#define PART_BITS 4 11#define PART_BITS 4
11 12
12static int major, index; 13static int major, index;
14struct workqueue_struct *virtblk_wq;
13 15
14struct virtio_blk 16struct virtio_blk
15{ 17{
@@ -26,6 +28,9 @@ struct virtio_blk
26 28
27 mempool_t *pool; 29 mempool_t *pool;
28 30
31 /* Process context for config space updates */
32 struct work_struct config_work;
33
29 /* What host tells us, plus 2 for header & tailer. */ 34 /* What host tells us, plus 2 for header & tailer. */
30 unsigned int sg_elems; 35 unsigned int sg_elems;
31 36
@@ -291,6 +296,46 @@ static ssize_t virtblk_serial_show(struct device *dev,
291} 296}
292DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL); 297DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);
293 298
299static void virtblk_config_changed_work(struct work_struct *work)
300{
301 struct virtio_blk *vblk =
302 container_of(work, struct virtio_blk, config_work);
303 struct virtio_device *vdev = vblk->vdev;
304 struct request_queue *q = vblk->disk->queue;
305 char cap_str_2[10], cap_str_10[10];
306 u64 capacity, size;
307
308 /* Host must always specify the capacity. */
309 vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
310 &capacity, sizeof(capacity));
311
312 /* If capacity is too big, truncate with warning. */
313 if ((sector_t)capacity != capacity) {
314 dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
315 (unsigned long long)capacity);
316 capacity = (sector_t)-1;
317 }
318
319 size = capacity * queue_logical_block_size(q);
320 string_get_size(size, STRING_UNITS_2, cap_str_2, sizeof(cap_str_2));
321 string_get_size(size, STRING_UNITS_10, cap_str_10, sizeof(cap_str_10));
322
323 dev_notice(&vdev->dev,
324 "new size: %llu %d-byte logical blocks (%s/%s)\n",
325 (unsigned long long)capacity,
326 queue_logical_block_size(q),
327 cap_str_10, cap_str_2);
328
329 set_capacity(vblk->disk, capacity);
330}
331
332static void virtblk_config_changed(struct virtio_device *vdev)
333{
334 struct virtio_blk *vblk = vdev->priv;
335
336 queue_work(virtblk_wq, &vblk->config_work);
337}
338
294static int __devinit virtblk_probe(struct virtio_device *vdev) 339static int __devinit virtblk_probe(struct virtio_device *vdev)
295{ 340{
296 struct virtio_blk *vblk; 341 struct virtio_blk *vblk;
@@ -327,6 +372,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
327 vblk->vdev = vdev; 372 vblk->vdev = vdev;
328 vblk->sg_elems = sg_elems; 373 vblk->sg_elems = sg_elems;
329 sg_init_table(vblk->sg, vblk->sg_elems); 374 sg_init_table(vblk->sg, vblk->sg_elems);
375 INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
330 376
331 /* We expect one virtqueue, for output. */ 377 /* We expect one virtqueue, for output. */
332 vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests"); 378 vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
@@ -477,6 +523,8 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
477{ 523{
478 struct virtio_blk *vblk = vdev->priv; 524 struct virtio_blk *vblk = vdev->priv;
479 525
526 flush_work(&vblk->config_work);
527
480 /* Nothing should be pending. */ 528 /* Nothing should be pending. */
481 BUG_ON(!list_empty(&vblk->reqs)); 529 BUG_ON(!list_empty(&vblk->reqs));
482 530
@@ -508,27 +556,47 @@ static unsigned int features[] = {
508 * Use __refdata to avoid this warning. 556 * Use __refdata to avoid this warning.
509 */ 557 */
510static struct virtio_driver __refdata virtio_blk = { 558static struct virtio_driver __refdata virtio_blk = {
511 .feature_table = features, 559 .feature_table = features,
512 .feature_table_size = ARRAY_SIZE(features), 560 .feature_table_size = ARRAY_SIZE(features),
513 .driver.name = KBUILD_MODNAME, 561 .driver.name = KBUILD_MODNAME,
514 .driver.owner = THIS_MODULE, 562 .driver.owner = THIS_MODULE,
515 .id_table = id_table, 563 .id_table = id_table,
516 .probe = virtblk_probe, 564 .probe = virtblk_probe,
517 .remove = __devexit_p(virtblk_remove), 565 .remove = __devexit_p(virtblk_remove),
566 .config_changed = virtblk_config_changed,
518}; 567};
519 568
520static int __init init(void) 569static int __init init(void)
521{ 570{
571 int error;
572
573 virtblk_wq = alloc_workqueue("virtio-blk", 0, 0);
574 if (!virtblk_wq)
575 return -ENOMEM;
576
522 major = register_blkdev(0, "virtblk"); 577 major = register_blkdev(0, "virtblk");
523 if (major < 0) 578 if (major < 0) {
524 return major; 579 error = major;
525 return register_virtio_driver(&virtio_blk); 580 goto out_destroy_workqueue;
581 }
582
583 error = register_virtio_driver(&virtio_blk);
584 if (error)
585 goto out_unregister_blkdev;
586 return 0;
587
588out_unregister_blkdev:
589 unregister_blkdev(major, "virtblk");
590out_destroy_workqueue:
591 destroy_workqueue(virtblk_wq);
592 return error;
526} 593}
527 594
528static void __exit fini(void) 595static void __exit fini(void)
529{ 596{
530 unregister_blkdev(major, "virtblk"); 597 unregister_blkdev(major, "virtblk");
531 unregister_virtio_driver(&virtio_blk); 598 unregister_virtio_driver(&virtio_blk);
599 destroy_workqueue(virtblk_wq);
532} 600}
533module_init(init); 601module_init(init);
534module_exit(fini); 602module_exit(fini);