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
Li Lingfeng (1): nbd: fix uaf in nbd_open
Luis Chamberlain (10): 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: 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
Wen Yang (1): Revert "Revert "block: nbd: add sanity check for first_minor""
Yu Kuai (3): nbd: fix max value for 'first_minor' nbd: fix possible overflow for 'first_minor' in nbd_dev_add() block: fix memory leak for elevator on add_disk failure
Zhang Wensheng (1): nbd: fix possible overflow on 'first_minor' in nbd_dev_add()
Zhong Jinghua (9): nbd: Reorganize the messy commit log about the first_minor check 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 mtd/ubi/block: Fix null pointer dereference issue in error path mtd/ubi/block: Fix uaf problem in ubiblock_cleanup
block/blk.h | 5 +- include/linux/blk-mq.h | 12 ++ include/linux/genhd.h | 36 +++++ block/blk-integrity.c | 12 +- block/blk-mq.c | 19 +++ block/genhd.c | 286 ++++++++++++++++++++++++++------------- drivers/block/brd.c | 103 ++++++-------- drivers/block/loop.c | 26 ++-- drivers/block/nbd.c | 75 ++++------ drivers/mtd/ubi/block.c | 76 +++++------ drivers/nvme/host/core.c | 41 +++--- drivers/scsi/sr.c | 7 +- 12 files changed, 413 insertions(+), 285 deletions(-)
From: Zhong Jinghua zhongjinghua@huawei.com
hulk inclusion category: bugfix bugzilla: 188217
----------------------------------------
Commits on our branch with check issues on first_minor had serious confusion, resulting in duplicate checks in nbd_dev_add and nbd_genl_connect.
So I revert the messy commit, backport lts patch.
Revert 881885f30261 [Backport] nbd: fix max value for 'first_minor' Revert 4d759cee3f18 [Backport] Revert "Revert "block: nbd: add sanity check for first_minor"" Revert b95487500a4f [Huawei] nbd: fix assignment error for first_minor in nbd_dev_add Revert 93c4218b2f4d [Backport] nbd: fix possible overflow on 'first_minor' in nbd_dev_add() Revert 60141517d289 nbd: Fix use-after-free in blk_mq_free_rqs Revert 98d3ad1d2589 nbd: add sanity check for first_minor
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- drivers/block/nbd.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index fa08f380f5be..29884a0f1fca 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1875,17 +1875,7 @@ static int nbd_dev_add(int index) refcount_set(&nbd->refs, 1); INIT_LIST_HEAD(&nbd->list); disk->major = NBD_MAJOR; - - /* Too big first_minor can cause duplicate creation of - * sysfs files/links, since index << part_shift might overflow, or - * MKDEV() expect that the max bits of first_minor is 20. - */ disk->first_minor = index << part_shift; - if (disk->first_minor < index || disk->first_minor > MINORMASK) { - err = -EINVAL; - goto out_free_idr; - } - disk->fops = &nbd_fops; disk->private_data = nbd; sprintf(disk->disk_name, "nbd%d", index); @@ -1972,20 +1962,8 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) if (!netlink_capable(skb, CAP_SYS_ADMIN)) return -EPERM;
- if (info->attrs[NBD_ATTR_INDEX]) { + if (info->attrs[NBD_ATTR_INDEX]) index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]); - - /* - * Too big first_minor can cause duplicate creation of - * sysfs files/links, since index << part_shift might - * overflow, or MKDEV() expect that the max bits of - * first_minor is 20. - */ - if (index < 0 || index > MINORMASK >> part_shift) { - printk(KERN_ERR "nbd: illegal input index %d\n", index); - return -EINVAL; - } - } if (!info->attrs[NBD_ATTR_SOCKETS]) { printk(KERN_ERR "nbd: must specify at least one socket\n"); return -EINVAL;
From: Wen Yang wenyang.linux@foxmail.com
stable inclusion from stable-v5.10.170 commit f3f6b33b77bac0bd27f1f1bec05ab58a54948fc9 category: bugfix bugzilla: 188217
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
This reverts commit 0daa75bf750c400af0a0127fae37cd959d36dee7.
These problems such as: https://lore.kernel.org/all/CACPK8XfUWoOHr-0RwRoYoskia4fbAbZ7DYf5wWBnv6qUnGq... It was introduced by introduced by commit b1a811633f73 ("block: nbd: add sanity check for first_minor") and has been have been fixed by commit e4c4871a7394 ("nbd: fix max value for 'first_minor'").
Cc: Joel Stanley joel@jms.id.au Cc: Christoph Hellwig hch@lst.de Cc: Pavel Skripkin paskripkin@gmail.com Cc: Jens Axboe axboe@kernel.dk Cc: Sasha Levin sashal@kernel.org Cc: stable@vger.kernel.org # v5.10+ Signed-off-by: Wen Yang wenyang.linux@foxmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- drivers/block/nbd.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 29884a0f1fca..7f26571a8ca0 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1875,7 +1875,17 @@ static int nbd_dev_add(int index) refcount_set(&nbd->refs, 1); INIT_LIST_HEAD(&nbd->list); disk->major = NBD_MAJOR; + + /* Too big first_minor can cause duplicate creation of + * sysfs files/links, since first_minor will be truncated to + * byte in __device_add_disk(). + */ disk->first_minor = index << part_shift; + if (disk->first_minor > 0xff) { + err = -EINVAL; + goto out_free_idr; + } + disk->fops = &nbd_fops; disk->private_data = nbd; sprintf(disk->disk_name, "nbd%d", index);
From: Yu Kuai yukuai3@huawei.com
stable inclusion from stable-v5.10.170 commit fd8107206a672f5a529a819e8930bf81fb54ae0f category: bugfix bugzilla: 188217
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
commit e4c4871a73944353ea23e319de27ef73ce546623 upstream.
commit b1a811633f73 ("block: nbd: add sanity check for first_minor") checks that 'first_minor' should not be greater than 0xff, which is wrong. Whitout the commit, the details that when user pass 0x100000, it ends up create sysfs dir "/sys/block/43:0" are as follows:
nbd_dev_add disk->first_minor = index << part_shift -> default part_shift is 5, first_minor is 0x2000000 device_add_disk ddev->devt = MKDEV(disk->major, disk->first_minor) -> (0x2b << 20) | (0x2000000) = 0x2b00000 device_add device_create_sys_dev_entry format_dev_t sprintf(buffer, "%u:%u", MAJOR(dev), MINOR(dev)); -> got 43:0 sysfs_create_link -> /sys/block/43:0
By the way, with the wrong fix, when part_shift is the default value, only 8 ndb devices can be created since 8 << 5 is greater than 0xff.
Since the max bits for 'first_minor' should be the same as what MKDEV() does, which is 20. Change the upper bound of 'first_minor' from 0xff to 0xfffff.
Fixes: b1a811633f73 ("block: nbd: add sanity check for first_minor") Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Josef Bacik josef@toxicpanda.com Link: https://lore.kernel.org/r/20211102015237.2309763-2-yebin10@huawei.com Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Wen Yang wenyang.linux@foxmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- drivers/block/nbd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 7f26571a8ca0..626e83fc0d81 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1877,11 +1877,11 @@ static int nbd_dev_add(int index) disk->major = NBD_MAJOR;
/* Too big first_minor can cause duplicate creation of - * sysfs files/links, since first_minor will be truncated to - * byte in __device_add_disk(). + * sysfs files/links, since MKDEV() expect that the max bits of + * first_minor is 20. */ disk->first_minor = index << part_shift; - if (disk->first_minor > 0xff) { + if (disk->first_minor > MINORMASK) { err = -EINVAL; goto out_free_idr; }
From: Yu Kuai yukuai3@huawei.com
stable inclusion from stable-v5.10.170 commit 2e0c3e43ebb99c2b495229f8fade4c043fbd06a5 category: bugfix bugzilla: 188217
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
commit 940c264984fd1457918393c49674f6b39ee16506 upstream.
If 'part_shift' is not zero, then 'index << part_shift' might overflow to a value that is not greater than '0xfffff', then sysfs might complains about duplicate creation.
Fixes: b0d9111a2d53 ("nbd: use an idr to keep track of nbd devices") Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Josef Bacik josef@toxicpanda.com Link: https://lore.kernel.org/r/20211102015237.2309763-3-yebin10@huawei.com Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Wen Yang wenyang.linux@foxmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- drivers/block/nbd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 626e83fc0d81..8290c1ac2e4f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1877,11 +1877,11 @@ static int nbd_dev_add(int index) disk->major = NBD_MAJOR;
/* Too big first_minor can cause duplicate creation of - * sysfs files/links, since MKDEV() expect that the max bits of - * first_minor is 20. + * sysfs files/links, since index << part_shift might overflow, or + * MKDEV() expect that the max bits of first_minor is 20. */ disk->first_minor = index << part_shift; - if (disk->first_minor > MINORMASK) { + if (disk->first_minor < index || disk->first_minor > MINORMASK) { err = -EINVAL; goto out_free_idr; }
From: Zhang Wensheng zhangwensheng5@huawei.com
stable inclusion from stable-v5.10.170 commit 4311ad1e7654f9dd569a4d1b0059f838f474e9d3 category: bugfix bugzilla: 188217
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
commit 858f1bf65d3d9c00b5e2d8ca87dc79ed88267c98 upstream.
When 'index' is a big numbers, it may become negative which forced to 'int'. then 'index << part_shift' might overflow to a positive value that is not greater than '0xfffff', then sysfs might complains about duplicate creation. Because of this, move the 'index' judgment to the front will fix it and be better.
Fixes: b0d9111a2d53 ("nbd: use an idr to keep track of nbd devices") Fixes: 940c264984fd ("nbd: fix possible overflow for 'first_minor' in nbd_dev_add()") Signed-off-by: Zhang Wensheng zhangwensheng5@huawei.com Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Josef Bacik josef@toxicpanda.com Link: https://lore.kernel.org/r/20220521073749.3146892-6-yukuai3@huawei.com Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Wen Yang wenyang.linux@foxmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- drivers/block/nbd.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 8290c1ac2e4f..33113d6d668f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1875,17 +1875,7 @@ static int nbd_dev_add(int index) refcount_set(&nbd->refs, 1); INIT_LIST_HEAD(&nbd->list); disk->major = NBD_MAJOR; - - /* Too big first_minor can cause duplicate creation of - * sysfs files/links, since index << part_shift might overflow, or - * MKDEV() expect that the max bits of first_minor is 20. - */ disk->first_minor = index << part_shift; - if (disk->first_minor < index || disk->first_minor > MINORMASK) { - err = -EINVAL; - goto out_free_idr; - } - disk->fops = &nbd_fops; disk->private_data = nbd; sprintf(disk->disk_name, "nbd%d", index); @@ -1972,8 +1962,19 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) if (!netlink_capable(skb, CAP_SYS_ADMIN)) return -EPERM;
- if (info->attrs[NBD_ATTR_INDEX]) + if (info->attrs[NBD_ATTR_INDEX]) { index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]); + + /* + * Too big first_minor can cause duplicate creation of + * sysfs files/links, since index << part_shift might overflow, or + * MKDEV() expect that the max bits of first_minor is 20. + */ + if (index < 0 || index > MINORMASK >> part_shift) { + printk(KERN_ERR "nbd: illegal input index %d\n", index); + return -EINVAL; + } + } if (!info->attrs[NBD_ATTR_SOCKETS]) { printk(KERN_ERR "nbd: must specify at least one socket\n"); return -EINVAL;
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.15-rc1 commit 52b85909f85d06efa69aaf4210e72467f1f58d2b category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@huawei.com --- block/blk.h | 5 +++-- block/blk-integrity.c | 12 +++++++----- 2 files changed, 10 insertions(+), 7 deletions(-)
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) { 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)
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.15-rc1 commit 92e7755ebc69233e25a2d1b760aeff536dc4016b category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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)
From: Zhong Jinghua zhongjinghua@huawei.com
hulk inclusion category: bugfix bugzilla: 188733
----------------------------------------
Modify the return value type of blk_register_region to prepare for adding error handling.
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- include/linux/genhd.h | 2 +- block/genhd.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-)
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 *), 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);
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.15-rc1 commit 83cbce9574462c6b4eed6797bdaf18fae6859ab3 category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@huawei.com --- include/linux/genhd.h | 6 +-- block/genhd.c | 95 +++++++++++++++++++++++++++++-------------- 2 files changed, 67 insertions(+), 34 deletions(-)
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) 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);
From: Luis Chamberlain mcgrof@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit fe7d064fa3faec5d8157029fb8720b4fddc9e1e8 category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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 */
From: Zhong Jinghua zhongjinghua@huawei.com
hulk inclusion category: bugfix bugzilla: 188733
----------------------------------------
Fix the kabi change caused by changing the return value of device_add_disk.
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- include/linux/genhd.h | 19 ++++++++++++++++--- block/genhd.c | 21 +++++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-)
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); 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;
From: Zhong Jinghua zhongjinghua@huawei.com
hulk inclusion category: bugfix bugzilla: 188733
----------------------------------------
Fix kabi change caused by blk_register_region change return value.
Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- include/linux/genhd.h | 2 +- block/genhd.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-)
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 *), 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; }
From: Yu Kuai yukuai3@huawei.com
mainline inclusion from mainline-v6.1-rc3 commit 02341a08c9dec5a88527981b0bdf0fb6f7499cbf category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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
----------------------------------------
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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;
From: Zhong Jinghua zhongjinghua@huawei.com
hulk inclusion category: bugfix bugzilla: 188733
----------------------------------------
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 Signed-off-by: Li Nan linan122@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)
From: Zhong Jinghua zhongjinghua@huawei.com
hulk inclusion category: bugfix bugzilla: 188217
----------------------------------------
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@huawei.com --- include/linux/genhd.h | 22 ++++++++++++++++++++++ block/genhd.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+)
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);
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
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.14-rc1 commit b461dfc49eb6fbabc60b9dad476e787ada56b7b4 category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@huawei.com --- include/linux/blk-mq.h | 12 ++++++++++++ block/blk-mq.c | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+)
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); 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.
From: Dan Carpenter dan.carpenter@oracle.com
mainline inclusion from mainline-v5.14-rc1 commit 52d7e288444906aa5c99888e80a9cc1a1423ed92 category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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 33113d6d668f..5f3d4662d7a9 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 @@ -1876,6 +1866,7 @@ static int nbd_dev_add(int index) INIT_LIST_HEAD(&nbd->list); disk->major = NBD_MAJOR; disk->first_minor = index << part_shift; + disk->minors = 1 << part_shift; disk->fops = &nbd_fops; disk->private_data = nbd; sprintf(disk->disk_name, "nbd%d", index); @@ -1883,12 +1874,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
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 Signed-off-by: Li Nan linan122@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 5f3d4662d7a9..bcfb3666c7be 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
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 Signed-off-by: Li Nan linan122@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 bcfb3666c7be..283395b1ed3c 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1870,10 +1870,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
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 Signed-off-by: Li Nan linan122@huawei.com --- include/linux/genhd.h | 1 + block/genhd.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-)
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;
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); }
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.15-rc1 commit 5f432cceb3e9de5223fa50d882c4a43cab39a3ee category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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..cd4348a618df 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
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 Signed-off-by: Li Nan linan122@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 cd4348a618df..bb3ccaebc9aa 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 e9d658c2175b95a8f091b12ddefb271683aeacd9 category: bugfix bugzilla: 188733
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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
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 Signed-off-by: Li Nan linan122@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:
From: Zhong Jinghua zhongjinghua@huawei.com
hulk inclusion category: bugfix bugzilla: 188733
----------------------------------------
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 Signed-off-by: Li Nan linan122@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:
From: Zhong Jinghua zhongjinghua@huawei.com
hulk inclusion category: bugfix bugzilla: 188733
----------------------------------------
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 Signed-off-by: Li Nan linan122@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)
From: Li Lingfeng lilingfeng3@huawei.com
hulk inclusion category: bugfix bugzilla: 189228
--------------------------------
Commit bd0c825c26c3 ("[Backport] nbd: use blk_mq_alloc_disk and blk_cleanup_disk") cleans up disk by blk_cleanup_disk() and it won't set disk->private_data as NULL as before. UAF may be triggered in nbd_open() if someone tries to open nbd device right after nbd_put() since refcount of nbd device is zero and private_data is not NULL.
Fixes: bd0c825c26c3 ("[Backport] nbd: use blk_mq_alloc_disk and blk_cleanup_disk") Signed-off-by: Li Lingfeng lilingfeng3@huawei.com Signed-off-by: Li Nan linan122@huawei.com --- drivers/block/nbd.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 283395b1ed3c..fe06abb9f830 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -229,6 +229,7 @@ static void nbd_dev_remove(struct nbd_device *nbd)
if (disk) { del_gendisk(disk); + disk->private_data = NULL; blk_cleanup_disk(disk); blk_mq_free_tag_set(&nbd->tag_set); }