brd: reduce the brd_devices_mutex scope
authorTetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Tue, 7 Sep 2021 10:18:00 +0000 (19:18 +0900)
committerJens Axboe <axboe@kernel.dk>
Sun, 17 Oct 2021 12:51:19 +0000 (06:51 -0600)
As with commit 8b52d8be86d72308 ("loop: reorder loop_exit"),
unregister_blkdev() needs to be called first in order to avoid calling
brd_alloc() from brd_probe() after brd_del_one() from brd_exit(). Then,
we can avoid holding global mutex during add_disk()/del_gendisk() as with
commit 1c500ad706383f1a ("loop: reduce the loop_ctl_mutex scope").

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/e205f13d-18ff-a49c-0988-7de6ea5ff823@i-love.sakura.ne.jp
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/brd.c

index 58ec167..530b312 100644 (file)
@@ -373,10 +373,22 @@ static int brd_alloc(int i)
        struct gendisk *disk;
        char buf[DISK_NAME_LEN];
 
        struct gendisk *disk;
        char buf[DISK_NAME_LEN];
 
+       mutex_lock(&brd_devices_mutex);
+       list_for_each_entry(brd, &brd_devices, brd_list) {
+               if (brd->brd_number == i) {
+                       mutex_unlock(&brd_devices_mutex);
+                       return -EEXIST;
+               }
+       }
        brd = kzalloc(sizeof(*brd), GFP_KERNEL);
        brd = kzalloc(sizeof(*brd), GFP_KERNEL);
-       if (!brd)
+       if (!brd) {
+               mutex_unlock(&brd_devices_mutex);
                return -ENOMEM;
                return -ENOMEM;
+       }
        brd->brd_number         = i;
        brd->brd_number         = i;
+       list_add_tail(&brd->brd_list, &brd_devices);
+       mutex_unlock(&brd_devices_mutex);
+
        spin_lock_init(&brd->brd_lock);
        INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
 
        spin_lock_init(&brd->brd_lock);
        INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
 
@@ -411,37 +423,30 @@ static int brd_alloc(int i)
        blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
        blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue);
        add_disk(disk);
        blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
        blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue);
        add_disk(disk);
-       list_add_tail(&brd->brd_list, &brd_devices);
 
        return 0;
 
 out_free_dev:
 
        return 0;
 
 out_free_dev:
+       mutex_lock(&brd_devices_mutex);
+       list_del(&brd->brd_list);
+       mutex_unlock(&brd_devices_mutex);
        kfree(brd);
        return -ENOMEM;
 }
 
 static void brd_probe(dev_t dev)
 {
        kfree(brd);
        return -ENOMEM;
 }
 
 static void brd_probe(dev_t dev)
 {
-       int i = MINOR(dev) / max_part;
-       struct brd_device *brd;
-
-       mutex_lock(&brd_devices_mutex);
-       list_for_each_entry(brd, &brd_devices, brd_list) {
-               if (brd->brd_number == i)
-                       goto out_unlock;
-       }
-
-       brd_alloc(i);
-out_unlock:
-       mutex_unlock(&brd_devices_mutex);
+       brd_alloc(MINOR(dev) / max_part);
 }
 
 static void brd_del_one(struct brd_device *brd)
 {
 }
 
 static void brd_del_one(struct brd_device *brd)
 {
-       list_del(&brd->brd_list);
        del_gendisk(brd->brd_disk);
        blk_cleanup_disk(brd->brd_disk);
        brd_free_pages(brd);
        del_gendisk(brd->brd_disk);
        blk_cleanup_disk(brd->brd_disk);
        brd_free_pages(brd);
+       mutex_lock(&brd_devices_mutex);
+       list_del(&brd->brd_list);
+       mutex_unlock(&brd_devices_mutex);
        kfree(brd);
 }
 
        kfree(brd);
 }
 
@@ -491,25 +496,21 @@ static int __init brd_init(void)
 
        brd_debugfs_dir = debugfs_create_dir("ramdisk_pages", NULL);
 
 
        brd_debugfs_dir = debugfs_create_dir("ramdisk_pages", NULL);
 
-       mutex_lock(&brd_devices_mutex);
        for (i = 0; i < rd_nr; i++) {
                err = brd_alloc(i);
                if (err)
                        goto out_free;
        }
 
        for (i = 0; i < rd_nr; i++) {
                err = brd_alloc(i);
                if (err)
                        goto out_free;
        }
 
-       mutex_unlock(&brd_devices_mutex);
-
        pr_info("brd: module loaded\n");
        return 0;
 
 out_free:
        pr_info("brd: module loaded\n");
        return 0;
 
 out_free:
+       unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
        debugfs_remove_recursive(brd_debugfs_dir);
 
        list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
                brd_del_one(brd);
        debugfs_remove_recursive(brd_debugfs_dir);
 
        list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
                brd_del_one(brd);
-       mutex_unlock(&brd_devices_mutex);
-       unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
 
        pr_info("brd: module NOT loaded !!!\n");
        return err;
 
        pr_info("brd: module NOT loaded !!!\n");
        return err;
@@ -519,13 +520,12 @@ static void __exit brd_exit(void)
 {
        struct brd_device *brd, *next;
 
 {
        struct brd_device *brd, *next;
 
+       unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
        debugfs_remove_recursive(brd_debugfs_dir);
 
        list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
                brd_del_one(brd);
 
        debugfs_remove_recursive(brd_debugfs_dir);
 
        list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
                brd_del_one(brd);
 
-       unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
-
        pr_info("brd: module unloaded\n");
 }
 
        pr_info("brd: module unloaded\n");
 }