UBI: block: Dynamically allocate minor numbers
This patch makes ubiblock devices have minor numbers beginning from 0, allocated dynamically independently of the ubi device/volume number. This property becomes useful because, on 32-bit architectures with LFS turned off in a userspace program, device minor numbers over 8 bits cause stat to return -EOVERFLOW. If the device number is high (>1) due to multiple MTD partitions, such an overflow will occur. While enabling LFS is clearly a nicer solution, it's often difficult to turn on in practice globally as many widely distributed packages don't work with LFS on. Other storage systems have their own workarounds, with SCSI making multiple device majors and MMC having a config option for the number of partitions per device. A completely dynamic minor numbering is simpler than these. It is unlikely that anyone is depending on a static minor number since the major is dynamic anyway. In addition, ubiblock is still relatively new, so now is the time to make such changes. Signed-off-by: Dan Ehrenberg <dehrenberg@chromium.org> Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
c65b99f046
commit
2bf50d42f3
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue