Christoph Hellwig (9): 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 (6): 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()
Wang Qing (1): nbd: fix order of cleaning up the queue and freeing the tagset
Zhong Jinghua (2): mtd/ubi/block: Fix null pointer dereference issue in error path mtd/ubi/block: Fix uaf problem in ubiblock_cleanup
include/linux/blk-mq.h | 12 +++++ include/linux/genhd.h | 23 +++++++++ block/blk-mq.c | 19 ++++++++ block/genhd.c | 42 +++++++++++++++- drivers/block/brd.c | 103 +++++++++++++++++---------------------- drivers/block/loop.c | 26 +++++----- drivers/block/nbd.c | 60 ++++++++++------------- drivers/mtd/ubi/block.c | 76 ++++++++++++++--------------- drivers/nvme/host/core.c | 41 ++++++++-------- drivers/scsi/sr.c | 7 ++- 10 files changed, 239 insertions(+), 170 deletions(-)
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/2817 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/Z...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/2817 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/Z...
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); }