summaryrefslogtreecommitdiff
path: root/fs/partitions
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-08-25 19:56:15 +0900
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 08:56:08 +0200
commit540eed5637b766bb1e881ef744c42617760b4815 (patch)
tree8bdf54967a8290f780216f767291623e67ee7e9b /fs/partitions
parent074a7aca7afa6f230104e8e65eba3420263714a5 (diff)
downloadlinux-3.10-540eed5637b766bb1e881ef744c42617760b4815.tar.gz
linux-3.10-540eed5637b766bb1e881ef744c42617760b4815.tar.bz2
linux-3.10-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 f517869e8d1..772b2ed8d23 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;