]> git.itanic.dy.fi Git - linux-stable/commitdiff
brd: remove brd_devices_mutex mutex
authorTetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Thu, 6 Jan 2022 09:53:16 +0000 (18:53 +0900)
committerJens Axboe <axboe@kernel.dk>
Mon, 17 Jan 2022 14:19:40 +0000 (07:19 -0700)
If brd_alloc() from brd_probe() is called before brd_alloc() from
brd_init() is called, module loading will fail with -EEXIST error.
To close this race, call __register_blkdev() just before leaving
brd_init().

Then, we can remove brd_devices_mutex mutex, for brd_device list
will no longer be accessed concurrently.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Link: https://lore.kernel.org/r/6b074af7-c165-4fab-b7da-8270a4f6f6cd@i-love.sakura.ne.jp
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/brd.c

index 8fe2e4289dae390d53c8607b36da88084e84a07a..6e3f2f0d235209c6994ef67fc7dc45aadaad3e1b 100644 (file)
@@ -362,7 +362,6 @@ __setup("ramdisk_size=", ramdisk_size);
  * (should share code eventually).
  */
 static LIST_HEAD(brd_devices);
-static DEFINE_MUTEX(brd_devices_mutex);
 static struct dentry *brd_debugfs_dir;
 
 static int brd_alloc(int i)
@@ -372,21 +371,14 @@ static int brd_alloc(int i)
        char buf[DISK_NAME_LEN];
        int err = -ENOMEM;
 
-       mutex_lock(&brd_devices_mutex);
-       list_for_each_entry(brd, &brd_devices, brd_list) {
-               if (brd->brd_number == i) {
-                       mutex_unlock(&brd_devices_mutex);
+       list_for_each_entry(brd, &brd_devices, brd_list)
+               if (brd->brd_number == i)
                        return -EEXIST;
-               }
-       }
        brd = kzalloc(sizeof(*brd), GFP_KERNEL);
-       if (!brd) {
-               mutex_unlock(&brd_devices_mutex);
+       if (!brd)
                return -ENOMEM;
-       }
        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);
@@ -429,9 +421,7 @@ static int brd_alloc(int i)
 out_cleanup_disk:
        blk_cleanup_disk(disk);
 out_free_dev:
-       mutex_lock(&brd_devices_mutex);
        list_del(&brd->brd_list);
-       mutex_unlock(&brd_devices_mutex);
        kfree(brd);
        return err;
 }
@@ -441,15 +431,19 @@ static void brd_probe(dev_t dev)
        brd_alloc(MINOR(dev) / max_part);
 }
 
-static void brd_del_one(struct brd_device *brd)
+static void brd_cleanup(void)
 {
-       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);
+       struct brd_device *brd, *next;
+
+       debugfs_remove_recursive(brd_debugfs_dir);
+
+       list_for_each_entry_safe(brd, next, &brd_devices, brd_list) {
+               del_gendisk(brd->brd_disk);
+               blk_cleanup_disk(brd->brd_disk);
+               brd_free_pages(brd);
+               list_del(&brd->brd_list);
+               kfree(brd);
+       }
 }
 
 static inline void brd_check_and_reset_par(void)
@@ -473,9 +467,18 @@ static inline void brd_check_and_reset_par(void)
 
 static int __init brd_init(void)
 {
-       struct brd_device *brd, *next;
        int err, i;
 
+       brd_check_and_reset_par();
+
+       brd_debugfs_dir = debugfs_create_dir("ramdisk_pages", NULL);
+
+       for (i = 0; i < rd_nr; i++) {
+               err = brd_alloc(i);
+               if (err)
+                       goto out_free;
+       }
+
        /*
         * brd module now has a feature to instantiate underlying device
         * structure on-demand, provided that there is an access dev node.
@@ -491,28 +494,16 @@ static int __init brd_init(void)
         *      dynamically.
         */
 
-       if (__register_blkdev(RAMDISK_MAJOR, "ramdisk", brd_probe))
-               return -EIO;
-
-       brd_check_and_reset_par();
-
-       brd_debugfs_dir = debugfs_create_dir("ramdisk_pages", NULL);
-
-       for (i = 0; i < rd_nr; i++) {
-               err = brd_alloc(i);
-               if (err)
-                       goto out_free;
+       if (__register_blkdev(RAMDISK_MAJOR, "ramdisk", brd_probe)) {
+               err = -EIO;
+               goto 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);
+       brd_cleanup();
 
        pr_info("brd: module NOT loaded !!!\n");
        return err;
@@ -520,13 +511,9 @@ static int __init brd_init(void)
 
 static void __exit brd_exit(void)
 {
-       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);
+       brd_cleanup();
 
        pr_info("brd: module unloaded\n");
 }