Commit 5fb58500 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Allocate hd_structs dynamically

From: Badari Pulavarty <pbadari@us.ibm.com>

Here is the patch to allocate hd_struct dynamically as we find
partitions.

There are 3 things I didn't like in the patch.

1) The patch allocates 15 pointers instead of 15 hd_structs.  (incase of
   s= csi).  I was really hoping to get rid of "15" and make it really
   dynamic.  (In ca= se if we ever want to support more than 15 partitions
   per disk etc..).=20 I was thought about making it a linked list, but
   blk_partition_remap() needs to get to hd_struct for a given partition
   everytime we do IO.  So linked list would be bad, we really need direct
   access to partition in= fo.

2) I had to add "partno" to hd_struct, since part_dev_read() used to calc=
   ulate partition number from the address before.

3) kmalloc() failure in add_partition() will be silently ignored.

It saves 2048 bytes per disk.
parent 88bdd4c3
......@@ -599,9 +599,12 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
luninfo.num_opens = drv->usage_count;
luninfo.num_parts = 0;
/* count partitions 1 to 15 with sizes > 0 */
for(i=1; i <MAX_PART; i++)
if (disk->part[i].nr_sects != 0)
for(i=1; i <MAX_PART; i++) {
if (!disk->part[i])
continue;
if (disk->part[i]->nr_sects != 0)
luninfo.num_parts++;
}
if (copy_to_user((void *) arg, &luninfo,
sizeof(LogvolInfo_struct)))
return -EFAULT;
......
......@@ -365,11 +365,13 @@ static int show_partition(struct seq_file *part, void *v)
(unsigned long long)get_capacity(sgp) >> 1,
disk_name(sgp, 0, buf));
for (n = 0; n < sgp->minors - 1; n++) {
if (sgp->part[n].nr_sects == 0)
if (!sgp->part[n])
continue;
if (sgp->part[n]->nr_sects == 0)
continue;
seq_printf(part, "%4d %4d %10llu %s\n",
sgp->major, n + 1 + sgp->first_minor,
(unsigned long long)sgp->part[n].nr_sects >> 1 ,
(unsigned long long)sgp->part[n]->nr_sects >> 1 ,
disk_name(sgp, n + 1, buf));
}
......@@ -552,7 +554,7 @@ struct gendisk *alloc_disk(int minors)
return NULL;
}
if (minors > 1) {
int size = (minors - 1) * sizeof(struct hd_struct);
int size = (minors - 1) * sizeof(struct hd_struct *);
disk->part = kmalloc(size, GFP_KERNEL);
if (!disk->part) {
kfree(disk);
......@@ -604,8 +606,8 @@ void set_device_ro(struct block_device *bdev, int flag)
struct gendisk *disk = bdev->bd_disk;
if (bdev->bd_contains != bdev) {
int part = bdev->bd_dev - MKDEV(disk->major, disk->first_minor);
struct hd_struct *p = &disk->part[part-1];
p->policy = flag;
struct hd_struct *p = disk->part[part-1];
if (p) p->policy = flag;
} else
disk->policy = flag;
}
......@@ -615,7 +617,7 @@ void set_disk_ro(struct gendisk *disk, int flag)
int i;
disk->policy = flag;
for (i = 0; i < disk->minors - 1; i++)
disk->part[i].policy = flag;
if (disk->part[i]) disk->part[i]->policy = flag;
}
int bdev_read_only(struct block_device *bdev)
......@@ -626,8 +628,9 @@ int bdev_read_only(struct block_device *bdev)
disk = bdev->bd_disk;
if (bdev->bd_contains != bdev) {
int part = bdev->bd_dev - MKDEV(disk->major, disk->first_minor);
struct hd_struct *p = &disk->part[part-1];
return p->policy;
struct hd_struct *p = disk->part[part-1];
if (p) return p->policy;
return 0;
} else
return disk->policy;
}
......
......@@ -41,11 +41,14 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
return -EINVAL;
}
/* partition number in use? */
if (disk->part[part - 1].nr_sects != 0)
if (disk->part[part - 1])
return -EBUSY;
/* overlap? */
for (i = 0; i < disk->minors - 1; i++) {
struct hd_struct *s = &disk->part[i];
struct hd_struct *s = disk->part[i];
if (!s)
continue;
if (!(start+length <= s->start_sect ||
start >= s->start_sect + s->nr_sects))
return -EBUSY;
......@@ -54,7 +57,9 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
add_partition(disk, part, start, length);
return 0;
case BLKPG_DEL_PARTITION:
if (disk->part[part - 1].nr_sects == 0)
if (!disk->part[part-1])
return -ENXIO;
if (disk->part[part - 1]->nr_sects == 0)
return -ENXIO;
/* partition in use? Incomplete check for now. */
bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part);
......
......@@ -1841,7 +1841,7 @@ static inline void blk_partition_remap(struct bio *bio)
if (bdev == bdev->bd_contains)
return;
p = &disk->part[bdev->bd_dev-MKDEV(disk->major,disk->first_minor)-1];
p = disk->part[bdev->bd_dev-MKDEV(disk->major,disk->first_minor)-1];
switch (bio->bi_rw) {
case READ:
p->read_sectors += bio_sectors(bio);
......
......@@ -559,10 +559,10 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
bdev->bd_contains = whole;
down(&whole->bd_sem);
whole->bd_part_count++;
p = disk->part + part - 1;
p = disk->part[part - 1];
bdev->bd_inode->i_data.backing_dev_info =
whole->bd_inode->i_data.backing_dev_info;
if (!(disk->flags & GENHD_FL_UP) || !p->nr_sects) {
if (!(disk->flags & GENHD_FL_UP) || !p || !p->nr_sects) {
whole->bd_part_count--;
up(&whole->bd_sem);
ret = -ENXIO;
......
......@@ -182,7 +182,7 @@ static struct sysfs_ops part_sysfs_ops = {
static ssize_t part_dev_read(struct hd_struct * p, char *page)
{
struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
int part = p - disk->part + 1;
int part = p->partno;
dev_t base = MKDEV(disk->major, disk->first_minor);
return sprintf(page, "%04x\n", (unsigned)(base + part));
}
......@@ -234,7 +234,9 @@ struct kobj_type ktype_part = {
void delete_partition(struct gendisk *disk, int part)
{
struct hd_struct *p = disk->part + part - 1;
struct hd_struct *p = disk->part[part-1];
if (!p)
return;
if (!p->nr_sects)
return;
p->start_sect = 0;
......@@ -242,14 +244,23 @@ void delete_partition(struct gendisk *disk, int part)
p->reads = p->writes = p->read_sectors = p->write_sectors = 0;
devfs_remove("%s/part%d", disk->devfs_name, part);
kobject_unregister(&p->kobj);
disk->part[part-1] = NULL;
kfree(p);
}
void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
{
struct hd_struct *p = disk->part + part - 1;
struct hd_struct *p;
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return;
memset(p, 0, sizeof(*p));
p->start_sect = start;
p->nr_sects = len;
p->partno = part;
disk->part[part-1] = p;
devfs_register_partition(disk, part);
snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
p->kobj.parent = &disk->kobj;
......
......@@ -64,7 +64,7 @@ struct hd_struct {
sector_t nr_sects;
struct kobject kobj;
unsigned reads, read_sectors, writes, write_sectors;
int policy;
int policy, partno;
};
#define GENHD_FL_REMOVABLE 1
......@@ -89,7 +89,7 @@ struct gendisk {
int minor_shift; /* number of times minor is shifted to
get real minor */
char disk_name[16]; /* name of major driver */
struct hd_struct *part; /* [indexed by minor] */
struct hd_struct **part; /* [indexed by minor] */
struct block_device_operations *fops;
struct request_queue *queue;
void *private_data;
......
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