Commit d7536161 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] split "gendisk" to be per-disk, part 1

now that gendisks don't have shared stuff (we used to set blk_size[]
from ->sizes) we can start splitting them into per-disk ones.

Step 1:
  we introduce a new field - ->first_minor (to be merged with ->major
  into dev_t of entire disk once all gendisks are split).  All arrays
  are assumed to start at that minor (i.e.  gd->part[minor] got replaced
  with gd->part[minor - gd->first_minor], etc.).  get_gendisk() is
  taught to pick the right gendisk if there are several with the same
  major.
parent 143fe0af
......@@ -86,7 +86,7 @@ int add_partition(struct block_device *bdev, struct blkpg_partition *p)
g = get_gendisk(dev);
if (!g)
return -ENXIO;
part = g->part + minor(dev);
part = g->part + minor(dev) - g->first_minor;
/* existing drive? */
......@@ -135,7 +135,7 @@ int del_partition(struct block_device *bdev, struct blkpg_partition *p)
g = get_gendisk(dev);
if (!g)
return -ENXIO;
part = g->part + minor(dev);
part = g->part + minor(dev) - g->first_minor;
if (bdev != bdev->bd_contains)
return -EINVAL;
......
......@@ -104,15 +104,22 @@ struct gendisk *
get_gendisk(kdev_t dev)
{
struct gendisk *gp = NULL;
int maj = major(dev);
int major = major(dev);
int minor = minor(dev);
read_lock(&gendisk_lock);
for (gp = gendisk_head; gp; gp = gp->next)
if (gp->major == maj)
break;
for (gp = gendisk_head; gp; gp = gp->next) {
if (gp->major != major)
continue;
if (gp->first_minor > minor)
continue;
if (gp->first_minor + (1<<gp->minor_shift) <= minor)
continue;
read_unlock(&gendisk_lock);
return gp;
}
read_unlock(&gendisk_lock);
return gp;
return NULL;
}
EXPORT_SYMBOL(get_gendisk);
......@@ -158,8 +165,9 @@ static int show_partition(struct seq_file *part, void *v)
if ((n & minormask) && sgp->part[n].nr_sects == 0)
continue;
seq_printf(part, "%4d %4d %10ld %s\n",
sgp->major, n, sgp->part[n].nr_sects << 1,
disk_name(sgp, n, buf));
sgp->major, n + sgp->first_minor,
sgp->part[n].nr_sects << 1,
disk_name(sgp, n + sgp->first_minor, buf));
}
return 0;
......
......@@ -599,9 +599,10 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
bdev->bd_offset = 0;
if (g) {
bdev->bd_inode->i_size =
(loff_t) g->part[minor(dev)].nr_sects << 9;
bdev->bd_offset = g->part[minor(dev)].start_sect;
struct hd_struct *p;
p = g->part + minor(dev) - g->first_minor;
bdev->bd_inode->i_size = (loff_t) p->nr_sects << 9;
bdev->bd_offset = p->start_sect;
} else if (blk_size[major(dev)])
bdev->bd_inode->i_size =
(loff_t) blk_size[major(dev)][minor(dev)] << 10;
......
......@@ -107,11 +107,13 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
const char *maj = hd->major_name;
unsigned int unit = (minor >> hd->minor_shift);
unsigned int part = (minor & ((1 << hd->minor_shift) -1 ));
struct hd_struct *p = hd->part + minor - hd->first_minor;
if ((unit < hd->nr_real) && hd->part[minor].de) {
if ((((minor - hd->first_minor) >> hd->minor_shift) < hd->nr_real) &&
p->de) {
int pos;
pos = devfs_generate_path (hd->part[minor].de, buf, 64);
pos = devfs_generate_path(p->de, buf, 64);
if (pos >= 0)
return buf + pos;
}
......@@ -230,13 +232,13 @@ static struct driver_file_entry partition_device_type_file = {
void driverfs_create_partitions(struct gendisk *hd, int minor)
{
int pos = -1;
int devnum = minor >> hd->minor_shift;
int devnum = (minor - hd->first_minor) >> hd->minor_shift;
char dirname[256];
struct device *parent = 0;
int max_p;
int part;
devfs_handle_t dir = 0;
struct hd_struct *p = hd->part + minor;
struct hd_struct *p = hd->part + minor - hd->first_minor;
/* get parent driverfs device structure */
if (hd->driverfs_dev_arr)
......@@ -308,7 +310,7 @@ void driverfs_remove_partitions(struct gendisk *hd, int minor)
int max_p;
int part;
struct device * current_driverfs_dev;
struct hd_struct *p = hd->part + minor;
struct hd_struct *p = hd->part + minor - hd->first_minor;
max_p=(1 << hd->minor_shift);
......@@ -335,31 +337,17 @@ void driverfs_remove_partitions(struct gendisk *hd, int minor)
static void check_partition(struct gendisk *hd, kdev_t dev)
{
devfs_handle_t de = NULL;
unsigned long first_sector;
struct block_device *bdev;
char buf[64];
struct parsed_partitions *state;
int i;
first_sector = hd->part[minor(dev)].start_sect;
/*
* This is a kludge to allow the partition check to be
* skipped for specific drives (e.g. IDE CD-ROM drives)
*/
if ((int)first_sector == -1) {
hd->part[minor(dev)].start_sect = 0;
return;
}
if (first_sector != 0)
BUG();
state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
if (!state)
return;
if (hd->de_arr)
de = hd->de_arr[minor(dev) >> hd->minor_shift];
de = hd->de_arr[(minor(dev)-hd->first_minor)>>hd->minor_shift];
i = devfs_generate_path (de, buf, sizeof buf);
if (i >= 0) {
printk(KERN_INFO " /dev/%s:", buf + i);
......@@ -377,6 +365,7 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
state->limit = 1<<hd->minor_shift;
for (i = 0; check_part[i]; i++) {
int res, j;
struct hd_struct *p;
memset(&state->parts, 0, sizeof(state->parts));
res = check_part[i](state, bdev);
if (!res)
......@@ -385,12 +374,11 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
if (warn_no_part)
printk(" unable to read partition table\n");
goto setup_devfs;
}
}
p = hd->part + minor(dev) - hd->first_minor;
for (j = 1; j < state->limit; j++) {
hd->part[j + minor(dev)].start_sect =
state->parts[j].from;
hd->part[j + minor(dev)].nr_sects =
state->parts[j].size;
p[j].start_sect = state->parts[j].from;
p[j].nr_sects = state->parts[j].size;
#if CONFIG_BLK_DEV_MD
if (!state->parts[j].flags)
continue;
......@@ -411,22 +399,24 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
#ifdef CONFIG_DEVFS_FS
static void devfs_register_partition (struct gendisk *dev, int minor, int part)
{
int devnum = minor >> dev->minor_shift;
int devnum = (minor - dev->first_minor) >> dev->minor_shift;
devfs_handle_t dir;
unsigned int devfs_flags = DEVFS_FL_DEFAULT;
struct hd_struct *p = dev->part + minor - dev->first_minor;
char devname[16];
if (dev->part[minor + part].de) return;
dir = devfs_get_parent (dev->part[minor].de);
if (!dir) return;
if (p[part].de)
return;
dir = devfs_get_parent(p[0].de);
if (!dir)
return;
if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
devfs_flags |= DEVFS_FL_REMOVABLE;
sprintf (devname, "part%d", part);
dev->part[minor + part].de =
devfs_register (dir, devname, devfs_flags,
dev->major, minor + part,
S_IFBLK | S_IRUSR | S_IWUSR,
dev->fops, NULL);
p[part].de = devfs_register (dir, devname, devfs_flags,
dev->major, minor + part,
S_IFBLK | S_IRUSR | S_IWUSR,
dev->fops, NULL);
}
static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
......@@ -434,38 +424,40 @@ static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
static void devfs_register_disc (struct gendisk *dev, int minor)
{
int pos = 0;
int devnum = minor >> dev->minor_shift;
int devnum = (minor - dev->first_minor) >> dev->minor_shift;
devfs_handle_t dir, slave;
unsigned int devfs_flags = DEVFS_FL_DEFAULT;
char dirname[64], symlink[16];
static devfs_handle_t devfs_handle;
struct hd_struct *p = dev->part + minor - dev->first_minor;
if (dev->part[minor].de) return;
if (p[0].de)
return;
if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
devfs_flags |= DEVFS_FL_REMOVABLE;
if (dev->de_arr) {
dir = dev->de_arr[devnum];
if (!dir) /* Aware driver wants to block disc management */
return;
pos = devfs_generate_path (dir, dirname + 3, sizeof dirname-3);
if (pos < 0) return;
strncpy (dirname + pos, "../", 3);
}
else {
pos = devfs_generate_path(dir, dirname + 3, sizeof dirname-3);
if (pos < 0)
return;
strncpy(dirname + pos, "../", 3);
} else {
/* Unaware driver: construct "real" directory */
sprintf (dirname, "../%s/disc%d", dev->major_name, devnum);
dir = devfs_mk_dir (NULL, dirname + 3, NULL);
sprintf(dirname, "../%s/disc%d", dev->major_name,
(dev->first_minor >> dev->minor_shift) + devnum);
dir = devfs_mk_dir(NULL, dirname + 3, NULL);
}
if (!devfs_handle)
devfs_handle = devfs_mk_dir (NULL, "discs", NULL);
dev->part[minor].number = devfs_alloc_unique_number (&disc_numspace);
sprintf (symlink, "disc%d", dev->part[minor].number);
devfs_handle = devfs_mk_dir(NULL, "discs", NULL);
p[0].number = devfs_alloc_unique_number (&disc_numspace);
sprintf(symlink, "disc%d", p[0].number);
devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT,
dirname + pos, &slave, NULL);
dev->part[minor].de =
devfs_register (dir, "disc", devfs_flags, dev->major, minor,
p[0].de = devfs_register (dir, "disc", devfs_flags, dev->major, minor,
S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL);
devfs_auto_unregister (dev->part[minor].de, slave);
devfs_auto_unregister(p[0].de, slave);
if (!dev->de_arr)
devfs_auto_unregister (slave, dir);
}
......@@ -475,23 +467,23 @@ void devfs_register_partitions (struct gendisk *dev, int minor, int unregister)
{
#ifdef CONFIG_DEVFS_FS
int part, max_p;
struct hd_struct *p = dev->part + minor - dev->first_minor;
if (!unregister)
devfs_register_disc (dev, minor);
max_p = (1 << dev->minor_shift);
for (part = 1; part < max_p; part++) {
if ( unregister || (dev->part[part + minor].nr_sects < 1) ) {
devfs_unregister (dev->part[part + minor].de);
dev->part[part + minor].de = NULL;
if ( unregister || (p[part].nr_sects < 1) ) {
devfs_unregister(p[part].de);
dev->part[p].de = NULL;
continue;
}
devfs_register_partition (dev, minor, part);
}
if (unregister) {
devfs_unregister (dev->part[minor].de);
dev->part[minor].de = NULL;
devfs_dealloc_unique_number (&disc_numspace,
dev->part[minor].number);
devfs_unregister(p[0].de);
p[0].de = NULL;
devfs_dealloc_unique_number(&disc_numspace, p[0].number);
}
#endif /* CONFIG_DEVFS_FS */
}
......@@ -516,8 +508,9 @@ void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors,
void grok_partitions(kdev_t dev, long size)
{
int i, minors, first_minor, end_minor;
int minors, first_minor, end_minor;
struct gendisk *g = get_gendisk(dev);
struct hd_struct *p;
if (!g)
return;
......@@ -531,7 +524,8 @@ void grok_partitions(kdev_t dev, long size)
}
end_minor = first_minor + minors;
g->part[first_minor].nr_sects = size;
p = g->part + first_minor - g->first_minor;
p[0].nr_sects = size;
/* No minors to use for partitions */
if (minors == 1)
......@@ -572,6 +566,7 @@ int wipe_partitions(kdev_t dev)
struct gendisk *g;
kdev_t devp;
int p, major, minor, minor0, max_p, res;
struct hd_struct *part;
g = get_gendisk(dev);
if (g == NULL)
......@@ -584,19 +579,20 @@ int wipe_partitions(kdev_t dev)
if (minor0 != minor) /* for now only whole-disk reread */
return -EINVAL; /* %%% later.. */
part = g->part + minor - g->first_minor;
/* invalidate stuff */
for (p = max_p - 1; p >= 0; p--) {
minor = minor0 + p;
devp = mk_kdev(major,minor);
#if 0 /* %%% superfluous? */
if (g->part[minor].nr_sects == 0)
if (part[p].nr_sects == 0)
continue;
#endif
res = invalidate_device(devp, 1);
if (res)
return res;
g->part[minor].start_sect = 0;
g->part[minor].nr_sects = 0;
part[p].start_sect = 0;
part[p].nr_sects = 0;
}
return 0;
}
......@@ -70,6 +70,7 @@ struct hd_struct {
struct gendisk {
int major; /* major number of driver */
int first_minor;
const char *major_name; /* name of major driver */
int minor_shift; /* number of times minor is shifted to
get real minor */
......
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