Commit ac2044c0 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Li Nan
Browse files

block: fix error unwinding in device_add_disk

mainline inclusion
from mainline-v5.17-rc1
commit 99d8690a
category: bugfix
bugzilla: 188733

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=99d8690aae4b2f0d1d90075de355ac087f820a66



----------------------------------------

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: default avatarsyzbot <syzbot+28a66a9fbc621c939000@syzkaller.appspotmail.com>
Tested-by: default avatarsyzbot <syzbot+28a66a9fbc621c939000@syzkaller.appspotmail.com>
Fixes: 83cbce95 ("block: add error handling for device_add_disk / add_disk")
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20211221161851.788424-1-hch@lst.de


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
conflict:
  block/genhd.c
Signed-off-by: default avatarZhong Jinghua <zhongjinghua@huawei.com>
Signed-off-by: default avatarLi Nan <linan122@huawei.com>
parent ed697adf
Loading
Loading
Loading
Loading
+4 −7
Original line number Diff line number Diff line
@@ -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 */