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

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
...@@ -438,19 +438,18 @@ static const struct block_device_operations brd_fops = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
*part = 0; if (new)
*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) ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment