|
@@ -48,6 +48,7 @@
|
|
|
#include <linux/blk-mq.h>
|
|
|
#include <linux/hdreg.h>
|
|
|
#include <linux/scatterlist.h>
|
|
|
+#include <linux/idr.h>
|
|
|
#include <asm/div64.h>
|
|
|
|
|
|
#include "ubi-media.h"
|
|
@@ -353,6 +354,8 @@ static struct blk_mq_ops ubiblock_mq_ops = {
|
|
|
.map_queue = blk_mq_map_queue,
|
|
|
};
|
|
|
|
|
|
+static DEFINE_IDR(ubiblock_minor_idr);
|
|
|
+
|
|
|
int ubiblock_create(struct ubi_volume_info *vi)
|
|
|
{
|
|
|
struct ubiblock *dev;
|
|
@@ -390,7 +393,13 @@ int ubiblock_create(struct ubi_volume_info *vi)
|
|
|
|
|
|
gd->fops = &ubiblock_ops;
|
|
|
gd->major = ubiblock_major;
|
|
|
- gd->first_minor = dev->ubi_num * UBI_MAX_VOLUMES + dev->vol_id;
|
|
|
+ gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
|
|
|
+ if (gd->first_minor < 0) {
|
|
|
+ dev_err(disk_to_dev(gd),
|
|
|
+ "block: dynamic minor allocation failed");
|
|
|
+ ret = -ENODEV;
|
|
|
+ goto out_put_disk;
|
|
|
+ }
|
|
|
gd->private_data = dev;
|
|
|
sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
|
|
|
set_capacity(gd, disk_capacity);
|
|
@@ -407,7 +416,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
|
|
|
ret = blk_mq_alloc_tag_set(&dev->tag_set);
|
|
|
if (ret) {
|
|
|
dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
|
|
|
- goto out_put_disk;
|
|
|
+ goto out_remove_minor;
|
|
|
}
|
|
|
|
|
|
dev->rq = blk_mq_init_queue(&dev->tag_set);
|
|
@@ -445,6 +454,8 @@ out_free_queue:
|
|
|
blk_cleanup_queue(dev->rq);
|
|
|
out_free_tags:
|
|
|
blk_mq_free_tag_set(&dev->tag_set);
|
|
|
+out_remove_minor:
|
|
|
+ idr_remove(&ubiblock_minor_idr, gd->first_minor);
|
|
|
out_put_disk:
|
|
|
put_disk(dev->gd);
|
|
|
out_free_dev:
|
|
@@ -463,6 +474,7 @@ static void ubiblock_cleanup(struct ubiblock *dev)
|
|
|
blk_cleanup_queue(dev->rq);
|
|
|
blk_mq_free_tag_set(&dev->tag_set);
|
|
|
dev_info(disk_to_dev(dev->gd), "released");
|
|
|
+ idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
|
|
|
put_disk(dev->gd);
|
|
|
}
|
|
|
|