Commit 40602997 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

block: fix error unwinding in blk_register_queue



blk_register_queue fails to handle errors from blk_mq_sysfs_register,
leaks various resources on errors and accidentally sets queue refs percpu
refcount to percpu mode on kobject_add failure.  Fix all that by
properly unwinding on errors.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20221114042637.1009333-4-hch@lst.de


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 6fc75f30
Loading
Loading
Loading
Loading
+16 −12
Original line number Diff line number Diff line
@@ -823,13 +823,15 @@ int blk_register_queue(struct gendisk *disk)
	int ret;

	mutex_lock(&q->sysfs_dir_lock);

	ret = kobject_add(&q->kobj, &disk_to_dev(disk)->kobj, "queue");
	if (ret < 0)
		goto unlock;
		goto out_unlock_dir;

	if (queue_is_mq(q))
		blk_mq_sysfs_register(disk);
	if (queue_is_mq(q)) {
		ret = blk_mq_sysfs_register(disk);
		if (ret)
			goto out_del_queue_kobj;
	}
	mutex_lock(&q->sysfs_lock);

	mutex_lock(&q->debugfs_mutex);
@@ -841,17 +843,17 @@ int blk_register_queue(struct gendisk *disk)

	ret = disk_register_independent_access_ranges(disk);
	if (ret)
		goto put_dev;
		goto out_debugfs_remove;

	if (q->elevator) {
		ret = elv_register_queue(q, false);
		if (ret)
			goto put_dev;
			goto out_unregister_ia_ranges;
	}

	ret = blk_crypto_sysfs_register(disk);
	if (ret)
		goto put_dev;
		goto out_elv_unregister;

	blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q);
	wbt_enable_default(q);
@@ -862,8 +864,6 @@ int blk_register_queue(struct gendisk *disk)
	if (q->elevator)
		kobject_uevent(&q->elevator->kobj, KOBJ_ADD);
	mutex_unlock(&q->sysfs_lock);

unlock:
	mutex_unlock(&q->sysfs_dir_lock);

	/*
@@ -882,13 +882,17 @@ int blk_register_queue(struct gendisk *disk)

	return ret;

put_dev:
out_elv_unregister:
	elv_unregister_queue(q);
out_unregister_ia_ranges:
	disk_unregister_independent_access_ranges(disk);
out_debugfs_remove:
	blk_debugfs_remove(disk);
	mutex_unlock(&q->sysfs_lock);
	mutex_unlock(&q->sysfs_dir_lock);
out_del_queue_kobj:
	kobject_del(&q->kobj);

out_unlock_dir:
	mutex_unlock(&q->sysfs_dir_lock);
	return ret;
}