[RFC 12/12] block: make probe in blk_request_module() return an error

From: Luis Chamberlain
Date: Thu Jul 15 2021 - 17:00:28 EST


This makes the probe callback use din blk_request_module() return
an error. We do this as add_disk() now has error handling, and
so we can bail earlier than before. If a probe is not implemented
then its not used.

This is mostly useful for the following drivers:

* ataflop
* brd
* floppy
* loop
* scsi/sd

Signed-off-by: Luis Chamberlain <mcgrof@xxxxxxxxxx>
---
block/genhd.c | 15 +++++++++------
drivers/block/ataflop.c | 20 +++++++++++++++-----
drivers/block/brd.c | 7 +++++--
drivers/block/floppy.c | 14 ++++++++++----
drivers/block/loop.c | 6 +++---
drivers/scsi/sd.c | 3 ++-
fs/block_dev.c | 5 ++++-
include/linux/genhd.h | 4 ++--
8 files changed, 50 insertions(+), 24 deletions(-)

diff --git a/block/genhd.c b/block/genhd.c
index 72703d243b44..ca6393df09ad 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -161,7 +161,7 @@ static struct blk_major_name {
struct blk_major_name *next;
int major;
char name[16];
- void (*probe)(dev_t devt);
+ int (*probe)(dev_t devt);
} *major_names[BLKDEV_MAJOR_HASH_SIZE];
static DEFINE_MUTEX(major_names_lock);

@@ -190,7 +190,7 @@ void blkdev_show(struct seq_file *seqf, off_t offset)
* @major: the requested major device number [1..BLKDEV_MAJOR_MAX-1]. If
* @major = 0, try to allocate any unused major number.
* @name: the name of the new block device as a zero terminated string
- * @probe: allback that is called on access to any minor number of @major
+ * @probe: callback that is called on access to any minor number of @major
*
* The @name must be unique within the system.
*
@@ -208,7 +208,7 @@ void blkdev_show(struct seq_file *seqf, off_t offset)
* Use register_blkdev instead for any new code.
*/
int __register_blkdev(unsigned int major, const char *name,
- void (*probe)(dev_t devt))
+ int (*probe)(dev_t devt))
{
struct blk_major_name **n, *p;
int index, ret = 0;
@@ -728,17 +728,18 @@ static ssize_t disk_badblocks_store(struct device *dev,
return badblocks_store(disk->bb, page, len, 0);
}

-void blk_request_module(dev_t devt)
+int blk_request_module(dev_t devt)
{
unsigned int major = MAJOR(devt);
struct blk_major_name **n;
+ int err;

mutex_lock(&major_names_lock);
for (n = &major_names[major_to_index(major)]; *n; n = &(*n)->next) {
if ((*n)->major == major && (*n)->probe) {
- (*n)->probe(devt);
+ err = (*n)->probe(devt);
mutex_unlock(&major_names_lock);
- return;
+ return err;
}
}
mutex_unlock(&major_names_lock);
@@ -746,6 +747,8 @@ void blk_request_module(dev_t devt)
if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
/* Make old-style 2.4 aliases work */
request_module("block-major-%d", MAJOR(devt));
+
+ return 0;
}

/*
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 4b3f1158fa04..ce08b8e60163 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -2005,22 +2005,32 @@ static void atari_floppy_disk_remove(void)

}

-static void ataflop_probe(dev_t dev)
+static int ataflop_probe(dev_t dev)
{
int drive = MINOR(dev) & 3;
int type = MINOR(dev) >> 2;
+ int err = -ENODEV;

if (type)
type--;

- if (drive >= FD_MAX_UNITS || type >= NUM_DISK_MINORS)
- return;
+ if (drive >= FD_MAX_UNITS || type >= NUM_DISK_MINORS) {
+ err = -EINVAL;
+ goto out;
+ }
+
mutex_lock(&ataflop_probe_lock);
if (!unit[drive].disk[type]) {
- if (ataflop_alloc_disk(drive, type) == 0)
- add_disk(unit[drive].disk[type]);
+ if (ataflop_alloc_disk(drive, type) == 0) {
+ err = add_disk(unit[drive].disk[type]);
+ if (err)
+ blk_cleanup_disk(unit[drive].disk[type]);
+ }
}
mutex_unlock(&ataflop_probe_lock);
+
+out:
+ return err;
}

static int __init atari_floppy_init (void)
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index ca017ca315c5..104adf70a15a 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -429,10 +429,11 @@ static int brd_alloc(int i)
return err;
}

-static void brd_probe(dev_t dev)
+static int brd_probe(dev_t dev)
{
int i = MINOR(dev) / max_part;
struct brd_device *brd;
+ int err = 0;

mutex_lock(&brd_devices_mutex);
list_for_each_entry(brd, &brd_devices, brd_list) {
@@ -440,9 +441,11 @@ static void brd_probe(dev_t dev)
goto out_unlock;
}

- brd_alloc(i);
+ err = brd_alloc(i);
out_unlock:
mutex_unlock(&brd_devices_mutex);
+
+ return err;
}

static void brd_del_one(struct brd_device *brd)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index cad17b49e700..52bc645f3060 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4517,21 +4517,27 @@ static int floppy_alloc_disk(unsigned int drive, unsigned int type)

static DEFINE_MUTEX(floppy_probe_lock);

-static void floppy_probe(dev_t dev)
+static int floppy_probe(dev_t dev)
{
unsigned int drive = (MINOR(dev) & 3) | ((MINOR(dev) & 0x80) >> 5);
unsigned int type = (MINOR(dev) >> 2) & 0x1f;
+ int err;

if (drive >= N_DRIVE || !floppy_available(drive) ||
type >= ARRAY_SIZE(floppy_type))
- return;
+ return -EINVAL;

mutex_lock(&floppy_probe_lock);
if (!disks[drive][type]) {
- if (floppy_alloc_disk(drive, type) == 0)
- add_disk(disks[drive][type]);
+ if (floppy_alloc_disk(drive, type) == 0) {
+ err = add_disk(disks[drive][type]);
+ if (err)
+ blk_cleanup_disk(disks[drive][type]);
+ }
}
mutex_unlock(&floppy_probe_lock);
+
+ return err;
}

static int __init do_floppy_init(void)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index efbd8e29aca7..081cccd39bc9 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -2358,13 +2358,13 @@ static void loop_remove(struct loop_device *lo)
kfree(lo);
}

-static void loop_probe(dev_t dev)
+static int loop_probe(dev_t dev)
{
int idx = MINOR(dev) >> part_shift;

if (max_loop && idx >= max_loop)
- return;
- loop_add(idx);
+ return -EINVAL;
+ return loop_add(idx);
}

static int loop_control_remove(int idx)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 01af61a38e4e..800dfd5984bd 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -633,8 +633,9 @@ static struct scsi_driver sd_template = {
* Don't request a new module, as that could deadlock in multipath
* environment.
*/
-static void sd_default_probe(dev_t devt)
+static int sd_default_probe(dev_t devt)
{
+ return 0;
}

/*
diff --git a/fs/block_dev.c b/fs/block_dev.c
index c41d0e550d39..531feb097cb2 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1326,10 +1326,13 @@ struct block_device *blkdev_get_no_open(dev_t dev)
{
struct block_device *bdev;
struct gendisk *disk;
+ int err;

bdev = bdget(dev);
if (!bdev) {
- blk_request_module(dev);
+ err = blk_request_module(dev);
+ if (err)
+ return NULL;
bdev = bdget(dev);
if (!bdev)
return NULL;
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 73024416d2d5..9db56d4562ae 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -312,7 +312,7 @@ struct gendisk *__blk_alloc_disk(int node);
void blk_cleanup_disk(struct gendisk *disk);

int __register_blkdev(unsigned int major, const char *name,
- void (*probe)(dev_t devt));
+ int (*probe)(dev_t devt));
#define register_blkdev(major, name) \
__register_blkdev(major, name, NULL)
void unregister_blkdev(unsigned int major, const char *name);
@@ -342,7 +342,7 @@ static inline void bd_unlink_disk_holder(struct block_device *bdev,

dev_t part_devt(struct gendisk *disk, u8 partno);
dev_t blk_lookup_devt(const char *name, int partno);
-void blk_request_module(dev_t devt);
+int blk_request_module(dev_t devt);
#ifdef CONFIG_BLOCK
void printk_all_partitions(void);
#else /* CONFIG_BLOCK */
--
2.27.0