summaryrefslogtreecommitdiffstats
path: root/fs/partitions
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-08-25 12:56:15 +0200
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 08:56:08 +0200
commit540eed5637b766bb1e881ef744c42617760b4815 (patch)
tree8bdf54967a8290f780216f767291623e67ee7e9b /fs/partitions
parentblock: move stats from disk to part0 (diff)
downloadlinux-540eed5637b766bb1e881ef744c42617760b4815.tar.xz
linux-540eed5637b766bb1e881ef744c42617760b4815.zip
block: make partition array dynamic
disk->__part used to be statically allocated to the maximum possible number of partitions. This patch makes partition array allocation dynamic. The added overhead is minimal as only real change is one memory dereference changed to RCU one. This saves both a bit of memory and cpu cycles iterating through unoccupied slots and makes increasing partition limit easier. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/partitions')
-rw-r--r--fs/partitions/check.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index f517869e8d10..772b2ed8d239 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -312,14 +312,18 @@ static void delete_partition_rcu_cb(struct rcu_head *head)
void delete_partition(struct gendisk *disk, int partno)
{
+ struct disk_part_tbl *ptbl = disk->part_tbl;
struct hd_struct *part;
- part = disk->__part[partno];
+ if (partno >= ptbl->len)
+ return;
+
+ part = ptbl->part[partno];
if (!part)
return;
blk_free_devt(part_devt(part));
- rcu_assign_pointer(disk->__part[partno], NULL);
+ rcu_assign_pointer(ptbl->part[partno], NULL);
kobject_put(part->holder_dir);
device_del(part_to_dev(part));
@@ -341,10 +345,16 @@ int add_partition(struct gendisk *disk, int partno,
dev_t devt = MKDEV(0, 0);
struct device *ddev = disk_to_dev(disk);
struct device *pdev;
+ struct disk_part_tbl *ptbl;
const char *dname;
int err;
- if (disk->__part[partno])
+ err = disk_expand_part_tbl(disk, partno);
+ if (err)
+ return err;
+ ptbl = disk->part_tbl;
+
+ if (ptbl->part[partno])
return -EBUSY;
p = kzalloc(sizeof(*p), GFP_KERNEL);
@@ -398,7 +408,7 @@ int add_partition(struct gendisk *disk, int partno,
/* everything is up and running, commence */
INIT_RCU_HEAD(&p->rcu_head);
- rcu_assign_pointer(disk->__part[partno], p);
+ rcu_assign_pointer(ptbl->part[partno], p);
/* suppress uevent if the disk supresses it */
if (!ddev->uevent_suppress)
@@ -487,7 +497,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
struct disk_part_iter piter;
struct hd_struct *part;
struct parsed_partitions *state;
- int p, res;
+ int p, highest, res;
if (bdev->bd_part_count)
return -EBUSY;
@@ -511,6 +521,17 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
/* tell userspace that the media / partition table may have changed */
kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
+ /* Detect the highest partition number and preallocate
+ * disk->part_tbl. This is an optimization and not strictly
+ * necessary.
+ */
+ for (p = 1, highest = 0; p < state->limit; p++)
+ if (state->parts[p].size)
+ highest = p;
+
+ disk_expand_part_tbl(disk, highest);
+
+ /* add partitions */
for (p = 1; p < state->limit; p++) {
sector_t size = state->parts[p].size;
sector_t from = state->parts[p].from;