diff options
Diffstat (limited to 'drivers/block/virtio_blk.c')
-rw-r--r-- | drivers/block/virtio_blk.c | 91 |
1 files changed, 80 insertions, 11 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 6ecf89cdf006..079c08808d8a 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
@@ -6,10 +6,13 @@ | |||
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> | ||
10 | #include <scsi/scsi_cmnd.h> | ||
9 | 11 | ||
10 | #define PART_BITS 4 | 12 | #define PART_BITS 4 |
11 | 13 | ||
12 | static int major, index; | 14 | static int major, index; |
15 | struct workqueue_struct *virtblk_wq; | ||
13 | 16 | ||
14 | struct virtio_blk | 17 | struct virtio_blk |
15 | { | 18 | { |
@@ -26,6 +29,9 @@ struct virtio_blk | |||
26 | 29 | ||
27 | mempool_t *pool; | 30 | mempool_t *pool; |
28 | 31 | ||
32 | /* Process context for config space updates */ | ||
33 | struct work_struct config_work; | ||
34 | |||
29 | /* What host tells us, plus 2 for header & tailer. */ | 35 | /* What host tells us, plus 2 for header & tailer. */ |
30 | unsigned int sg_elems; | 36 | unsigned int sg_elems; |
31 | 37 | ||
@@ -141,7 +147,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, | |||
141 | num = blk_rq_map_sg(q, vbr->req, vblk->sg + out); | 147 | num = blk_rq_map_sg(q, vbr->req, vblk->sg + out); |
142 | 148 | ||
143 | if (vbr->req->cmd_type == REQ_TYPE_BLOCK_PC) { | 149 | if (vbr->req->cmd_type == REQ_TYPE_BLOCK_PC) { |
144 | sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96); | 150 | sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, SCSI_SENSE_BUFFERSIZE); |
145 | sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr, | 151 | sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr, |
146 | sizeof(vbr->in_hdr)); | 152 | sizeof(vbr->in_hdr)); |
147 | } | 153 | } |
@@ -291,6 +297,46 @@ static ssize_t virtblk_serial_show(struct device *dev, | |||
291 | } | 297 | } |
292 | DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL); | 298 | DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL); |
293 | 299 | ||
300 | static void virtblk_config_changed_work(struct work_struct *work) | ||
301 | { | ||
302 | struct virtio_blk *vblk = | ||
303 | container_of(work, struct virtio_blk, config_work); | ||
304 | struct virtio_device *vdev = vblk->vdev; | ||
305 | struct request_queue *q = vblk->disk->queue; | ||
306 | char cap_str_2[10], cap_str_10[10]; | ||
307 | u64 capacity, size; | ||
308 | |||
309 | /* Host must always specify the capacity. */ | ||
310 | vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity), | ||
311 | &capacity, sizeof(capacity)); | ||
312 | |||
313 | /* If capacity is too big, truncate with warning. */ | ||
314 | if ((sector_t)capacity != capacity) { | ||
315 | dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n", | ||
316 | (unsigned long long)capacity); | ||
317 | capacity = (sector_t)-1; | ||
318 | } | ||
319 | |||
320 | size = capacity * queue_logical_block_size(q); | ||
321 | string_get_size(size, STRING_UNITS_2, cap_str_2, sizeof(cap_str_2)); | ||
322 | string_get_size(size, STRING_UNITS_10, cap_str_10, sizeof(cap_str_10)); | ||
323 | |||
324 | dev_notice(&vdev->dev, | ||
325 | "new size: %llu %d-byte logical blocks (%s/%s)\n", | ||
326 | (unsigned long long)capacity, | ||
327 | queue_logical_block_size(q), | ||
328 | cap_str_10, cap_str_2); | ||
329 | |||
330 | set_capacity(vblk->disk, capacity); | ||
331 | } | ||
332 | |||
333 | static void virtblk_config_changed(struct virtio_device *vdev) | ||
334 | { | ||
335 | struct virtio_blk *vblk = vdev->priv; | ||
336 | |||
337 | queue_work(virtblk_wq, &vblk->config_work); | ||
338 | } | ||
339 | |||
294 | static int __devinit virtblk_probe(struct virtio_device *vdev) | 340 | static int __devinit virtblk_probe(struct virtio_device *vdev) |
295 | { | 341 | { |
296 | struct virtio_blk *vblk; | 342 | struct virtio_blk *vblk; |
@@ -327,6 +373,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
327 | vblk->vdev = vdev; | 373 | vblk->vdev = vdev; |
328 | vblk->sg_elems = sg_elems; | 374 | vblk->sg_elems = sg_elems; |
329 | sg_init_table(vblk->sg, vblk->sg_elems); | 375 | sg_init_table(vblk->sg, vblk->sg_elems); |
376 | INIT_WORK(&vblk->config_work, virtblk_config_changed_work); | ||
330 | 377 | ||
331 | /* We expect one virtqueue, for output. */ | 378 | /* We expect one virtqueue, for output. */ |
332 | vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests"); | 379 | vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests"); |
@@ -477,6 +524,8 @@ static void __devexit virtblk_remove(struct virtio_device *vdev) | |||
477 | { | 524 | { |
478 | struct virtio_blk *vblk = vdev->priv; | 525 | struct virtio_blk *vblk = vdev->priv; |
479 | 526 | ||
527 | flush_work(&vblk->config_work); | ||
528 | |||
480 | /* Nothing should be pending. */ | 529 | /* Nothing should be pending. */ |
481 | BUG_ON(!list_empty(&vblk->reqs)); | 530 | BUG_ON(!list_empty(&vblk->reqs)); |
482 | 531 | ||
@@ -508,27 +557,47 @@ static unsigned int features[] = { | |||
508 | * Use __refdata to avoid this warning. | 557 | * Use __refdata to avoid this warning. |
509 | */ | 558 | */ |
510 | static struct virtio_driver __refdata virtio_blk = { | 559 | static struct virtio_driver __refdata virtio_blk = { |
511 | .feature_table = features, | 560 | .feature_table = features, |
512 | .feature_table_size = ARRAY_SIZE(features), | 561 | .feature_table_size = ARRAY_SIZE(features), |
513 | .driver.name = KBUILD_MODNAME, | 562 | .driver.name = KBUILD_MODNAME, |
514 | .driver.owner = THIS_MODULE, | 563 | .driver.owner = THIS_MODULE, |
515 | .id_table = id_table, | 564 | .id_table = id_table, |
516 | .probe = virtblk_probe, | 565 | .probe = virtblk_probe, |
517 | .remove = __devexit_p(virtblk_remove), | 566 | .remove = __devexit_p(virtblk_remove), |
567 | .config_changed = virtblk_config_changed, | ||
518 | }; | 568 | }; |
519 | 569 | ||
520 | static int __init init(void) | 570 | static int __init init(void) |
521 | { | 571 | { |
572 | int error; | ||
573 | |||
574 | virtblk_wq = alloc_workqueue("virtio-blk", 0, 0); | ||
575 | if (!virtblk_wq) | ||
576 | return -ENOMEM; | ||
577 | |||
522 | major = register_blkdev(0, "virtblk"); | 578 | major = register_blkdev(0, "virtblk"); |
523 | if (major < 0) | 579 | if (major < 0) { |
524 | return major; | 580 | error = major; |
525 | return register_virtio_driver(&virtio_blk); | 581 | goto out_destroy_workqueue; |
582 | } | ||
583 | |||
584 | error = register_virtio_driver(&virtio_blk); | ||
585 | if (error) | ||
586 | goto out_unregister_blkdev; | ||
587 | return 0; | ||
588 | |||
589 | out_unregister_blkdev: | ||
590 | unregister_blkdev(major, "virtblk"); | ||
591 | out_destroy_workqueue: | ||
592 | destroy_workqueue(virtblk_wq); | ||
593 | return error; | ||
526 | } | 594 | } |
527 | 595 | ||
528 | static void __exit fini(void) | 596 | static void __exit fini(void) |
529 | { | 597 | { |
530 | unregister_blkdev(major, "virtblk"); | 598 | unregister_blkdev(major, "virtblk"); |
531 | unregister_virtio_driver(&virtio_blk); | 599 | unregister_virtio_driver(&virtio_blk); |
600 | destroy_workqueue(virtblk_wq); | ||
532 | } | 601 | } |
533 | module_init(init); | 602 | module_init(init); |
534 | module_exit(fini); | 603 | module_exit(fini); |