Unverified Commit 38d70d3e authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!2783 Add error handle for add_disk

Merge Pull Request from: @ci-robot 
 
PR sync from: Li Nan <linan122@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/SW7XZX2OMWT6AZ2X4U3FB27GUFXHTWPU/ 
To make applying the mainline patch easier, reorder the nbd commit about
the first_minor check here.

Christoph Hellwig (5):
  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

Luis Chamberlain (4):
  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

Tetsuo Handa (1):
  block: check minor range in device_add_disk()

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 (7):
  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


-- 
2.39.2
 
 
 
Link:https://gitee.com/openeuler/kernel/pulls/2783

 

Reviewed-by: default avatarYu Kuai <yukuai3@huawei.com>
Reviewed-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 8ab53135 e638776f
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -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;

	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)
+3 −2
Original line number Diff line number Diff line
@@ -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)
{
+150 −96
Original line number Diff line number Diff line
@@ -40,10 +40,13 @@ 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);
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
@@ -646,6 +649,7 @@ 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,
			 struct kobject *(*probe)(dev_t, int *, void *),
@@ -687,55 +691,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;
@@ -813,16 +768,20 @@ 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)
{
	struct device *ddev = disk_to_dev(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
@@ -832,6 +791,7 @@ static void __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.
@@ -840,16 +800,16 @@ static void __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 > 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) {
		WARN_ON(1);
		return;
	}
	if (retval)
		goto out_exit_elevator;
	disk->major = MAJOR(devt);
	disk->first_minor = MINOR(devt);

	disk_alloc_events(disk);

	if (disk->flags & GENHD_FL_HIDDEN) {
		/*
		 * Don't let hidden disks show up in /proc/partitions,
@@ -859,29 +819,78 @@ 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;
		ret = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt));
		WARN_ON(ret);
		bdi_set_owner(bdi, dev);
		blk_register_region(disk_devt(disk), disk->minors, NULL,
		ddev->devt = devt;
		retval = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt));
		if (retval)
			goto out_free_ext_minor;
		bdi_set_owner(bdi, ddev);
		retval = kobj_map(bdev_map, disk_devt(disk), disk->minors, NULL,
				  exact_match, exact_lock, disk);
		if (retval)
			goto out_unregister_bdi;
	}

	/* 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);
	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));
		if (retval)
			goto out_device_del;
	}
	register_disk(parent, disk, groups);
	if (register_queue)
		blk_register_queue(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.
	 * avoid probable deadlock caused by allocating memory with
	 * GFP_KERNEL in runtime_resume callback of its all ancestor
	 * devices
	 */
	WARN_ON_ONCE(!blk_get_queue(disk->queue));
	pm_runtime_set_memalloc_noio(ddev, true);

	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) {
		retval = -ENOMEM;
		goto out_del_integrity;
	}
	disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
	if (!disk->slave_dir) {
		retval = -ENOMEM;
		goto out_put_holder_dir;
	}

	if (!(disk->flags & GENHD_FL_HIDDEN)) {
		retval = sysfs_create_link(&ddev->kobj,
			&disk->queue->backing_dev_info->dev->kobj, "bdi");
		if (retval)
			goto out_put_slave_dir;
	}

	if (register_queue) {
		retval = blk_register_queue(disk);
		if (retval)
			goto out_del_bdi_sysfs_link;
	}

	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))
@@ -893,6 +902,44 @@ 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);
	disk->slave_dir = NULL;
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));
	/*
	 * 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:
	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_free_ext_minor:
	blk_free_devt(devt);
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,
@@ -903,12 +950,29 @@ void device_add_disk(struct device *parent, struct gendisk *disk,
}
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;
@@ -1002,6 +1066,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;
@@ -1521,6 +1586,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
@@ -2351,19 +2419,11 @@ 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,
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);

static const struct attribute *disk_events_attrs[] = {
	&dev_attr_events.attr,
	&dev_attr_events_async.attr,
	&dev_attr_events_poll_msecs.attr,
	NULL,
};

/*
 * The default polling interval can be specified by the kernel
 * parameter block.events_dfl_poll_msecs which defaults to 0
@@ -2404,17 +2464,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);
@@ -2426,15 +2486,11 @@ 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)
{
	/* 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;

@@ -2458,8 +2514,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)
+2 −13
Original line number Diff line number Diff line
@@ -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);
@@ -1977,9 +1967,8 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)

		/*
		 * 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.
		 * 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);
+13 −0
Original line number Diff line number Diff line
@@ -307,15 +307,28 @@ extern bool disk_has_partitions(struct gendisk *disk);
extern unsigned int part_in_flight(struct hd_struct *part);
extern void device_add_disk(struct device *parent, struct gendisk *disk,
			    const struct attribute_group **groups);
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)
{
	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);