block: fix error unwinding in blk_register_queue
authorChristoph Hellwig <hch@lst.de>
Mon, 14 Nov 2022 04:26:35 +0000 (05:26 +0100)
committerJens Axboe <axboe@kernel.dk>
Wed, 30 Nov 2022 18:09:00 +0000 (11:09 -0700)
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: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20221114042637.1009333-4-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-sysfs.c

index 197646d479b4a034e529b76f75194a1b4c30f6c2..abd1784ff05e3fd63c1bfebae7f924b67d154ede 100644 (file)
@@ -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 @@ unlock:
 
        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;
 }