Commit 00358933 authored by Tetsuo Handa's avatar Tetsuo Handa Committed by Jens Axboe
Browse files

brd: remove brd_devices_mutex mutex



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: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarLuis Chamberlain <mcgrof@kernel.org>
Link: https://lore.kernel.org/r/6b074af7-c165-4fab-b7da-8270a4f6f6cd@i-love.sakura.ne.jp


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent a6431e35
Loading
Loading
Loading
Loading
+30 −43
Original line number Diff line number Diff line
@@ -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,16 +431,20 @@ 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)
{
	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);
	mutex_lock(&brd_devices_mutex);
		list_del(&brd->brd_list);
	mutex_unlock(&brd_devices_mutex);
		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,16 +494,8 @@ 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)
	if (__register_blkdev(RAMDISK_MAJOR, "ramdisk", brd_probe)) {
		err = -EIO;
		goto out_free;
	}

@@ -508,11 +503,7 @@ static int __init brd_init(void)
	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");
}