Befor these paths, block is not know when drvier is add fail. Now, add error handling for drivers.
Christoph Hellwig (14): block: fold register_disk into device_add_disk block: call blk_integrity_add earlier in device_add_disk block: add the events* attributes to disk_attrs block: fix error unwinding in device_add_disk block: clear ->slave_dir when dropping the main slave_dir reference block: add blk_alloc_disk and blk_cleanup_disk APIs blk-mq: add the blk_mq_alloc_disk APIs loop: use blk_mq_alloc_disk and blk_cleanup_disk loop: fix order of cleaning up the queue and freeing the tagset nbd: use blk_mq_alloc_disk and blk_cleanup_disk block: add a flag to make put_disk on partially initalized disks safer nvme: use blk_mq_alloc_disk brd: convert to blk_alloc_disk/blk_cleanup_disk ubi: use blk_mq_alloc_disk and blk_cleanup_disk
Dan Carpenter (1): blk-mq: fix an IS_ERR() vs NULL bug
Luis Chamberlain (11): block: return errors from blk_integrity_add block: return errors from disk_alloc_events block: add error handling for device_add_disk / add_disk block: fix device_add_disk() kobject_create_and_add() error handling loop: add error handling support for add_disk() nbd: add error handling support for add_disk() nvme: add error handling support for add_disk() block/brd: add error handling support for add_disk() scsi: sd: Add error handling support for add_disk() scsi: sr: Add error handling support for add_disk() mtd/ubi/block: add error handling support for add_disk()
Tetsuo Handa (1): block: check minor range in device_add_disk()
Wang Qing (1): nbd: fix order of cleaning up the queue and freeing the tagset
Yu Kuai (1): block: fix memory leak for elevator on add_disk failure
Zhong Jinghua (9): block: return errors from blk_register_region block: Fix the kabi change in device_add_disk block: Fix the kabi change on blk_register_region block: call blk_get_queue earlier in __device_add_disk block: Fix minor range check in device_add_disk() block: Set memalloc_noio to false in the error path scsi: sd: Clean up sdkp if device_add_disk() failed mtd/ubi/block: Fix null pointer dereference issue in error path mtd/ubi/block: Fix uaf problem in ubiblock_cleanup
block/blk-integrity.c | 12 +- block/blk-mq.c | 19 +++ block/blk.h | 5 +- block/genhd.c | 286 ++++++++++++++++++++++++++------------- drivers/block/brd.c | 103 ++++++-------- drivers/block/loop.c | 26 ++-- drivers/block/nbd.c | 59 ++++---- drivers/mtd/ubi/block.c | 76 +++++------ drivers/nvme/host/core.c | 41 +++--- drivers/scsi/sd.c | 8 +- drivers/scsi/sr.c | 7 +- include/linux/blk-mq.h | 12 ++ include/linux/genhd.h | 36 +++++ 13 files changed, 417 insertions(+), 273 deletions(-)
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.15-rc1 commit 52b85909f85d06efa69aaf4210e72467f1f58d2b category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
There is no real reason these should be separate. Also simplify the groups assignment a bit.
Signed-off-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/20210818144542.19305-3-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 97 +++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 53 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 83f407e1563a..aef153a824a4 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -687,55 +687,6 @@ static int exact_lock(dev_t devt, void *data) return 0; }
-static void register_disk(struct device *parent, struct gendisk *disk, - const struct attribute_group **groups) -{ - struct device *ddev = disk_to_dev(disk); - int err; - - ddev->parent = parent; - - dev_set_name(ddev, "%s", disk->disk_name); - - /* delay uevents, until we scanned partition table */ - dev_set_uevent_suppress(ddev, 1); - - if (groups) { - WARN_ON(ddev->groups); - ddev->groups = groups; - } - if (device_add(ddev)) - return; - if (!sysfs_deprecated) { - err = sysfs_create_link(block_depr, &ddev->kobj, - kobject_name(&ddev->kobj)); - if (err) { - device_del(ddev); - return; - } - } - - /* - * avoid probable deadlock caused by allocating memory with - * GFP_KERNEL in runtime_resume callback of its all ancestor - * devices - */ - pm_runtime_set_memalloc_noio(ddev, true); - - disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); - disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); - - if (disk->flags & GENHD_FL_HIDDEN) - return; - - if (disk->queue->backing_dev_info->dev) { - err = sysfs_create_link(&ddev->kobj, - &disk->queue->backing_dev_info->dev->kobj, - "bdi"); - WARN_ON(err); - } -} - int disk_scan_partitions(struct gendisk *disk, fmode_t mode) { struct block_device *bdev; @@ -820,6 +771,7 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, const struct attribute_group **groups, bool register_queue) { + struct device *ddev = disk_to_dev(disk); dev_t devt; int retval;
@@ -859,18 +811,57 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, disk->flags |= GENHD_FL_NO_PART_SCAN; } 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; + ddev->devt = devt; ret = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt)); WARN_ON(ret); - bdi_set_owner(bdi, dev); + bdi_set_owner(bdi, ddev); blk_register_region(disk_devt(disk), disk->minors, NULL, exact_match, exact_lock, disk); } - register_disk(parent, disk, groups); + + /* delay uevents, until we scanned partition table */ + dev_set_uevent_suppress(ddev, 1); + + ddev->parent = parent; + if (groups) { + WARN_ON(ddev->groups); + ddev->groups = groups; + } + dev_set_name(ddev, "%s", disk->disk_name); + if (device_add(ddev)) + return; + if (!sysfs_deprecated) { + retval = sysfs_create_link(block_depr, &ddev->kobj, + kobject_name(&ddev->kobj)); + if (retval) { + device_del(ddev); + return; + } + } + + /* + * avoid probable deadlock caused by allocating memory with + * GFP_KERNEL in runtime_resume callback of its all ancestor + * devices + */ + pm_runtime_set_memalloc_noio(ddev, true); + + disk->part0.holder_dir = + kobject_create_and_add("holders", &ddev->kobj); + disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); + + if (!(disk->flags & GENHD_FL_HIDDEN)) { + if (disk->queue->backing_dev_info->dev) { + retval = sysfs_create_link(&ddev->kobj, + &disk->queue->backing_dev_info->dev->kobj, + "bdi"); + WARN_ON(retval); + } + } + if (register_queue) blk_register_queue(disk);
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.15-rc1 commit bab53f6b617d9f530978d6e3693f88e586d81a8a category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Doing all the sysfs file creation before adding the bdev and thus allowing it to be opened will simplify the about to be added error handling.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Link: https://lore.kernel.org/r/20210818144542.19305-6-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/block/genhd.c b/block/genhd.c index aef153a824a4..d2153303ae05 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -849,6 +849,8 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, */ pm_runtime_set_memalloc_noio(ddev, true);
+ blk_integrity_add(disk); + disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); @@ -872,7 +874,6 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, WARN_ON_ONCE(!blk_get_queue(disk->queue));
disk_add_events(disk); - blk_integrity_add(disk);
/* Make sure the first partition scan will be proceed */ if (get_capacity(disk) && disk_part_scan_enabled(disk))
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.15-rc1 commit 614310c9c8ca15359f4e71a5bbd9165897b4d54e category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Prepare for proper error handling in add_disk.
Signed-off-by: Luis Chamberlain mcgrof@kernel.org [hch: split from a larger patch] Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Link: https://lore.kernel.org/r/20210818144542.19305-8-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/blk-integrity.c | 12 +++++++----- block/blk.h | 5 +++-- 2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 9e83159f5a52..16d5d5338392 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -438,13 +438,15 @@ void blk_integrity_unregister(struct gendisk *disk) } EXPORT_SYMBOL(blk_integrity_unregister);
-void blk_integrity_add(struct gendisk *disk) +int blk_integrity_add(struct gendisk *disk) { - if (kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype, - &disk_to_dev(disk)->kobj, "%s", "integrity")) - return; + int ret;
- kobject_uevent(&disk->integrity_kobj, KOBJ_ADD); + ret = kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype, + &disk_to_dev(disk)->kobj, "%s", "integrity"); + if (!ret) + kobject_uevent(&disk->integrity_kobj, KOBJ_ADD); + return ret; }
void blk_integrity_del(struct gendisk *disk) diff --git a/block/blk.h b/block/blk.h index 7b3693149183..4bbcc971d4f7 100644 --- a/block/blk.h +++ b/block/blk.h @@ -134,7 +134,7 @@ static inline bool integrity_req_gap_front_merge(struct request *req, bip_next->bip_vec[0].bv_offset); }
-void blk_integrity_add(struct gendisk *); +int blk_integrity_add(struct gendisk *disk); void blk_integrity_del(struct gendisk *); #else /* CONFIG_BLK_DEV_INTEGRITY */ static inline bool blk_integrity_merge_rq(struct request_queue *rq, @@ -168,8 +168,9 @@ static inline bool bio_integrity_endio(struct bio *bio) static inline void bio_integrity_free(struct bio *bio) { } -static inline void blk_integrity_add(struct gendisk *disk) +static inline int blk_integrity_add(struct gendisk *disk) { + return 0; } static inline void blk_integrity_del(struct gendisk *disk) {
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.15-rc1 commit 92e7755ebc69233e25a2d1b760aeff536dc4016b category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Prepare for proper error handling in add_disk.
Signed-off-by: Luis Chamberlain mcgrof@kernel.org [hch: split from a larger patch] Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Link: https://lore.kernel.org/r/20210818144542.19305-9-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index d2153303ae05..ef13a9689dd7 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -40,7 +40,7 @@ static DEFINE_IDR(ext_devt_idr);
static void disk_check_events(struct disk_events *ev, unsigned int *clearing_ptr); -static void disk_alloc_events(struct gendisk *disk); +static int disk_alloc_events(struct gendisk *disk); static void disk_add_events(struct gendisk *disk); static void disk_del_events(struct gendisk *disk); static void disk_release_events(struct gendisk *disk); @@ -2396,17 +2396,17 @@ module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops, /* * disk_{alloc|add|del|release}_events - initialize and destroy disk_events. */ -static void disk_alloc_events(struct gendisk *disk) +static int disk_alloc_events(struct gendisk *disk) { struct disk_events *ev;
if (!disk->fops->check_events || !disk->events) - return; + return 0;
ev = kzalloc(sizeof(*ev), GFP_KERNEL); if (!ev) { pr_warn("%s: failed to initialize events\n", disk->disk_name); - return; + return -ENOMEM; }
INIT_LIST_HEAD(&ev->node); @@ -2418,6 +2418,7 @@ static void disk_alloc_events(struct gendisk *disk) INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
disk->ev = ev; + return 0; }
static void disk_add_events(struct gendisk *disk)
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit 2bc8cda5ea4b42ff78be1b11011092d57b424d37 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Add the events attributes to the disk_attrs array, which ensures they are added by the driver core when the device is created rather than adding them after the device has been added, which is racy versus uevents and requires more boilerplate code.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Link: https://lore.kernel.org/r/20210624073843.251178-3-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index ef13a9689dd7..261a71360b5c 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -44,6 +44,9 @@ static int disk_alloc_events(struct gendisk *disk); static void disk_add_events(struct gendisk *disk); static void disk_del_events(struct gendisk *disk); static void disk_release_events(struct gendisk *disk); +static struct device_attribute dev_attr_events; +static struct device_attribute dev_attr_events_async; +static struct device_attribute dev_attr_events_poll_msecs;
/* * Set disk capacity and notify if the size is not currently @@ -1513,6 +1516,9 @@ static struct attribute *disk_attrs[] = { &dev_attr_stat.attr, &dev_attr_inflight.attr, &dev_attr_badblocks.attr, + &dev_attr_events.attr, + &dev_attr_events_async.attr, + &dev_attr_events_poll_msecs.attr, #ifdef CONFIG_FAIL_MAKE_REQUEST &dev_attr_fail.attr, #endif @@ -2343,18 +2349,10 @@ static ssize_t disk_events_poll_msecs_store(struct device *dev, return count; }
-static const DEVICE_ATTR(events, 0444, disk_events_show, NULL); -static const DEVICE_ATTR(events_async, 0444, disk_events_async_show, NULL); -static const DEVICE_ATTR(events_poll_msecs, 0644, - disk_events_poll_msecs_show, - disk_events_poll_msecs_store); - -static const struct attribute *disk_events_attrs[] = { - &dev_attr_events.attr, - &dev_attr_events_async.attr, - &dev_attr_events_poll_msecs.attr, - NULL, -}; +static DEVICE_ATTR(events, 0444, disk_events_show, NULL); +static DEVICE_ATTR(events_async, 0444, disk_events_async_show, NULL); +static DEVICE_ATTR(events_poll_msecs, 0644, disk_events_poll_msecs_show, + disk_events_poll_msecs_store);
/* * The default polling interval can be specified by the kernel @@ -2423,11 +2421,6 @@ static int disk_alloc_events(struct gendisk *disk)
static void disk_add_events(struct gendisk *disk) { - /* FIXME: error handling */ - if (sysfs_create_files(&disk_to_dev(disk)->kobj, disk_events_attrs) < 0) - pr_warn("%s: failed to create sysfs files for events\n", - disk->disk_name); - if (!disk->ev) return;
@@ -2451,8 +2444,6 @@ static void disk_del_events(struct gendisk *disk) list_del_init(&disk->ev->node); mutex_unlock(&disk_events_mutex); } - - sysfs_remove_files(&disk_to_dev(disk)->kobj, disk_events_attrs); }
static void disk_release_events(struct gendisk *disk)
hulk inclusion category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
Modify the return value type of blk_register_region to prepare for adding error handling.
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 5 +++-- include/linux/genhd.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 261a71360b5c..11c6869005c6 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -649,12 +649,13 @@ static char *bdevt_str(dev_t devt, char *buf) * Register device numbers dev..(dev+range-1) * range must be nonzero * The hash chain is sorted on range, so that subranges can override. + * Add error handling. */ -void blk_register_region(dev_t devt, unsigned long range, struct module *module, +int blk_register_region(dev_t devt, unsigned long range, struct module *module, struct kobject *(*probe)(dev_t, int *, void *), int (*lock)(dev_t, void *), void *data) { - kobj_map(bdev_map, devt, range, module, probe, lock, data); + return kobj_map(bdev_map, devt, range, module, probe, lock, data); }
EXPORT_SYMBOL(blk_register_region); diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 959add98b686..61b5e9359152 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -361,7 +361,7 @@ extern struct gendisk *__alloc_disk_node(int minors, int node_id); extern struct kobject *get_disk_and_module(struct gendisk *disk); extern void put_disk(struct gendisk *disk); extern void put_disk_and_module(struct gendisk *disk); -extern void blk_register_region(dev_t devt, unsigned long range, +extern int blk_register_region(dev_t devt, unsigned long range, struct module *module, struct kobject *(*probe)(dev_t, int *, void *), int (*lock)(dev_t, void *),
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.15-rc1 commit 83cbce9574462c6b4eed6797bdaf18fae6859ab3 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Properly unwind on errors in device_add_disk. This is the initial work as drivers are not converted yet, which will follow in separate patches.
Signed-off-by: Luis Chamberlain mcgrof@kernel.org [hch: major rebase. All bugs are probably mine] Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Link: https://lore.kernel.org/r/20210818144542.19305-10-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflicts: block/genhd.c include/linux/genhd.h Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 95 +++++++++++++++++++++++++++++-------------- include/linux/genhd.h | 6 +-- 2 files changed, 67 insertions(+), 34 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 11c6869005c6..3a2c8be1b79a 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -768,10 +768,8 @@ static void disk_init_partition(struct gendisk *disk) * * This function registers the partitioning information in @disk * with the kernel. - * - * FIXME: error handling */ -static void __device_add_disk(struct device *parent, struct gendisk *disk, +static int __device_add_disk(struct device *parent, struct gendisk *disk, const struct attribute_group **groups, bool register_queue) { @@ -797,14 +795,14 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, !(disk->flags & (GENHD_FL_EXT_DEVT | GENHD_FL_HIDDEN)));
retval = blk_alloc_devt(&disk->part0, &devt); - if (retval) { - WARN_ON(1); - return; - } + if (retval) + return retval; disk->major = MAJOR(devt); disk->first_minor = MINOR(devt);
- disk_alloc_events(disk); + retval = disk_alloc_events(disk); + if (retval) + goto out_free_ext_minor;
if (disk->flags & GENHD_FL_HIDDEN) { /* @@ -815,15 +813,17 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, disk->flags |= GENHD_FL_NO_PART_SCAN; } else { struct backing_dev_info *bdi = disk->queue->backing_dev_info; - int ret;
/* Register BDI before referencing it from bdev */ ddev->devt = devt; - ret = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt)); - WARN_ON(ret); + retval = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt)); + if (retval) + goto out_disk_release_events; bdi_set_owner(bdi, ddev); - blk_register_region(disk_devt(disk), disk->minors, NULL, - exact_match, exact_lock, disk); + retval = blk_register_region(disk_devt(disk), disk->minors, + NULL, exact_match, exact_lock, disk); + if (retval) + goto out_unregister_bdi; }
/* delay uevents, until we scanned partition table */ @@ -835,15 +835,14 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, ddev->groups = groups; } dev_set_name(ddev, "%s", disk->disk_name); - if (device_add(ddev)) - return; + retval = device_add(ddev); + if (retval) + goto out_unregister_region; if (!sysfs_deprecated) { retval = sysfs_create_link(block_depr, &ddev->kobj, - kobject_name(&ddev->kobj)); - if (retval) { - device_del(ddev); - return; - } + kobject_name(&ddev->kobj)); + if (retval) + goto out_device_del; }
/* @@ -853,23 +852,30 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, */ pm_runtime_set_memalloc_noio(ddev, true);
- blk_integrity_add(disk); + retval = blk_integrity_add(disk); + if (retval) + goto out_del_block_link;
disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); + if (!disk->part0.holder_dir) + goto out_del_integrity; disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); + if (!disk->slave_dir) + goto out_put_holder_dir;
if (!(disk->flags & GENHD_FL_HIDDEN)) { - if (disk->queue->backing_dev_info->dev) { - retval = sysfs_create_link(&ddev->kobj, - &disk->queue->backing_dev_info->dev->kobj, - "bdi"); - WARN_ON(retval); - } + retval = sysfs_create_link(&ddev->kobj, + &disk->queue->backing_dev_info->dev->kobj, "bdi"); + if (retval) + goto out_put_slave_dir; }
- if (register_queue) - blk_register_queue(disk); + if (register_queue) { + retval = blk_register_queue(disk); + if (retval) + goto out_del_bdi_sysfs_link; + }
/* * Take an extra ref on queue which will be put on disk_release() @@ -889,13 +895,40 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, */ disk->flags |= GENHD_FL_UP; disk_init_partition(disk); + return 0; + +out_del_bdi_sysfs_link: + if (!(disk->flags & GENHD_FL_HIDDEN)) + sysfs_remove_link(&ddev->kobj, "bdi"); +out_put_slave_dir: + kobject_put(disk->slave_dir); +out_put_holder_dir: + kobject_put(disk->part0.holder_dir); +out_del_integrity: + blk_integrity_del(disk); +out_del_block_link: + if (!sysfs_deprecated) + sysfs_remove_link(block_depr, kobject_name(&ddev->kobj)); +out_device_del: + device_del(ddev); +out_unregister_region: + if (!(disk->flags & GENHD_FL_HIDDEN)) + blk_unregister_region(disk_devt(disk), disk->minors); +out_unregister_bdi: + if (!(disk->flags & GENHD_FL_HIDDEN)) + bdi_unregister(disk->queue->backing_dev_info); +out_disk_release_events: + disk_release_events(disk); +out_free_ext_minor: + blk_free_devt(devt); + return WARN_ON_ONCE(retval); /* keep until all callers handle errors */ }
-void device_add_disk(struct device *parent, struct gendisk *disk, +int device_add_disk(struct device *parent, struct gendisk *disk, const struct attribute_group **groups)
{ - __device_add_disk(parent, disk, groups, true); + return __device_add_disk(parent, disk, groups, true); } EXPORT_SYMBOL(device_add_disk);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 61b5e9359152..bd44031cf35b 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -305,11 +305,11 @@ extern bool disk_has_partitions(struct gendisk *disk);
/* block/genhd.c */ extern unsigned int part_in_flight(struct hd_struct *part); -extern void device_add_disk(struct device *parent, struct gendisk *disk, +extern int device_add_disk(struct device *parent, struct gendisk *disk, const struct attribute_group **groups); -static inline void add_disk(struct gendisk *disk) +static inline int add_disk(struct gendisk *disk) { - device_add_disk(NULL, disk, NULL); + return device_add_disk(NULL, disk, NULL); } extern void device_add_disk_no_queue_reg(struct device *parent, struct gendisk *disk); static inline void add_disk_no_queue_reg(struct gendisk *disk)
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit fe7d064fa3faec5d8157029fb8720b4fddc9e1e8 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Commit 83cbce957446 ("block: add error handling for device_add_disk / add_disk") added error handling to device_add_disk(), however the goto label for the kobject_create_and_add() failure did not set the return value correctly, and so we can end up in a situation where kobject_create_and_add() fails but we report success.
Fixes: 83cbce957446 ("block: add error handling for device_add_disk / add_disk") Reported-by: kernel test robot lkp@intel.com Reported-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Luis Chamberlain mcgrof@kernel.org Reviewed-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/20211103164023.1384821-1-mcgrof@kernel.org [axboe: fold in followup fix from Wu Bo wubo40@huawei.com] Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 3a2c8be1b79a..96db5ae191d6 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -858,11 +858,15 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk,
disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); - if (!disk->part0.holder_dir) + if (!disk->part0.holder_dir) { + retval = -ENOMEM; goto out_del_integrity; + } disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); - if (!disk->slave_dir) + if (!disk->slave_dir) { + retval = -ENOMEM; goto out_put_holder_dir; + }
if (!(disk->flags & GENHD_FL_HIDDEN)) { retval = sysfs_create_link(&ddev->kobj,
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.17-rc1 commit 99d8690aae4b2f0d1d90075de355ac087f820a66 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
One device_add is called disk->ev will be freed by disk_release, so we should free it twice. Fix this by allocating disk->ev after device_add so that the extra local unwinding can be removed entirely.
Based on an earlier patch from Tetsuo Handa.
Reported-by: syzbot syzbot+28a66a9fbc621c939000@syzkaller.appspotmail.com Tested-by: syzbot syzbot+28a66a9fbc621c939000@syzkaller.appspotmail.com Fixes: 83cbce9574462c6b ("block: add error handling for device_add_disk / add_disk") Signed-off-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/20211221161851.788424-1-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 96db5ae191d6..878d521523a2 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -800,10 +800,6 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, disk->major = MAJOR(devt); disk->first_minor = MINOR(devt);
- retval = disk_alloc_events(disk); - if (retval) - goto out_free_ext_minor; - if (disk->flags & GENHD_FL_HIDDEN) { /* * Don't let hidden disks show up in /proc/partitions, @@ -818,7 +814,7 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, ddev->devt = devt; retval = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt)); if (retval) - goto out_disk_release_events; + goto out_free_ext_minor; bdi_set_owner(bdi, ddev); retval = blk_register_region(disk_devt(disk), disk->minors, NULL, exact_match, exact_lock, disk); @@ -838,6 +834,9 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, retval = device_add(ddev); if (retval) goto out_unregister_region; + retval = disk_alloc_events(disk); + if (retval) + goto out_device_del; if (!sysfs_deprecated) { retval = sysfs_create_link(block_depr, &ddev->kobj, kobject_name(&ddev->kobj)); @@ -921,8 +920,6 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, out_unregister_bdi: if (!(disk->flags & GENHD_FL_HIDDEN)) bdi_unregister(disk->queue->backing_dev_info); -out_disk_release_events: - disk_release_events(disk); out_free_ext_minor: blk_free_devt(devt); return WARN_ON_ONCE(retval); /* keep until all callers handle errors */
hulk inclusion category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
Fix the kabi change caused by changing the return value of device_add_disk.
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 21 +++++++++++++++++++-- include/linux/genhd.h | 19 ++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 878d521523a2..3c3ba1e7a62f 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -925,20 +925,37 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, return WARN_ON_ONCE(retval); /* keep until all callers handle errors */ }
-int device_add_disk(struct device *parent, struct gendisk *disk, +void device_add_disk(struct device *parent, struct gendisk *disk, const struct attribute_group **groups)
{ - return __device_add_disk(parent, disk, groups, true); + __device_add_disk(parent, disk, groups, true); } EXPORT_SYMBOL(device_add_disk);
+ +int __must_check device_add_disk_safe(struct device *parent, + struct gendisk *disk, + const struct attribute_group **groups) + +{ + return __device_add_disk(parent, disk, groups, true); +} +EXPORT_SYMBOL(device_add_disk_safe); + void device_add_disk_no_queue_reg(struct device *parent, struct gendisk *disk) { __device_add_disk(parent, disk, NULL, false); } EXPORT_SYMBOL(device_add_disk_no_queue_reg);
+int __must_check device_add_disk_no_queue_reg_safe(struct device *parent, + struct gendisk *disk) +{ + return __device_add_disk(parent, disk, NULL, false); +} +EXPORT_SYMBOL(device_add_disk_no_queue_reg_safe); + static void invalidate_partition(struct gendisk *disk, int partno) { struct block_device *bdev; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index bd44031cf35b..92396234e96f 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -305,17 +305,30 @@ extern bool disk_has_partitions(struct gendisk *disk);
/* block/genhd.c */ extern unsigned int part_in_flight(struct hd_struct *part); -extern int device_add_disk(struct device *parent, struct gendisk *disk, +extern void device_add_disk(struct device *parent, struct gendisk *disk, const struct attribute_group **groups); -static inline int add_disk(struct gendisk *disk) +extern int __must_check device_add_disk_safe(struct device *parent, + struct gendisk *disk, + const struct attribute_group **groups); +static inline void add_disk(struct gendisk *disk) { - return device_add_disk(NULL, disk, NULL); + device_add_disk(NULL, disk, NULL); } extern void device_add_disk_no_queue_reg(struct device *parent, struct gendisk *disk); +extern int __must_check device_add_disk_no_queue_reg_safe(struct device *parent, + struct gendisk *disk); static inline void add_disk_no_queue_reg(struct gendisk *disk) { device_add_disk_no_queue_reg(NULL, disk); } +static inline int __must_check add_disk_no_queue_reg_safe(struct gendisk *disk) +{ + return device_add_disk_no_queue_reg_safe(NULL, disk); +} +static inline int __must_check add_disk_safe(struct gendisk *disk) +{ + return device_add_disk_safe(NULL, disk, NULL); +}
extern void del_gendisk(struct gendisk *gp); extern struct gendisk *get_gendisk(dev_t dev, int *partno);
hulk inclusion category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
Fix kabi change caused by blk_register_region change return value.
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 8 ++++---- include/linux/genhd.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 3c3ba1e7a62f..ea4899e92788 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -651,11 +651,11 @@ static char *bdevt_str(dev_t devt, char *buf) * The hash chain is sorted on range, so that subranges can override. * Add error handling. */ -int blk_register_region(dev_t devt, unsigned long range, struct module *module, +void blk_register_region(dev_t devt, unsigned long range, struct module *module, struct kobject *(*probe)(dev_t, int *, void *), int (*lock)(dev_t, void *), void *data) { - return kobj_map(bdev_map, devt, range, module, probe, lock, data); + kobj_map(bdev_map, devt, range, module, probe, lock, data); }
EXPORT_SYMBOL(blk_register_region); @@ -816,8 +816,8 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, if (retval) goto out_free_ext_minor; bdi_set_owner(bdi, ddev); - retval = blk_register_region(disk_devt(disk), disk->minors, - NULL, exact_match, exact_lock, disk); + retval = kobj_map(bdev_map, disk_devt(disk), disk->minors, NULL, + exact_match, exact_lock, disk); if (retval) goto out_unregister_bdi; } diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 92396234e96f..b0b9c4fa6311 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -374,7 +374,7 @@ extern struct gendisk *__alloc_disk_node(int minors, int node_id); extern struct kobject *get_disk_and_module(struct gendisk *disk); extern void put_disk(struct gendisk *disk); extern void put_disk_and_module(struct gendisk *disk); -extern int blk_register_region(dev_t devt, unsigned long range, +extern void blk_register_region(dev_t devt, unsigned long range, struct module *module, struct kobject *(*probe)(dev_t, int *, void *), int (*lock)(dev_t, void *),
From: Yu Kuai yukuai3@huawei.com
mainline inclusion from mainline-v6.1-rc3 commit 02341a08c9dec5a88527981b0bdf0fb6f7499cbf category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
The default elevator is allocated in the beginning of device_add_disk(), however, it's not freed in the following error path.
Fixes: 50e34d78815e ("block: disable the elevator int del_gendisk") Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Jason Yan yanaijie@huawei.com Link: https://lore.kernel.org/r/20221022021615.2756171-1-yukuai1@huaweicloud.com Signed-off-by: Jens Axboe axboe@kernel.dk confilic: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index ea4899e92788..bfbc61be3ddd 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -786,6 +786,7 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, if (register_queue) elevator_init_mq(disk->queue);
+ retval = -EINVAL; /* minors == 0 indicates to use ext devt from part0 and should * be accompanied with EXT_DEVT flag. Make sure all * parameters make sense. @@ -796,7 +797,7 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk,
retval = blk_alloc_devt(&disk->part0, &devt); if (retval) - return retval; + goto out_exit_elevator; disk->major = MAJOR(devt); disk->first_minor = MINOR(devt);
@@ -922,7 +923,14 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, bdi_unregister(disk->queue->backing_dev_info); out_free_ext_minor: blk_free_devt(devt); - return WARN_ON_ONCE(retval); /* keep until all callers handle errors */ +out_exit_elevator: + if (register_queue && disk->queue->elevator) { + mutex_lock(&disk->queue->sysfs_lock); + elevator_exit(disk->queue, disk->queue->elevator); + mutex_unlock(&disk->queue->sysfs_lock); + } + WARN_ON_ONCE(retval); /* keep until all callers handle errors */ + return retval; }
void device_add_disk(struct device *parent, struct gendisk *disk,
From: Tetsuo Handa penguin-kernel@i-love.sakura.ne.jp
mainline inclusion from mainline-v5.17-rc1 commit e338924bd05d6e71574bc13e310c89e10e49a8a5 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
ioctl(fd, LOOP_CTL_ADD, 1048576) causes
sysfs: cannot create duplicate filename '/dev/block/7:0'
message because such request is treated as if ioctl(fd, LOOP_CTL_ADD, 0) due to MINORMASK == 1048575. Verify that all minor numbers for that device fit in the minor range.
Reported-by: wangyangbo wangyangbo@uniontech.com Signed-off-by: Tetsuo Handa penguin-kernel@I-love.SAKURA.ne.jp Reviewed-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/b1b19379-23ee-5379-0eb5-94bf5f79f1b4@i-love.sakura... Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/block/genhd.c b/block/genhd.c index bfbc61be3ddd..1f2940cbb68e 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -795,6 +795,9 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, WARN_ON(!disk->minors && !(disk->flags & (GENHD_FL_EXT_DEVT | GENHD_FL_HIDDEN)));
+ if (disk->minors != 0 && + disk->first_minor + disk->minors > MINORMASK + 1) + goto out_exit_elevator; retval = blk_alloc_devt(&disk->part0, &devt); if (retval) goto out_exit_elevator;
From: Zhong Jinghua zhongjinghua@huaweicloud.com
hulk inclusion category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
When adding a disk, first obtain the reference count of the request_queue, and release the reference count when error handling, which will make it easier for the driver to add error handling.
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 1f2940cbb68e..d03588201416 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -777,6 +777,11 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, dev_t devt; int retval;
+ /* + * Take an extra ref on queue which will be put on disk_release() + * so that it sticks around as long as @disk is there. + */ + WARN_ON_ONCE(!blk_get_queue(disk->queue)); /* * The disk queue should now be all set with enough information about * the device for the elevator code to pick an adequate default @@ -884,12 +889,6 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, goto out_del_bdi_sysfs_link; }
- /* - * Take an extra ref on queue which will be put on disk_release() - * so that it sticks around as long as @disk is there. - */ - WARN_ON_ONCE(!blk_get_queue(disk->queue)); - disk_add_events(disk);
/* Make sure the first partition scan will be proceed */
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v6.2-rc1 commit d90db3b1c8676bc88b4309c5a571333de2263b8e category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Zero out the pointer to ->slave_dir so that the holder code doesn't incorrectly treat the object as alive when add_disk failed or after del_gendisk was called.
Fixes: 89f871af1b26 ("dm: delay registering the gendisk") Reported-by: Yu Kuai yukuai3@huawei.com Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Mike Snitzer snitzer@kernel.org Link: https://lore.kernel.org/r/20221115141054.1051801-2-yukuai1@huaweicloud.com Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/block/genhd.c b/block/genhd.c index d03588201416..ff61a19b2260 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -908,6 +908,7 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, sysfs_remove_link(&ddev->kobj, "bdi"); out_put_slave_dir: kobject_put(disk->slave_dir); + disk->slave_dir = NULL; out_put_holder_dir: kobject_put(disk->part0.holder_dir); out_del_integrity: @@ -1059,6 +1060,7 @@ void del_gendisk(struct gendisk *disk)
kobject_put(disk->part0.holder_dir); kobject_put(disk->slave_dir); + disk->slave_dir = NULL;
part_stat_set_all(&disk->part0, 0); disk->part0.stamp = 0;
hulk inclusion category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
Checks added in patch: 51901d95c47e("block: check minor range in device_add_disk()") ignore the problem of first_minore < 0 and disk->minors < 0.
Fix it by adding first_minore < 0 and disk->minors < 0 check.
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index ff61a19b2260..aa8e22f026a5 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -800,8 +800,9 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, WARN_ON(!disk->minors && !(disk->flags & (GENHD_FL_EXT_DEVT | GENHD_FL_HIDDEN)));
- if (disk->minors != 0 && - disk->first_minor + disk->minors > MINORMASK + 1) + if (disk->minors != 0 && (disk->first_minor > MINORMASK || + disk->minors > (1U << MINORBITS) || + disk->first_minor + disk->minors > (1U << MINORBITS))) goto out_exit_elevator; retval = blk_alloc_devt(&disk->part0, &devt); if (retval)
hulk inclusion category: bugfix bugzilla: 188217, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
In del_gendisk, memalloc_noio is set to false, so it would be better to do the same thing in the error path.
Fixes: c6b84a94528e ("block: add error handling for device_add_disk / add_disk") Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/block/genhd.c b/block/genhd.c index aa8e22f026a5..e5df4d63ecd2 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -917,6 +917,11 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, out_del_block_link: if (!sysfs_deprecated) sysfs_remove_link(block_depr, kobject_name(&ddev->kobj)); + /* + * The error path needs to set memalloc_noio to false + * consistent with del_gendisk. + */ + pm_runtime_set_memalloc_noio(ddev, false); out_device_del: device_del(ddev); out_unregister_region:
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit f525464a8000f092c20b00eead3eaa9d849c599e category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Add two new APIs to allocate and free a gendisk including the request_queue for use with BIO based drivers. This is to avoid boilerplate code in drivers.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Reviewed-by: Ulf Hansson ulf.hansson@linaro.org Link: https://lore.kernel.org/r/20210521055116.1053587-6-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflicts: block/genhd.c include/linux/genhd.h Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 35 +++++++++++++++++++++++++++++++++++ include/linux/genhd.h | 22 ++++++++++++++++++++++ 2 files changed, 57 insertions(+)
diff --git a/block/genhd.c b/block/genhd.c index e5df4d63ecd2..87f622899d70 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1927,6 +1927,25 @@ struct gendisk *__alloc_disk_node(int minors, int node_id) } EXPORT_SYMBOL(__alloc_disk_node);
+struct gendisk *__blk_alloc_disk(int node) +{ + struct request_queue *q; + struct gendisk *disk; + + q = blk_alloc_queue(node); + if (!q) + return NULL; + + disk = __alloc_disk_node(0, node); + if (!disk) { + blk_cleanup_queue(q); + return NULL; + } + disk->queue = q; + return disk; +} +EXPORT_SYMBOL(__blk_alloc_disk); + /** * get_disk_and_module - increments the gendisk and gendisk fops module refcount * @disk: the struct gendisk to increment the refcount for @@ -1973,6 +1992,22 @@ void put_disk(struct gendisk *disk) } EXPORT_SYMBOL(put_disk);
+/** + * blk_cleanup_disk - shutdown a gendisk allocated by blk_alloc_disk + * @disk: gendisk to shutdown + * + * Mark the queue hanging off @disk DYING, drain all pending requests, then mark + * the queue DEAD, destroy and put it and the gendisk structure. + * + * Context: can sleep + */ +void blk_cleanup_disk(struct gendisk *disk) +{ + blk_cleanup_queue(disk->queue); + put_disk(disk); +} +EXPORT_SYMBOL(blk_cleanup_disk); + /** * put_disk_and_module - decrements the module and gendisk refcount * @disk: the struct gendisk to decrement the refcount for diff --git a/include/linux/genhd.h b/include/linux/genhd.h index b0b9c4fa6311..dd58608f0ce7 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -401,6 +401,28 @@ extern void blk_delete_region(dev_t devt, unsigned long range,
#define alloc_disk(minors) alloc_disk_node(minors, NUMA_NO_NODE)
+/** + * blk_alloc_disk - allocate a gendisk structure + * @node_id: numa node to allocate on + * + * Allocate and pre-initialize a gendisk structure for use with BIO based + * drivers. + * + * Context: can sleep + */ +#define blk_alloc_disk(node_id) \ +({ \ + struct gendisk *__disk = __blk_alloc_disk(node_id); \ + static struct lock_class_key __key; \ + \ + if (__disk) \ + lockdep_init_map(&__disk->lockdep_map, \ + "(bio completion)", &__key, 0); \ + __disk; \ +}) +struct gendisk *__blk_alloc_disk(int node); +void blk_cleanup_disk(struct gendisk *disk); + int register_blkdev(unsigned int major, const char *name); void unregister_blkdev(unsigned int major, const char *name);
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit b461dfc49eb6fbabc60b9dad476e787ada56b7b4 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Add a new API to allocate a gendisk including the request_queue for use with blk-mq based drivers. This is to avoid boilerplate code in drivers.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Chaitanya Kulkarni chaitanya.kulkarni@wdc.com Link: https://lore.kernel.org/r/20210602065345.355274-4-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: include/linux/blk-mq.h Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/blk-mq.c | 19 +++++++++++++++++++ include/linux/blk-mq.h | 12 ++++++++++++ 2 files changed, 31 insertions(+)
diff --git a/block/blk-mq.c b/block/blk-mq.c index 1d1200afb771..9e3934259933 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -3310,6 +3310,25 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) } EXPORT_SYMBOL(blk_mq_init_queue);
+struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata) +{ + struct request_queue *q; + struct gendisk *disk; + + q = blk_mq_init_queue_data(set, queuedata); + if (IS_ERR(q)) + return ERR_CAST(q); + + disk = __alloc_disk_node(0, set->numa_node); + if (!disk) { + blk_cleanup_queue(q); + return ERR_PTR(-ENOMEM); + } + disk->queue = q; + return disk; +} +EXPORT_SYMBOL(__blk_mq_alloc_disk); + /* * Helper for setting up a queue with mq ops, given queue depth, and * the passed in mq ops flags. diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 2eca0b76b3e9..74a57d8aa76d 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -464,6 +464,18 @@ enum {
#define BLK_MQ_NO_HCTX_IDX (-1U)
+#define blk_mq_alloc_disk(set, queuedata) \ +({ \ + static struct lock_class_key __key; \ + struct gendisk *__disk = __blk_mq_alloc_disk(set, queuedata); \ + \ + if (__disk) \ + lockdep_init_map(&__disk->lockdep_map, \ + "(bio completion)", &__key, 0); \ + __disk; \ +}) +struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, + void *queuedata); struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *); struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set, void *queuedata);
From: Dan Carpenter dan.carpenter@oracle.com
mainline inclusion from mainline-v5.14-rc1 commit 52d7e288444906aa5c99888e80a9cc1a1423ed92 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
The __blk_mq_alloc_disk() function doesn't return NULLs it returns error pointers.
Fixes: b461dfc49eb6 ("blk-mq: add the blk_mq_alloc_disk APIs") Signed-off-by: Dan Carpenter dan.carpenter@oracle.com Reviewed-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/YMyjci35WBqrtqG+@mwanda Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- include/linux/blk-mq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 74a57d8aa76d..289ec99e376a 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -469,7 +469,7 @@ enum { static struct lock_class_key __key; \ struct gendisk *__disk = __blk_mq_alloc_disk(set, queuedata); \ \ - if (__disk) \ + if (!IS_ERR(__disk)) \ lockdep_init_map(&__disk->lockdep_map, \ "(bio completion)", &__key, 0); \ __disk; \
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit 1c99502fae359182a93a1c9cf7406edc0e28b6b0 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Use blk_mq_alloc_disk and blk_cleanup_disk to simplify the gendisk and request_queue allocation.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Chaitanya Kulkarni chaitanya.kulkarni@wdc.com Link: https://lore.kernel.org/r/20210602065345.355274-19-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: drivers/block/loop.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/block/loop.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 0bb2e46cefab..ac030b4436ee 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -2129,12 +2129,12 @@ static int loop_add(struct loop_device **l, int i) if (err) goto out_free_idr;
- lo->lo_queue = blk_mq_init_queue(&lo->tag_set); - if (IS_ERR(lo->lo_queue)) { - err = PTR_ERR(lo->lo_queue); + disk = lo->lo_disk = blk_mq_alloc_disk(&lo->tag_set, lo); + if (IS_ERR(disk)) { + err = PTR_ERR(disk); goto out_cleanup_tags; } - lo->lo_queue->queuedata = lo; + lo->lo_queue = lo->lo_disk->queue;
blk_queue_max_hw_sectors(lo->lo_queue, BLK_DEF_MAX_SECTORS);
@@ -2146,11 +2146,6 @@ static int loop_add(struct loop_device **l, int i) */ blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue);
- err = -ENOMEM; - disk = lo->lo_disk = alloc_disk(1 << part_shift); - if (!disk) - goto out_free_queue; - /* * Disable partition scanning by default. The in-kernel partition * scanning can be requested individually per-device during its @@ -2177,6 +2172,7 @@ static int loop_add(struct loop_device **l, int i) spin_lock_init(&lo->lo_lock); disk->major = LOOP_MAJOR; disk->first_minor = i << part_shift; + disk->minors = 1 << part_shift; disk->fops = &lo_fops; disk->private_data = lo; disk->queue = lo->lo_queue; @@ -2185,8 +2181,6 @@ static int loop_add(struct loop_device **l, int i) *l = lo; return lo->lo_number;
-out_free_queue: - blk_cleanup_queue(lo->lo_queue); out_cleanup_tags: blk_mq_free_tag_set(&lo->tag_set); out_free_idr: @@ -2200,9 +2194,8 @@ static int loop_add(struct loop_device **l, int i) static void loop_remove(struct loop_device *lo) { del_gendisk(lo->lo_disk); - blk_cleanup_queue(lo->lo_queue); blk_mq_free_tag_set(&lo->tag_set); - put_disk(lo->lo_disk); + blk_cleanup_disk(lo->lo_disk); kfree(lo); }
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit 6a03cd9843fa4dcf827dc3ad60fa9b4217f3057c category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We must release the queue before freeing the tagset.
Fixes: 1c99502fae35 ("loop: use blk_mq_alloc_disk and blk_cleanup_disk") Reported-by: Bruno Goncalves bgoncalv@redhat.com Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: drivers/block/loop.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/block/loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ac030b4436ee..066473c3556c 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -2194,8 +2194,8 @@ static int loop_add(struct loop_device **l, int i) static void loop_remove(struct loop_device *lo) { del_gendisk(lo->lo_disk); - blk_mq_free_tag_set(&lo->tag_set); blk_cleanup_disk(lo->lo_disk); + blk_mq_free_tag_set(&lo->tag_set); kfree(lo); }
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit 905705f083a936e49d5259e0bb539c53d5e0a9be category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling.
Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Signed-off-by: Luis Chamberlain mcgrof@kernel.org Signed-off-by: Jens Axboe axboe@kernel.dk confilct: drivers/block/loop.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/block/loop.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 066473c3556c..c64b22ce2bec 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -2177,10 +2177,15 @@ static int loop_add(struct loop_device **l, int i) disk->private_data = lo; disk->queue = lo->lo_queue; sprintf(disk->disk_name, "loop%d", i); - add_disk(disk); + err = add_disk_safe(disk); + if (err) + goto out_cleanup_disk; + *l = lo; return lo->lo_number;
+out_cleanup_disk: + blk_cleanup_disk(disk); out_cleanup_tags: blk_mq_free_tag_set(&lo->tag_set); out_free_idr:
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit 4af5f2e0301311f88c420fcfc5f3c8611ade20ac category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Use blk_mq_alloc_disk and blk_cleanup_disk to simplify the gendisk and request_queue allocation.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Chaitanya Kulkarni chaitanya.kulkarni@wdc.com Link: https://lore.kernel.org/r/20210602065345.355274-20-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/block/nbd.c | 53 ++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 32 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index fa08f380f5be..fada869a54c9 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -226,15 +226,11 @@ static const struct device_attribute pid_attr = { static void nbd_dev_remove(struct nbd_device *nbd) { struct gendisk *disk = nbd->disk; - struct request_queue *q;
if (disk) { - q = disk->queue; del_gendisk(disk); - blk_cleanup_queue(q); blk_mq_free_tag_set(&nbd->tag_set); - disk->private_data = NULL; - put_disk(disk); + blk_cleanup_disk(disk); }
/* @@ -1810,15 +1806,24 @@ static int nbd_dev_add(int index) { struct nbd_device *nbd; struct gendisk *disk; - struct request_queue *q; int err = -ENOMEM;
nbd = kzalloc(sizeof(struct nbd_device), GFP_KERNEL); if (!nbd) goto out;
- disk = alloc_disk(1 << part_shift); - if (!disk) + nbd->tag_set.ops = &nbd_mq_ops; + nbd->tag_set.nr_hw_queues = 1; + nbd->tag_set.queue_depth = 128; + nbd->tag_set.numa_node = NUMA_NO_NODE; + nbd->tag_set.cmd_size = sizeof(struct nbd_cmd); + nbd->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | + BLK_MQ_F_BLOCKING; + nbd->tag_set.driver_data = nbd; + nbd->destroy_complete = NULL; + + err = blk_mq_alloc_tag_set(&nbd->tag_set); + if (err) goto out_free_nbd;
if (index >= 0) { @@ -1832,30 +1837,15 @@ static int nbd_dev_add(int index) index = err; } if (err < 0) - goto out_free_disk; - + goto out_free_tags; nbd->index = index; - nbd->disk = disk; - nbd->tag_set.ops = &nbd_mq_ops; - nbd->tag_set.nr_hw_queues = 1; - nbd->tag_set.queue_depth = 128; - nbd->tag_set.numa_node = NUMA_NO_NODE; - nbd->tag_set.cmd_size = sizeof(struct nbd_cmd); - nbd->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | - BLK_MQ_F_BLOCKING; - nbd->tag_set.driver_data = nbd; - nbd->destroy_complete = NULL;
- err = blk_mq_alloc_tag_set(&nbd->tag_set); - if (err) + disk = blk_mq_alloc_disk(&nbd->tag_set, NULL); + if (IS_ERR(disk)) { + err = PTR_ERR(disk); goto out_free_idr; - - q = blk_mq_init_queue(&nbd->tag_set); - if (IS_ERR(q)) { - err = PTR_ERR(q); - goto out_free_tags; } - disk->queue = q; + nbd->disk = disk;
/* * Tell the block layer that we are not a rotational device @@ -1886,6 +1876,7 @@ static int nbd_dev_add(int index) goto out_free_idr; }
+ disk->minors = 1 << part_shift; disk->fops = &nbd_fops; disk->private_data = nbd; sprintf(disk->disk_name, "nbd%d", index); @@ -1893,12 +1884,10 @@ static int nbd_dev_add(int index) nbd_total_devices++; return index;
-out_free_tags: - blk_mq_free_tag_set(&nbd->tag_set); out_free_idr: idr_remove(&nbd_index_idr, index); -out_free_disk: - put_disk(disk); +out_free_tags: + blk_mq_free_tag_set(&nbd->tag_set); out_free_nbd: kfree(nbd); out:
From: Wang Qing wangqing@vivo.com
mainline inclusion from mainline-v5.14-rc1 commit 16ad3db3b24cd9f70aa24e93cef0d4a83dece7ac category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We must release the queue before freeing the tagset.
Fixes: 4af5f2e03013 ("nbd: use blk_mq_alloc_disk and blk_cleanup_disk") Reported-and-tested-by: syzbot+9ca43ff47167c0ee3466@syzkaller.appspotmail.com Signed-off-by: Wang Qing wangqing@vivo.com Signed-off-by: Guoqing Jiang jiangguoqing@kylinos.cn Reviewed-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/20210706040016.1360412-1-guoqing.jiang@linux.dev Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index fada869a54c9..88374312fe8b 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -229,8 +229,8 @@ static void nbd_dev_remove(struct nbd_device *nbd)
if (disk) { del_gendisk(disk); - blk_mq_free_tag_set(&nbd->tag_set); blk_cleanup_disk(disk); + blk_mq_free_tag_set(&nbd->tag_set); }
/*
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit e1654f413fe08ffbc3292d8d2b8958b2cc5cb5e8 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling.
Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Signed-off-by: Luis Chamberlain mcgrof@kernel.org Signed-off-by: Jens Axboe axboe@kernel.dk conflict: drivers/block/nbd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/block/nbd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 88374312fe8b..70552d6f2810 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1880,10 +1880,14 @@ static int nbd_dev_add(int index) disk->fops = &nbd_fops; disk->private_data = nbd; sprintf(disk->disk_name, "nbd%d", index); - add_disk(disk); + err = add_disk_safe(disk); + if (err) + goto out_err_disk; nbd_total_devices++; return index;
+out_err_disk: + blk_cleanup_disk(disk); out_free_idr: idr_remove(&nbd_index_idr, index); out_free_tags:
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit 958229a7c55f219b1cff99f939dabbc1b6ba7161 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Add a flag to indicate that __device_add_disk did grab a queue reference so that disk_release only drops it if we actually had it. This sort out one of the major pitfals with partially initialized gendisk that a lot of drivers did get wrong or still do.
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-5-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflicts: block/genhd.c include/linux/genhd.h Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- block/genhd.c | 7 +++++-- include/linux/genhd.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c index 87f622899d70..1f358495e218 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -781,7 +781,10 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, * Take an extra ref on queue which will be put on disk_release() * so that it sticks around as long as @disk is there. */ - WARN_ON_ONCE(!blk_get_queue(disk->queue)); + if (blk_get_queue(disk->queue)) + set_bit(GD_QUEUE_REF, &disk->state); + else + WARN_ON_ONCE(1); /* * The disk queue should now be all set with enough information about * the device for the elevator code to pick an adequate default @@ -1725,7 +1728,7 @@ static void disk_release(struct device *dev) kfree(disk->random); disk_replace_part_tbl(disk, NULL); hd_free_part(&disk->part0); - if (disk->queue) + if (test_bit(GD_QUEUE_REF, &disk->state) && disk->queue) blk_put_queue(disk->queue); kfree(disk); } diff --git a/include/linux/genhd.h b/include/linux/genhd.h index dd58608f0ce7..1d7d5aa73760 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -204,6 +204,7 @@ struct gendisk { int flags; unsigned long state; #define GD_NEED_PART_SCAN 0 +#define GD_QUEUE_REF 1 struct rw_semaphore lookup_sem; struct kobject *slave_dir;
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.15-rc1 commit 5f432cceb3e9de5223fa50d882c4a43cab39a3ee category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Switch to use the blk_mq_alloc_disk helper for allocating the request_queue and gendisk.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Keith Busch kbusch@kernel.org Reviewed-by: Sagi Grimberg sagi@grimberg.me Link: https://lore.kernel.org/r/20210816131910.615153-2-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: drivers/nvme/host/core.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/nvme/host/core.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 96eed00b1f4a..7a5faa6950d6 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3904,9 +3904,14 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, if (!ns) goto out_free_id;
- ns->queue = blk_mq_init_queue(ctrl->tagset); - if (IS_ERR(ns->queue)) + disk = blk_mq_alloc_disk(ctrl->tagset, ns); + if (IS_ERR(disk)) goto out_free_ns; + disk->fops = &nvme_fops; + disk->private_data = ns; + + ns->disk = disk; + ns->queue = disk->queue;
if (ctrl->opts && ctrl->opts->data_digest) blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, ns->queue); @@ -3915,34 +3920,25 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, if (ctrl->ops->flags & NVME_F_PCI_P2PDMA) blk_queue_flag_set(QUEUE_FLAG_PCI_P2PDMA, ns->queue);
- ns->queue->queuedata = ns; ns->ctrl = ctrl; kref_init(&ns->kref);
ret = nvme_init_ns_head(ns, nsid, ids, id->nmic & NVME_NS_NMIC_SHARED); if (ret) - goto out_free_queue; + goto out_cleanup_disk; nvme_set_disk_name(disk_name, ns, ctrl, &flags);
- disk = alloc_disk_node(0, node); - if (!disk) - goto out_unlink_ns; - - disk->fops = &nvme_fops; - disk->private_data = ns; - disk->queue = ns->queue; disk->flags = flags; memcpy(disk->disk_name, disk_name, DISK_NAME_LEN); - ns->disk = disk;
if (nvme_update_ns_info(ns, id)) - goto out_put_disk; + goto out_unlink_ns;
if ((ctrl->quirks & NVME_QUIRK_LIGHTNVM) && id->vs[0] == 0x1) { ret = nvme_nvm_register(ns, disk_name, node); if (ret) { dev_warn(ctrl->device, "LightNVM init failure\n"); - goto out_put_disk; + goto out_unlink_ns; } }
@@ -3958,10 +3954,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, kfree(id);
return; - out_put_disk: - /* prevent double queue cleanup */ - ns->disk->queue = NULL; - put_disk(ns->disk); + out_unlink_ns: mutex_lock(&ctrl->subsys->lock); list_del_rcu(&ns->siblings); @@ -3969,8 +3962,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, list_del_init(&ns->head->entry); mutex_unlock(&ctrl->subsys->lock); nvme_put_ns_head(ns->head); - out_free_queue: - blk_cleanup_queue(ns->queue); + out_cleanup_disk: + blk_cleanup_disk(disk); out_free_ns: kfree(ns); out_free_id:
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.15-rc1 commit ab3994f6efba95e0832dc9e68c088b2d7ae764b8 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling.
Signed-off-by: Luis Chamberlain mcgrof@kernel.org Reviewed-by: Hannes Reinecke hare@suse.de Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/nvme/host/core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 7a5faa6950d6..4e8777529c96 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3947,7 +3947,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, up_write(&ctrl->namespaces_rwsem); nvme_get_ctrl(ctrl);
- device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups); + if (device_add_disk_safe(ctrl->device, ns->disk, nvme_ns_id_attr_groups)) + goto out_cleanup_ns_from_list;
nvme_mpath_add_disk(ns, id); nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name); @@ -3955,6 +3956,11 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
return;
+ out_cleanup_ns_from_list: + nvme_put_ctrl(ctrl); + down_write(&ctrl->namespaces_rwsem); + list_del_init(&ns->list); + up_write(&ctrl->namespaces_rwsem); out_unlink_ns: mutex_lock(&ctrl->subsys->lock); list_del_rcu(&ns->siblings);
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit 7f9b348cb5e94259acdcbafbcaed55d3bb515304 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Convert the brd driver to use the blk_alloc_disk and blk_cleanup_disk helpers to simplify gendisk and request_queue allocation. This also allows to remove the request_queue pointer in struct request_queue, and to simplify the initialization as blk_cleanup_disk can be called on any disk returned from blk_alloc_disk.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Hannes Reinecke hare@suse.de Reviewed-by: Ulf Hansson ulf.hansson@linaro.org Link: https://lore.kernel.org/r/20210521055116.1053587-7-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: drivers/block/brd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/block/brd.c | 98 ++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 59 deletions(-)
diff --git a/drivers/block/brd.c b/drivers/block/brd.c index fa75f137cc77..f44d994bdea5 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -37,9 +37,7 @@ * device). */ struct brd_device { - int brd_number; - - struct request_queue *brd_queue; + int brd_number; struct gendisk *brd_disk; struct list_head brd_list;
@@ -373,7 +371,7 @@ static LIST_HEAD(brd_devices); static DEFINE_MUTEX(brd_devices_mutex); static struct dentry *brd_debugfs_dir;
-static struct brd_device *brd_alloc(int i) +static int brd_alloc(int i) { struct brd_device *brd; struct gendisk *disk; @@ -381,63 +379,55 @@ static struct brd_device *brd_alloc(int i)
brd = kzalloc(sizeof(*brd), GFP_KERNEL); if (!brd) - goto out; + return -ENOMEM; brd->brd_number = i; spin_lock_init(&brd->brd_lock); INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
- brd->brd_queue = blk_alloc_queue(NUMA_NO_NODE); - if (!brd->brd_queue) - goto out_free_dev; - snprintf(buf, DISK_NAME_LEN, "ram%d", i); if (!IS_ERR_OR_NULL(brd_debugfs_dir)) debugfs_create_u64(buf, 0444, brd_debugfs_dir, &brd->brd_nr_pages);
- /* This is so fdisk will align partitions on 4k, because of - * direct_access API needing 4k alignment, returning a PFN - * (This is only a problem on very small devices <= 4M, - * otherwise fdisk will align on 1M. Regardless this call - * is harmless) - */ - blk_queue_physical_block_size(brd->brd_queue, PAGE_SIZE); - disk = brd->brd_disk = alloc_disk(max_part); + disk = brd->brd_disk = blk_alloc_disk(NUMA_NO_NODE); if (!disk) - goto out_free_queue; + goto out_free_dev; + disk->major = RAMDISK_MAJOR; disk->first_minor = i * max_part; + disk->minors = max_part; disk->fops = &brd_fops; disk->private_data = brd; disk->flags = GENHD_FL_EXT_DEVT; strlcpy(disk->disk_name, buf, DISK_NAME_LEN); set_capacity(disk, rd_size * 2);
+ /* + * This is so fdisk will align partitions on 4k, because of + * direct_access API needing 4k alignment, returning a PFN + * (This is only a problem on very small devices <= 4M, + * otherwise fdisk will align on 1M. Regardless this call + * is harmless) + */ + blk_queue_physical_block_size(disk->queue, PAGE_SIZE); + /* Tell the block layer that this is not a rotational device */ - blk_queue_flag_set(QUEUE_FLAG_NONROT, brd->brd_queue); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, brd->brd_queue); + blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); + blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); + add_disk(disk); + list_add_tail(&brd->brd_list, &brd_devices);
- return brd; + return 0;
-out_free_queue: - blk_cleanup_queue(brd->brd_queue); out_free_dev: kfree(brd); -out: - return NULL; -} - -static void brd_free(struct brd_device *brd) -{ - put_disk(brd->brd_disk); - blk_cleanup_queue(brd->brd_queue); - brd_free_pages(brd); - kfree(brd); + return -ENOMEM; }
static struct brd_device *brd_init_one(int i, bool *new) { struct brd_device *brd; + int err;
*new = false; list_for_each_entry(brd, &brd_devices, brd_list) { @@ -445,13 +435,14 @@ static struct brd_device *brd_init_one(int i, bool *new) goto out; }
- brd = brd_alloc(i); - if (brd) { - brd->brd_disk->queue = brd->brd_queue; - add_disk(brd->brd_disk); - list_add_tail(&brd->brd_list, &brd_devices); - } *new = true; + err = brd_alloc(i); + if (err) + return NULL; + list_for_each_entry(brd, &brd_devices, brd_list) { + if (brd->brd_number == i) + goto out; + } out: return brd; } @@ -460,7 +451,9 @@ static void brd_del_one(struct brd_device *brd) { list_del(&brd->brd_list); del_gendisk(brd->brd_disk); - brd_free(brd); + blk_cleanup_disk(brd->brd_disk); + brd_free_pages(brd); + kfree(brd); }
static struct kobject *brd_probe(dev_t dev, int *part, void *data) @@ -502,7 +495,7 @@ static inline void brd_check_and_reset_par(void) static int __init brd_init(void) { struct brd_device *brd, *next; - int i; + int err, i;
/* * brd module now has a feature to instantiate underlying device @@ -527,22 +520,11 @@ static int __init brd_init(void) brd_debugfs_dir = debugfs_create_dir("ramdisk_pages", NULL);
for (i = 0; i < rd_nr; i++) { - brd = brd_alloc(i); - if (!brd) + err = brd_alloc(i); + if (err) goto out_free; - list_add_tail(&brd->brd_list, &brd_devices); }
- /* point of no return */ - - list_for_each_entry(brd, &brd_devices, brd_list) { - /* - * associate with queue just before adding disk for - * avoiding to mess up failure path - */ - brd->brd_disk->queue = brd->brd_queue; - add_disk(brd->brd_disk); - }
blk_register_region(MKDEV(RAMDISK_MAJOR, 0), 1UL << MINORBITS, THIS_MODULE, brd_probe, NULL, NULL); @@ -553,14 +535,12 @@ static int __init brd_init(void) out_free: debugfs_remove_recursive(brd_debugfs_dir);
- list_for_each_entry_safe(brd, next, &brd_devices, brd_list) { - list_del(&brd->brd_list); - brd_free(brd); - } + list_for_each_entry_safe(brd, next, &brd_devices, brd_list) + brd_del_one(brd); unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
pr_info("brd: module NOT loaded !!!\n"); - return -ENOMEM; + return err; }
static void __exit brd_exit(void)
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit e1528830bd4ebf435d91c154e309e6e028336210 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling.
Signed-off-by: Luis Chamberlain mcgrof@kernel.org Link: https://lore.kernel.org/r/20211015235219.2191207-2-mcgrof@kernel.org Signed-off-by: Jens Axboe axboe@kernel.dk conflict: drivers/block/brd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/block/brd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/block/brd.c b/drivers/block/brd.c index f44d994bdea5..651282d4f17a 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -376,6 +376,7 @@ static int brd_alloc(int i) struct brd_device *brd; struct gendisk *disk; char buf[DISK_NAME_LEN]; + int err = -ENOMEM;
brd = kzalloc(sizeof(*brd), GFP_KERNEL); if (!brd) @@ -414,14 +415,18 @@ static int brd_alloc(int i) /* Tell the block layer that this is not a rotational device */ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); - add_disk(disk); + err = add_disk_safe(disk); + if (err) + goto out_cleanup_disk; list_add_tail(&brd->brd_list, &brd_devices);
return 0;
+out_cleanup_disk: + blk_cleanup_disk(disk); out_free_dev: kfree(brd); - return -ENOMEM; + return err; }
static struct brd_device *brd_init_one(int i, bool *new)
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit 2a7a891f4c406822801ecd676b076c64de072c9e category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling.
As with the error handling for device_add() we follow the same logic and just put the device so that cleanup is done via the scsi_disk_release().
Link: https://lore.kernel.org/r/20211015233028.2167651-2-mcgrof@kernel.org Reviewed-by: Christoph Hellwig hch@lst.de Acked-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Luis Chamberlain mcgrof@kernel.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com conflict: drivers/scsi/sd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/scsi/sd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7c8bfb26c995..0a83320deb14 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3498,7 +3498,13 @@ static int sd_probe(struct device *dev) pm_runtime_set_autosuspend_delay(dev, sdp->host->hostt->rpm_autosuspend_delay); } - device_add_disk(dev, gd, NULL); + + error = device_add_disk_safe(dev, gd, NULL); + if (error) { + put_device(&sdkp->dev); + goto out; + } + blk_delete_region(disk_devt(sdkp->disk), SD_MINORS, sd_default_probe); if (sdkp->security) { sdkp->opal_dev = init_opal_dev(sdkp, &sd_sec_submit);
hulk inclusion category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
If device_add_disk fail, we should clear the resources requested by device_add, otherwise sdkp is not be cleared and will cause memory leaks.
Fix it by call device_del to clean the sdkp.
Fixes: 2a7a891f4c40 ("scsi: sd: Add error handling support for add_disk()") Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/scsi/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0a83320deb14..5385805e06a8 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3501,7 +3501,7 @@ static int sd_probe(struct device *dev)
error = device_add_disk_safe(dev, gd, NULL); if (error) { - put_device(&sdkp->dev); + device_unregister(&sdkp->dev); goto out; }
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit e9d658c2175b95a8f091b12ddefb271683aeacd9 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling.
Just put the cdrom kref and have the unwinding be done by sr_kref_release().
Link: https://lore.kernel.org/r/20211015233028.2167651-3-mcgrof@kernel.org Reviewed-by: Christoph Hellwig hch@lst.de Acked-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Luis Chamberlain mcgrof@kernel.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/scsi/sr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 464418413ced..7ccdf4fcb596 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -793,7 +793,12 @@ static int sr_probe(struct device *dev) dev_set_drvdata(dev, cd); disk->flags |= GENHD_FL_REMOVABLE; sr_revalidate_disk(cd); - device_add_disk(&sdev->sdev_gendev, disk, NULL); + + error = device_add_disk_safe(&sdev->sdev_gendev, disk, NULL); + if (error) { + kref_put(&cd->kref, sr_kref_release); + goto fail; + }
sdev_printk(KERN_DEBUG, sdev, "Attached scsi CD-ROM %s\n", cd->cdi.name);
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit 77567b25ab9f06c6477a153e58ace6897c6794d1 category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
Use blk_mq_alloc_disk and blk_cleanup_disk to simplify the gendisk and request_queue allocation.
Signed-off-by: Christoph Hellwig hch@lst.de Reviewed-by: Chaitanya Kulkarni chaitanya.kulkarni@wdc.com Link: https://lore.kernel.org/r/20210602065345.355274-27-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/mtd/ubi/block.c | 68 ++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 39 deletions(-)
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index e1a2ae21dfd3..e003b4b44ffa 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -394,53 +394,46 @@ int ubiblock_create(struct ubi_volume_info *vi) dev->vol_id = vi->vol_id; dev->leb_size = vi->usable_leb_size;
+ dev->tag_set.ops = &ubiblock_mq_ops; + dev->tag_set.queue_depth = 64; + dev->tag_set.numa_node = NUMA_NO_NODE; + dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu); + dev->tag_set.driver_data = dev; + dev->tag_set.nr_hw_queues = 1; + + 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_free_dev;; + } + + /* Initialize the gendisk of this ubiblock device */ - gd = alloc_disk(1); - if (!gd) { - pr_err("UBI: block: alloc_disk failed\n"); - ret = -ENODEV; - goto out_free_dev; + gd = blk_mq_alloc_disk(&dev->tag_set, dev); + if (IS_ERR(gd)) { + ret = PTR_ERR(gd); + goto out_free_tags; }
gd->fops = &ubiblock_ops; gd->major = ubiblock_major; + gd->minors = 1; 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; + goto out_cleanup_disk; } gd->private_data = dev; sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); set_capacity(gd, disk_capacity); dev->gd = gd;
- dev->tag_set.ops = &ubiblock_mq_ops; - dev->tag_set.queue_depth = 64; - dev->tag_set.numa_node = NUMA_NO_NODE; - dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; - dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu); - dev->tag_set.driver_data = dev; - dev->tag_set.nr_hw_queues = 1; - - 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_remove_minor; - } - - dev->rq = blk_mq_init_queue(&dev->tag_set); - if (IS_ERR(dev->rq)) { - dev_err(disk_to_dev(gd), "blk_mq_init_queue failed"); - ret = PTR_ERR(dev->rq); - goto out_free_tags; - } + dev->rq = gd->queue; blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
- dev->rq->queuedata = dev; - dev->gd->queue = dev->rq; - /* * Create one workqueue per volume (per registered block device). * Rembember workqueues are cheap, they're not threads. @@ -448,7 +441,7 @@ int ubiblock_create(struct ubi_volume_info *vi) dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name); if (!dev->wq) { ret = -ENOMEM; - goto out_free_queue; + goto out_remove_minor; }
list_add_tail(&dev->list, &ubiblock_devices); @@ -460,14 +453,12 @@ int ubiblock_create(struct ubi_volume_info *vi) mutex_unlock(&devices_mutex); return 0;
-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_cleanup_disk: + blk_cleanup_disk(dev->gd); +out_free_tags: + blk_mq_free_tag_set(&dev->tag_set); out_free_dev: kfree(dev); out_unlock: @@ -483,11 +474,10 @@ static void ubiblock_cleanup(struct ubiblock *dev) /* Flush pending work */ destroy_workqueue(dev->wq); /* Finally destroy the blk queue */ - blk_cleanup_queue(dev->rq); - blk_mq_free_tag_set(&dev->tag_set); dev_info(disk_to_dev(dev->gd), "released"); + blk_cleanup_disk(dev->gd); + blk_mq_free_tag_set(&dev->tag_set); idr_remove(&ubiblock_minor_idr, dev->gd->first_minor); - put_disk(dev->gd); }
int ubiblock_remove(struct ubi_volume_info *vi)
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit ed73919124b2e48490adbbe48ffe885a2a4c6fee category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling.
Reviewed-by: Christoph Hellwig hch@lst.de Signed-off-by: Luis Chamberlain mcgrof@kernel.org Link: https://lore.kernel.org/r/20211103230437.1639990-10-mcgrof@kernel.org Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/mtd/ubi/block.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index e003b4b44ffa..669b53244096 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -447,12 +447,18 @@ int ubiblock_create(struct ubi_volume_info *vi) list_add_tail(&dev->list, &ubiblock_devices);
/* Must be the last step: anyone can call file ops from now on */ - add_disk(dev->gd); + ret = add_disk_safe(dev->gd); + if (ret) + goto out_destroy_wq; + dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", dev->ubi_num, dev->vol_id, vi->name); mutex_unlock(&devices_mutex); return 0;
+out_destroy_wq: + list_del(&dev->list); + destroy_workqueue(dev->wq); out_remove_minor: idr_remove(&ubiblock_minor_idr, gd->first_minor); out_cleanup_disk:
hulk inclusion category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
When idr_alloc fails and goes the out_cleanup_disk error path, we get a null pointer dereference problem because dev->gd has not been assigned a value at this time.
Fix this problem by changing dev->gd to gd.
Fixes: 2bf50d42f3a4 ("UBI: block: Dynamically allocate minor numbers") Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/mtd/ubi/block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 669b53244096..9e71a7803224 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -462,7 +462,7 @@ int ubiblock_create(struct ubi_volume_info *vi) out_remove_minor: idr_remove(&ubiblock_minor_idr, gd->first_minor); out_cleanup_disk: - blk_cleanup_disk(dev->gd); + blk_cleanup_disk(gd); out_free_tags: blk_mq_free_tag_set(&dev->tag_set); out_free_dev:
hulk inclusion category: bugfix bugzilla: 188733, https://gitee.com/openeuler/kernel/issues/I81XCK
----------------------------------------
put_disk should be placed after idr_remove, otherwise it will trigger the uaf problem of dev->gd.
Fixes: 77567b25ab9f ("ubi: use blk_mq_alloc_disk and blk_cleanup_disk") Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- drivers/mtd/ubi/block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 9e71a7803224..203d42191585 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -481,9 +481,9 @@ static void ubiblock_cleanup(struct ubiblock *dev) destroy_workqueue(dev->wq); /* Finally destroy the blk queue */ dev_info(disk_to_dev(dev->gd), "released"); + idr_remove(&ubiblock_minor_idr, dev->gd->first_minor); blk_cleanup_disk(dev->gd); blk_mq_free_tag_set(&dev->tag_set); - idr_remove(&ubiblock_minor_idr, dev->gd->first_minor); }
int ubiblock_remove(struct ubi_volume_info *vi)
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/2681 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/P...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/2681 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/P...