From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.17-rc1 commit 99d8690aae4b2f0d1d90075de355ac087f820a66 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I81XCK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------
One device_add is called disk->ev will be freed by disk_release, so we should free it twice. Fix this by allocating disk->ev after device_add so that the extra local unwinding can be removed entirely.
Based on an earlier patch from Tetsuo Handa.
Reported-by: syzbot syzbot+28a66a9fbc621c939000@syzkaller.appspotmail.com Tested-by: syzbot syzbot+28a66a9fbc621c939000@syzkaller.appspotmail.com Fixes: 83cbce9574462c6b ("block: add error handling for device_add_disk / add_disk") Signed-off-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/20211221161851.788424-1-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk conflict: block/genhd.c Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com 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 ca082822d48a..dff4b67e947d 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -793,10 +793,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, @@ -811,7 +807,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); @@ -831,6 +827,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)); @@ -914,8 +913,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 */