block: refactor device number setup in __device_add_disk

Untangle the mess around blk_alloc_devt by moving the check for
the used allocation scheme into the callers.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://lore.kernel.org/r/20210521055116.1053587-2-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Christoph Hellwig 2021-05-21 07:50:51 +02:00 committed by Jens Axboe
parent d97e594c51
commit 7c3f828b52
3 changed files with 49 additions and 66 deletions

View File

@ -343,8 +343,8 @@ static inline void blk_queue_free_zone_bitmaps(struct request_queue *q) {}
static inline void blk_queue_clear_zone_settings(struct request_queue *q) {}
#endif
int blk_alloc_devt(struct block_device *part, dev_t *devt);
void blk_free_devt(dev_t devt);
int blk_alloc_ext_minor(void);
void blk_free_ext_minor(unsigned int minor);
char *disk_name(struct gendisk *hd, int partno, char *buf);
#define ADDPART_FLAG_NONE 0
#define ADDPART_FLAG_RAID 1

View File

@ -333,52 +333,22 @@ static int blk_mangle_minor(int minor)
return minor;
}
/**
* blk_alloc_devt - allocate a dev_t for a block device
* @bdev: block device to allocate dev_t for
* @devt: out parameter for resulting dev_t
*
* Allocate a dev_t for block device.
*
* RETURNS:
* 0 on success, allocated dev_t is returned in *@devt. -errno on
* failure.
*
* CONTEXT:
* Might sleep.
*/
int blk_alloc_devt(struct block_device *bdev, dev_t *devt)
int blk_alloc_ext_minor(void)
{
struct gendisk *disk = bdev->bd_disk;
int idx;
/* in consecutive minor range? */
if (bdev->bd_partno < disk->minors) {
*devt = MKDEV(disk->major, disk->first_minor + bdev->bd_partno);
return 0;
}
idx = ida_alloc_range(&ext_devt_ida, 0, NR_EXT_DEVT, GFP_KERNEL);
if (idx < 0)
return idx == -ENOSPC ? -EBUSY : idx;
*devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
return 0;
if (idx < 0) {
if (idx == -ENOSPC)
return -EBUSY;
return idx;
}
return blk_mangle_minor(idx);
}
/**
* blk_free_devt - free a dev_t
* @devt: dev_t to free
*
* Free @devt which was allocated using blk_alloc_devt().
*
* CONTEXT:
* Might sleep.
*/
void blk_free_devt(dev_t devt)
void blk_free_ext_minor(unsigned int minor)
{
if (MAJOR(devt) == BLOCK_EXT_MAJOR)
ida_free(&ext_devt_ida, blk_mangle_minor(MINOR(devt)));
ida_free(&ext_devt_ida, blk_mangle_minor(minor));
}
static char *bdevt_str(dev_t devt, char *buf)
@ -499,8 +469,7 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
const struct attribute_group **groups,
bool register_queue)
{
dev_t devt;
int retval;
int ret;
/*
* The disk queue should now be all set with enough information about
@ -511,24 +480,30 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
if (register_queue)
elevator_init_mq(disk->queue);
/* minors == 0 indicates to use ext devt from part0 and should
* be accompanied with EXT_DEVT flag. Make sure all
* parameters make sense.
/*
* If the driver provides an explicit major number it also must provide
* the number of minors numbers supported, and those will be used to
* setup the gendisk.
* Otherwise just allocate the device numbers for both the whole device
* and all partitions from the extended dev_t space.
*/
WARN_ON(disk->minors && !(disk->major || disk->first_minor));
WARN_ON(!disk->minors &&
!(disk->flags & (GENHD_FL_EXT_DEVT | GENHD_FL_HIDDEN)));
if (disk->major) {
WARN_ON(!disk->minors);
} else {
WARN_ON(disk->minors);
WARN_ON(!(disk->flags & (GENHD_FL_EXT_DEVT | GENHD_FL_HIDDEN)));
ret = blk_alloc_ext_minor();
if (ret < 0) {
WARN_ON(1);
return;
}
disk->major = BLOCK_EXT_MAJOR;
disk->first_minor = MINOR(ret);
}
disk->flags |= GENHD_FL_UP;
retval = blk_alloc_devt(disk->part0, &devt);
if (retval) {
WARN_ON(1);
return;
}
disk->major = MAJOR(devt);
disk->first_minor = MINOR(devt);
disk_alloc_events(disk);
if (disk->flags & GENHD_FL_HIDDEN) {
@ -541,14 +516,14 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
} else {
struct backing_dev_info *bdi = disk->queue->backing_dev_info;
struct device *dev = disk_to_dev(disk);
int ret;
/* Register BDI before referencing it from bdev */
dev->devt = devt;
ret = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt));
dev->devt = MKDEV(disk->major, disk->first_minor);
ret = bdi_register(bdi, "%u:%u",
disk->major, disk->first_minor);
WARN_ON(ret);
bdi_set_owner(bdi, dev);
bdev_add(disk->part0, devt);
bdev_add(disk->part0, dev->devt);
}
register_disk(parent, disk, groups);
if (register_queue)
@ -1120,7 +1095,8 @@ static void disk_release(struct device *dev)
might_sleep();
blk_free_devt(dev->devt);
if (MAJOR(dev->devt) == BLOCK_EXT_MAJOR)
blk_free_ext_minor(MINOR(dev->devt));
disk_release_events(disk);
kfree(disk->random);
xa_destroy(&disk->part_tbl);

View File

@ -260,7 +260,8 @@ static const struct attribute_group *part_attr_groups[] = {
static void part_release(struct device *dev)
{
blk_free_devt(dev->devt);
if (MAJOR(dev->devt) == BLOCK_EXT_MAJOR)
blk_free_ext_minor(MINOR(dev->devt));
bdput(dev_to_bdev(dev));
}
@ -379,9 +380,15 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
pdev->type = &part_type;
pdev->parent = ddev;
err = blk_alloc_devt(bdev, &devt);
if (err)
goto out_put;
/* in consecutive minor range? */
if (bdev->bd_partno < disk->minors) {
devt = MKDEV(disk->major, disk->first_minor + bdev->bd_partno);
} else {
err = blk_alloc_ext_minor();
if (err < 0)
goto out_put;
devt = MKDEV(BLOCK_EXT_MAJOR, err);
}
pdev->devt = devt;
/* delay uevent until 'holders' subdir is created */