From: Badari Pulavarty 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. drivers/block/cciss.c | 9 ++++++--- drivers/block/genhd.c | 19 +++++++++++-------- drivers/block/ioctl.c | 8 +++++--- drivers/block/ll_rw_blk.c | 2 +- fs/block_dev.c | 4 ++-- fs/partitions/check.c | 22 +++++++++++++++++----- include/linux/genhd.h | 4 ++-- 7 files changed, 44 insertions(+), 24 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-03 18:21:00.000000000 -0800 +++ 25-akpm/drivers/block/genhd.c 2003-04-03 18:21:00.000000000 -0800 @@ -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)); } @@ -540,7 +542,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); @@ -592,8 +594,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; } @@ -603,7 +605,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) @@ -614,8 +616,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-03 18:21:00.000000000 -0800 +++ 25-akpm/drivers/block/ioctl.c 2003-04-03 18:21:00.000000000 -0800 @@ -41,11 +41,11 @@ 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 (!(start+length <= s->start_sect || start >= s->start_sect + s->nr_sects)) return -EBUSY; @@ -54,7 +54,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-03 18:21:00.000000000 -0800 +++ 25-akpm/drivers/block/ll_rw_blk.c 2003-04-03 18:21:00.000000000 -0800 @@ -1867,7 +1867,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-03 18:21:00.000000000 -0800 +++ 25-akpm/fs/block_dev.c 2003-04-03 18:21:00.000000000 -0800 @@ -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-03 18:21:00.000000000 -0800 +++ 25-akpm/fs/partitions/check.c 2003-04-03 18:21:00.000000000 -0800 @@ -103,8 +103,8 @@ char *disk_name(struct gendisk *hd, int } sprintf(buf, "%s", hd->disk_name); } else { - if (hd->part[part-1].de) { - pos = devfs_generate_path(hd->part[part-1].de, buf, 64); + if (hd->part[part-1]->de) { + pos = devfs_generate_path(hd->part[part-1]->de, buf, 64); if (pos >= 0) return buf + pos; } @@ -203,7 +203,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)); } @@ -255,7 +255,9 @@ static 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; @@ -264,12 +266,19 @@ void delete_partition(struct gendisk *di devfs_unregister(p->de); p->de = NULL; 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(struct hd_struct), GFP_KERNEL); + if (!p) + return; + + memset(p, 0, sizeof(struct hd_struct)); p->start_sect = start; p->nr_sects = len; devfs_register_partition(disk, part); @@ -277,6 +286,9 @@ void add_partition(struct gendisk *disk, p->kobj.parent = &disk->kobj; p->kobj.ktype = &ktype_part; kobject_register(&p->kobj); + + p->partno = part; + disk->part[part-1] = p; } static void disk_sysfs_symlinks(struct gendisk *disk) 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-03 18:21:00.000000000 -0800 +++ 25-akpm/include/linux/genhd.h 2003-04-03 18:21:00.000000000 -0800 @@ -63,7 +63,7 @@ struct hd_struct { devfs_handle_t de; /* primary (master) devfs entry */ 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;