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.



 drivers/block/cciss.c     |    9 ++++++---
 drivers/block/genhd.c     |   19 +++++++++++--------
 drivers/block/ioctl.c     |   11 ++++++++---
 drivers/block/ll_rw_blk.c |    2 +-
 fs/block_dev.c            |    4 ++--
 fs/partitions/check.c     |   17 ++++++++++++++---
 include/linux/genhd.h     |    4 ++--
 7 files changed, 44 insertions(+), 22 deletions(-)

diff -puN drivers/block/genhd.c~dynamic-hd_struct-allocation drivers/block/genhd.c
--- 25/drivers/block/genhd.c~dynamic-hd_struct-allocation	2003-04-19 21:03:12.000000000 -0700
+++ 25-akpm/drivers/block/genhd.c	2003-04-19 21:27:31.000000000 -0700
@@ -365,11 +365,13 @@ static int show_partition(struct seq_fil
 		(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 *
 	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, i
 	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 *
 	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;
 }
diff -puN drivers/block/ioctl.c~dynamic-hd_struct-allocation drivers/block/ioctl.c
--- 25/drivers/block/ioctl.c~dynamic-hd_struct-allocation	2003-04-19 21:03:12.000000000 -0700
+++ 25-akpm/drivers/block/ioctl.c	2003-04-19 21:03:12.000000000 -0700
@@ -41,11 +41,14 @@ static int blkpg_ioctl(struct block_devi
 					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_devi
 			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);
diff -puN drivers/block/ll_rw_blk.c~dynamic-hd_struct-allocation drivers/block/ll_rw_blk.c
--- 25/drivers/block/ll_rw_blk.c~dynamic-hd_struct-allocation	2003-04-19 21:03:12.000000000 -0700
+++ 25-akpm/drivers/block/ll_rw_blk.c	2003-04-19 21:03:12.000000000 -0700
@@ -1869,7 +1869,7 @@ static inline void blk_partition_remap(s
 	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);
diff -puN fs/block_dev.c~dynamic-hd_struct-allocation fs/block_dev.c
--- 25/fs/block_dev.c~dynamic-hd_struct-allocation	2003-04-19 21:03:12.000000000 -0700
+++ 25-akpm/fs/block_dev.c	2003-04-19 21:03:12.000000000 -0700
@@ -559,10 +559,10 @@ static int do_open(struct block_device *
 			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;
diff -puN fs/partitions/check.c~dynamic-hd_struct-allocation fs/partitions/check.c
--- 25/fs/partitions/check.c~dynamic-hd_struct-allocation	2003-04-19 21:03:12.000000000 -0700
+++ 25-akpm/fs/partitions/check.c	2003-04-19 21:05:24.000000000 -0700
@@ -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 *di
 	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;
diff -puN include/linux/genhd.h~dynamic-hd_struct-allocation include/linux/genhd.h
--- 25/include/linux/genhd.h~dynamic-hd_struct-allocation	2003-04-19 21:03:12.000000000 -0700
+++ 25-akpm/include/linux/genhd.h	2003-04-19 21:03:12.000000000 -0700
@@ -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;
diff -puN drivers/block/cciss.c~dynamic-hd_struct-allocation drivers/block/cciss.c
--- 25/drivers/block/cciss.c~dynamic-hd_struct-allocation	2003-04-19 21:03:12.000000000 -0700
+++ 25-akpm/drivers/block/cciss.c	2003-04-19 21:03:12.000000000 -0700
@@ -599,9 +599,12 @@ static int cciss_ioctl(struct inode *ino
  		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)
- 				luninfo.num_parts++;
+ 		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;

_