aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Ehrenberg <dehrenberg@chromium.org>2015-03-17 13:37:26 -0400
committerRichard Weinberger <richard@nod.at>2015-06-02 05:35:49 -0400
commit2bf50d42f3a418153d2964ca0f25655177f36445 (patch)
tree1567f0d7744c6f1ad64a0ebd2b8dbe7b79b4aaf8
parentc65b99f046843d2455aa231747b5a07a999a9f3d (diff)
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>
-rw-r--r--drivers/mtd/ubi/block.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index c9eb78f10a0d..1a92d30689e7 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -48,6 +48,7 @@
48#include <linux/blk-mq.h> 48#include <linux/blk-mq.h>
49#include <linux/hdreg.h> 49#include <linux/hdreg.h>
50#include <linux/scatterlist.h> 50#include <linux/scatterlist.h>
51#include <linux/idr.h>
51#include <asm/div64.h> 52#include <asm/div64.h>
52 53
53#include "ubi-media.h" 54#include "ubi-media.h"
@@ -353,6 +354,8 @@ static struct blk_mq_ops ubiblock_mq_ops = {
353 .map_queue = blk_mq_map_queue, 354 .map_queue = blk_mq_map_queue,
354}; 355};
355 356
357static DEFINE_IDR(ubiblock_minor_idr);
358
356int ubiblock_create(struct ubi_volume_info *vi) 359int ubiblock_create(struct ubi_volume_info *vi)
357{ 360{
358 struct ubiblock *dev; 361 struct ubiblock *dev;
@@ -390,7 +393,13 @@ int ubiblock_create(struct ubi_volume_info *vi)
390 393
391 gd->fops = &ubiblock_ops; 394 gd->fops = &ubiblock_ops;
392 gd->major = ubiblock_major; 395 gd->major = ubiblock_major;
393 gd->first_minor = dev->ubi_num * UBI_MAX_VOLUMES + dev->vol_id; 396 gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
397 if (gd->first_minor < 0) {
398 dev_err(disk_to_dev(gd),
399 "block: dynamic minor allocation failed");
400 ret = -ENODEV;
401 goto out_put_disk;
402 }
394 gd->private_data = dev; 403 gd->private_data = dev;
395 sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); 404 sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
396 set_capacity(gd, disk_capacity); 405 set_capacity(gd, disk_capacity);
@@ -407,7 +416,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
407 ret = blk_mq_alloc_tag_set(&dev->tag_set); 416 ret = blk_mq_alloc_tag_set(&dev->tag_set);
408 if (ret) { 417 if (ret) {
409 dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed"); 418 dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
410 goto out_put_disk; 419 goto out_remove_minor;
411 } 420 }
412 421
413 dev->rq = blk_mq_init_queue(&dev->tag_set); 422 dev->rq = blk_mq_init_queue(&dev->tag_set);
@@ -445,6 +454,8 @@ out_free_queue:
445 blk_cleanup_queue(dev->rq); 454 blk_cleanup_queue(dev->rq);
446out_free_tags: 455out_free_tags:
447 blk_mq_free_tag_set(&dev->tag_set); 456 blk_mq_free_tag_set(&dev->tag_set);
457out_remove_minor:
458 idr_remove(&ubiblock_minor_idr, gd->first_minor);
448out_put_disk: 459out_put_disk:
449 put_disk(dev->gd); 460 put_disk(dev->gd);
450out_free_dev: 461out_free_dev:
@@ -463,6 +474,7 @@ static void ubiblock_cleanup(struct ubiblock *dev)
463 blk_cleanup_queue(dev->rq); 474 blk_cleanup_queue(dev->rq);
464 blk_mq_free_tag_set(&dev->tag_set); 475 blk_mq_free_tag_set(&dev->tag_set);
465 dev_info(disk_to_dev(dev->gd), "released"); 476 dev_info(disk_to_dev(dev->gd), "released");
477 idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
466 put_disk(dev->gd); 478 put_disk(dev->gd);
467} 479}
468 480