aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Hellwig <[email protected]>2021-12-21 17:18:51 +0100
committerJens Axboe <[email protected]>2021-12-21 09:31:51 -0700
commit99d8690aae4b2f0d1d90075de355ac087f820a66 (patch)
tree602e947ef3c103a6be94489d84cb1e8da3523aa9
parent37e11c3616f6182b6bd7f95a04df035b43464f39 (diff)
block: fix error unwinding in device_add_disk
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 <[email protected]> Tested-by: syzbot <[email protected]> Fixes: 83cbce9574462c6b ("block: add error handling for device_add_disk / add_disk") Signed-off-by: Christoph Hellwig <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
-rw-r--r--block/genhd.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/block/genhd.c b/block/genhd.c
index 3c139a1b6f04..603db5d6f10c 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -442,10 +442,6 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
disk->first_minor = ret;
}
- ret = disk_alloc_events(disk);
- if (ret)
- goto out_free_ext_minor;
-
/* delay uevents, until we scanned partition table */
dev_set_uevent_suppress(ddev, 1);
@@ -456,7 +452,12 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
ddev->devt = MKDEV(disk->major, disk->first_minor);
ret = device_add(ddev);
if (ret)
- goto out_disk_release_events;
+ goto out_free_ext_minor;
+
+ ret = disk_alloc_events(disk);
+ if (ret)
+ goto out_device_del;
+
if (!sysfs_deprecated) {
ret = sysfs_create_link(block_depr, &ddev->kobj,
kobject_name(&ddev->kobj));
@@ -538,8 +539,6 @@ out_del_block_link:
sysfs_remove_link(block_depr, dev_name(ddev));
out_device_del:
device_del(ddev);
-out_disk_release_events:
- disk_release_events(disk);
out_free_ext_minor:
if (disk->major == BLOCK_EXT_MAJOR)
blk_free_ext_minor(disk->first_minor);