Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 937af5ec authored by Boaz Harrosh's avatar Boaz Harrosh Committed by Jens Axboe
Browse files

brd: Fix all partitions BUGs



This patch fixes up brd's partitions scheme, now enjoying all worlds.

The MAIN fix here is that currently, if one fdisks some partitions,
a BAD bug will make all partitions point to the same start-end sector
ie: 0 - brd_size And an mkfs of any partition would trash the partition
table and the other partition.

Another fix is that "mount -U uuid" will not work if show_part was not
specified, because of the GENHD_FL_SUPPRESS_PARTITION_INFO flag.
We now always load without it and remove the show_part parameter.

[We remove Dmitry's new module-param part_show it is now always
 show]

So NOW the logic goes like this:
* max_part - Just says how many minors to reserve between ramX
  devices. In any way, there can be as many partition as requested.
  If minors between devices ends, then dynamic 259-major ids will
  be allocated on the fly.
  The default is now max_part=1, which means all partitions devt(s)
  will be from the dynamic (259) major-range.
  (If persistent partition minors is needed use max_part=X)
  For example with /dev/sdX max_part is hard coded 16.

* Creation of new devices on the fly still/always work:
  mknod /path/devnod b 1 X
  fdisk -l /path/devnod
  Will create a new device if [X / max_part] was not already
  created before. (Just as before)

  partitions on the dynamically created device will work as well
  Same logic applies with minors as with the pre-created ones.

TODO: dynamic grow of device size. So each device can have it's
      own size.

CC: Dmitry Monakhov <dmonakhov@openvz.org>
Tested-by: default avatarRoss Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: default avatarBoaz Harrosh <boaz@plexistor.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent d4119ee0
Loading
Loading
Loading
Loading
+38 −62
Original line number Original line Diff line number Diff line
@@ -438,19 +438,18 @@ static const struct block_device_operations brd_fops = {
/*
/*
 * And now the modules code and kernel interface.
 * And now the modules code and kernel interface.
 */
 */
static int rd_nr;
static int rd_nr = CONFIG_BLK_DEV_RAM_COUNT;
int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
static int max_part;
static int part_shift;
static int part_show = 0;
module_param(rd_nr, int, S_IRUGO);
module_param(rd_nr, int, S_IRUGO);
MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");
MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");

int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
module_param(rd_size, int, S_IRUGO);
module_param(rd_size, int, S_IRUGO);
MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");

static int max_part = 1;
module_param(max_part, int, S_IRUGO);
module_param(max_part, int, S_IRUGO);
MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
MODULE_PARM_DESC(max_part, "Num Minors to reserve between devices");
module_param(part_show, int, S_IRUGO);

MODULE_PARM_DESC(part_show, "Control RAM disk visibility in /proc/partitions");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
MODULE_ALIAS("rd");
MODULE_ALIAS("rd");
@@ -496,16 +495,15 @@ static struct brd_device *brd_alloc(int i)
	brd->brd_queue->limits.discard_zeroes_data = 1;
	brd->brd_queue->limits.discard_zeroes_data = 1;
	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue);
	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue);


	disk = brd->brd_disk = alloc_disk(1 << part_shift);
	disk = brd->brd_disk = alloc_disk(max_part);
	if (!disk)
	if (!disk)
		goto out_free_queue;
		goto out_free_queue;
	disk->major		= RAMDISK_MAJOR;
	disk->major		= RAMDISK_MAJOR;
	disk->first_minor	= i << part_shift;
	disk->first_minor	= i * max_part;
	disk->fops		= &brd_fops;
	disk->fops		= &brd_fops;
	disk->private_data	= brd;
	disk->private_data	= brd;
	disk->queue		= brd->brd_queue;
	disk->queue		= brd->brd_queue;
	if (!part_show)
	disk->flags		= GENHD_FL_EXT_DEVT;
		disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
	sprintf(disk->disk_name, "ram%d", i);
	sprintf(disk->disk_name, "ram%d", i);
	set_capacity(disk, rd_size * 2);
	set_capacity(disk, rd_size * 2);


@@ -527,10 +525,11 @@ static void brd_free(struct brd_device *brd)
	kfree(brd);
	kfree(brd);
}
}


static struct brd_device *brd_init_one(int i)
static struct brd_device *brd_init_one(int i, bool *new)
{
{
	struct brd_device *brd;
	struct brd_device *brd;


	*new = false;
	list_for_each_entry(brd, &brd_devices, brd_list) {
	list_for_each_entry(brd, &brd_devices, brd_list) {
		if (brd->brd_number == i)
		if (brd->brd_number == i)
			goto out;
			goto out;
@@ -541,6 +540,7 @@ static struct brd_device *brd_init_one(int i)
		add_disk(brd->brd_disk);
		add_disk(brd->brd_disk);
		list_add_tail(&brd->brd_list, &brd_devices);
		list_add_tail(&brd->brd_list, &brd_devices);
	}
	}
	*new = true;
out:
out:
	return brd;
	return brd;
}
}
@@ -556,70 +556,46 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data)
{
{
	struct brd_device *brd;
	struct brd_device *brd;
	struct kobject *kobj;
	struct kobject *kobj;
	bool new;


	mutex_lock(&brd_devices_mutex);
	mutex_lock(&brd_devices_mutex);
	brd = brd_init_one(MINOR(dev) >> part_shift);
	brd = brd_init_one(MINOR(dev) / max_part, &new);
	kobj = brd ? get_disk(brd->brd_disk) : NULL;
	kobj = brd ? get_disk(brd->brd_disk) : NULL;
	mutex_unlock(&brd_devices_mutex);
	mutex_unlock(&brd_devices_mutex);


	if (new)
		*part = 0;
		*part = 0;

	return kobj;
	return kobj;
}
}


static int __init brd_init(void)
static int __init brd_init(void)
{
{
	int i, nr;
	unsigned long range;
	struct brd_device *brd, *next;
	struct brd_device *brd, *next;
	int i;


	/*
	/*
	 * brd module now has a feature to instantiate underlying device
	 * brd module now has a feature to instantiate underlying device
	 * structure on-demand, provided that there is an access dev node.
	 * structure on-demand, provided that there is an access dev node.
	 * However, this will not work well with user space tool that doesn't
	 * know about such "feature".  In order to not break any existing
	 * tool, we do the following:
	 *
	 *
	 * (1) if rd_nr is specified, create that many upfront, and this
	 * (1) if rd_nr is specified, create that many upfront. else
	 *     also becomes a hard limit.
	 *     it defaults to CONFIG_BLK_DEV_RAM_COUNT
	 * (2) if rd_nr is not specified, create CONFIG_BLK_DEV_RAM_COUNT
	 * (2) User can further extend brd devices by create dev node themselves
	 *     (default 16) rd device on module load, user can further
	 *     and have kernel automatically instantiate actual device
	 *     extend brd device by create dev node themselves and have
	 *     on-demand. Example:
	 *     kernel automatically instantiate actual device on-demand.
	 *		mknod /path/devnod_name b 1 X	# 1 is the rd major
	 *		fdisk -l /path/devnod_name
	 *	If (X / max_part) was not already created it will be created
	 *	dynamically.
	 */
	 */


	part_shift = 0;
	if (max_part > 0) {
		part_shift = fls(max_part);

		/*
		 * Adjust max_part according to part_shift as it is exported
		 * to user space so that user can decide correct minor number
		 * if [s]he want to create more devices.
		 *
		 * Note that -1 is required because partition 0 is reserved
		 * for the whole disk.
		 */
		max_part = (1UL << part_shift) - 1;
	}

	if ((1UL << part_shift) > DISK_MAX_PARTS)
		return -EINVAL;

	if (rd_nr > 1UL << (MINORBITS - part_shift))
		return -EINVAL;

	if (rd_nr) {
		nr = rd_nr;
		range = rd_nr << part_shift;
	} else {
		nr = CONFIG_BLK_DEV_RAM_COUNT;
		range = 1UL << MINORBITS;
	}

	if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
	if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
		return -EIO;
		return -EIO;


	for (i = 0; i < nr; i++) {
	if (unlikely(!max_part))
		max_part = 1;

	for (i = 0; i < rd_nr; i++) {
		brd = brd_alloc(i);
		brd = brd_alloc(i);
		if (!brd)
		if (!brd)
			goto out_free;
			goto out_free;
@@ -631,10 +607,10 @@ static int __init brd_init(void)
	list_for_each_entry(brd, &brd_devices, brd_list)
	list_for_each_entry(brd, &brd_devices, brd_list)
		add_disk(brd->brd_disk);
		add_disk(brd->brd_disk);


	blk_register_region(MKDEV(RAMDISK_MAJOR, 0), range,
	blk_register_region(MKDEV(RAMDISK_MAJOR, 0), 1UL << MINORBITS,
				  THIS_MODULE, brd_probe, NULL, NULL);
				  THIS_MODULE, brd_probe, NULL, NULL);


	printk(KERN_INFO "brd: module loaded\n");
	pr_info("brd: module loaded\n");
	return 0;
	return 0;


out_free:
out_free:
@@ -644,21 +620,21 @@ static int __init brd_init(void)
	}
	}
	unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
	unregister_blkdev(RAMDISK_MAJOR, "ramdisk");


	pr_info("brd: module NOT loaded !!!\n");
	return -ENOMEM;
	return -ENOMEM;
}
}


static void __exit brd_exit(void)
static void __exit brd_exit(void)
{
{
	unsigned long range;
	struct brd_device *brd, *next;
	struct brd_device *brd, *next;


	range = rd_nr ? rd_nr << part_shift : 1UL << MINORBITS;

	list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
	list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
		brd_del_one(brd);
		brd_del_one(brd);


	blk_unregister_region(MKDEV(RAMDISK_MAJOR, 0), range);
	blk_unregister_region(MKDEV(RAMDISK_MAJOR, 0), 1UL << MINORBITS);
	unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
	unregister_blkdev(RAMDISK_MAJOR, "ramdisk");

	pr_info("brd: module unloaded\n");
}
}


module_init(brd_init);
module_init(brd_init);