diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/virtio_blk.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 079c08808d8a..e7a5750a93d9 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
@@ -8,10 +8,13 @@ | |||
8 | #include <linux/scatterlist.h> | 8 | #include <linux/scatterlist.h> |
9 | #include <linux/string_helpers.h> | 9 | #include <linux/string_helpers.h> |
10 | #include <scsi/scsi_cmnd.h> | 10 | #include <scsi/scsi_cmnd.h> |
11 | #include <linux/idr.h> | ||
11 | 12 | ||
12 | #define PART_BITS 4 | 13 | #define PART_BITS 4 |
13 | 14 | ||
14 | static int major, index; | 15 | static int major; |
16 | static DEFINE_IDA(vd_index_ida); | ||
17 | |||
15 | struct workqueue_struct *virtblk_wq; | 18 | struct workqueue_struct *virtblk_wq; |
16 | 19 | ||
17 | struct virtio_blk | 20 | struct virtio_blk |
@@ -35,6 +38,9 @@ struct virtio_blk | |||
35 | /* What host tells us, plus 2 for header & tailer. */ | 38 | /* What host tells us, plus 2 for header & tailer. */ |
36 | unsigned int sg_elems; | 39 | unsigned int sg_elems; |
37 | 40 | ||
41 | /* Ida index - used to track minor number allocations. */ | ||
42 | int index; | ||
43 | |||
38 | /* Scatterlist: can be too big for stack. */ | 44 | /* Scatterlist: can be too big for stack. */ |
39 | struct scatterlist sg[/*sg_elems*/]; | 45 | struct scatterlist sg[/*sg_elems*/]; |
40 | }; | 46 | }; |
@@ -276,6 +282,11 @@ static int index_to_minor(int index) | |||
276 | return index << PART_BITS; | 282 | return index << PART_BITS; |
277 | } | 283 | } |
278 | 284 | ||
285 | static int minor_to_index(int minor) | ||
286 | { | ||
287 | return minor >> PART_BITS; | ||
288 | } | ||
289 | |||
279 | static ssize_t virtblk_serial_show(struct device *dev, | 290 | static ssize_t virtblk_serial_show(struct device *dev, |
280 | struct device_attribute *attr, char *buf) | 291 | struct device_attribute *attr, char *buf) |
281 | { | 292 | { |
@@ -341,14 +352,17 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
341 | { | 352 | { |
342 | struct virtio_blk *vblk; | 353 | struct virtio_blk *vblk; |
343 | struct request_queue *q; | 354 | struct request_queue *q; |
344 | int err; | 355 | int err, index; |
345 | u64 cap; | 356 | u64 cap; |
346 | u32 v, blk_size, sg_elems, opt_io_size; | 357 | u32 v, blk_size, sg_elems, opt_io_size; |
347 | u16 min_io_size; | 358 | u16 min_io_size; |
348 | u8 physical_block_exp, alignment_offset; | 359 | u8 physical_block_exp, alignment_offset; |
349 | 360 | ||
350 | if (index_to_minor(index) >= 1 << MINORBITS) | 361 | err = ida_simple_get(&vd_index_ida, 0, minor_to_index(1 << MINORBITS), |
351 | return -ENOSPC; | 362 | GFP_KERNEL); |
363 | if (err < 0) | ||
364 | goto out; | ||
365 | index = err; | ||
352 | 366 | ||
353 | /* We need to know how many segments before we allocate. */ | 367 | /* We need to know how many segments before we allocate. */ |
354 | err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX, | 368 | err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX, |
@@ -365,7 +379,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
365 | sizeof(vblk->sg[0]) * sg_elems, GFP_KERNEL); | 379 | sizeof(vblk->sg[0]) * sg_elems, GFP_KERNEL); |
366 | if (!vblk) { | 380 | if (!vblk) { |
367 | err = -ENOMEM; | 381 | err = -ENOMEM; |
368 | goto out; | 382 | goto out_free_index; |
369 | } | 383 | } |
370 | 384 | ||
371 | INIT_LIST_HEAD(&vblk->reqs); | 385 | INIT_LIST_HEAD(&vblk->reqs); |
@@ -421,7 +435,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) | |||
421 | vblk->disk->private_data = vblk; | 435 | vblk->disk->private_data = vblk; |
422 | vblk->disk->fops = &virtblk_fops; | 436 | vblk->disk->fops = &virtblk_fops; |
423 | vblk->disk->driverfs_dev = &vdev->dev; | 437 | vblk->disk->driverfs_dev = &vdev->dev; |
424 | index++; | 438 | vblk->index = index; |
425 | 439 | ||
426 | /* configure queue flush support */ | 440 | /* configure queue flush support */ |
427 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) | 441 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) |
@@ -516,6 +530,8 @@ out_free_vq: | |||
516 | vdev->config->del_vqs(vdev); | 530 | vdev->config->del_vqs(vdev); |
517 | out_free_vblk: | 531 | out_free_vblk: |
518 | kfree(vblk); | 532 | kfree(vblk); |
533 | out_free_index: | ||
534 | ida_simple_remove(&vd_index_ida, index); | ||
519 | out: | 535 | out: |
520 | return err; | 536 | return err; |
521 | } | 537 | } |
@@ -523,6 +539,7 @@ out: | |||
523 | static void __devexit virtblk_remove(struct virtio_device *vdev) | 539 | static void __devexit virtblk_remove(struct virtio_device *vdev) |
524 | { | 540 | { |
525 | struct virtio_blk *vblk = vdev->priv; | 541 | struct virtio_blk *vblk = vdev->priv; |
542 | int index = vblk->index; | ||
526 | 543 | ||
527 | flush_work(&vblk->config_work); | 544 | flush_work(&vblk->config_work); |
528 | 545 | ||
@@ -538,6 +555,7 @@ static void __devexit virtblk_remove(struct virtio_device *vdev) | |||
538 | mempool_destroy(vblk->pool); | 555 | mempool_destroy(vblk->pool); |
539 | vdev->config->del_vqs(vdev); | 556 | vdev->config->del_vqs(vdev); |
540 | kfree(vblk); | 557 | kfree(vblk); |
558 | ida_simple_remove(&vd_index_ida, index); | ||
541 | } | 559 | } |
542 | 560 | ||
543 | static const struct virtio_device_id id_table[] = { | 561 | static const struct virtio_device_id id_table[] = { |