summaryrefslogtreecommitdiffstats
path: root/block/genhd.c
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2012-08-01 06:24:18 -0400
committerJens Axboe <axboe@kernel.dk>2012-08-01 06:24:18 -0400
commitc83f6bf98dc1f1a194118b3830706cebbebda8c4 (patch)
treeea8fbd925584f784164617964a9f025bda16ed15 /block/genhd.c
parent4638a83e8615de9c16c39dfed234951d0f468cf1 (diff)
block: add partition resize function to blkpg ioctl
Add a new operation code (BLKPG_RESIZE_PARTITION) to the BLKPG ioctl that allows altering the size of an existing partition, even if it is currently in use. This patch converts hd_struct->nr_sects into sequence counter because One might extend a partition while IO is happening to it and update of nr_sects can be non-atomic on 32bit machines with 64bit sector_t. This can lead to issues like reading inconsistent size of a partition. Sequence counter have been used so that readers don't have to take bdev mutex lock as we call sector_in_part() very frequently. Now all the access to hd_struct->nr_sects should happen using sequence counter read/update helper functions part_nr_sects_read/part_nr_sects_write. There is one exception though, set_capacity()/get_capacity(). I think theoritically race should exist there too but this patch does not modify set_capacity()/get_capacity() due to sheer number of call sites and I am afraid that change might break something. I have left that as a TODO item. We can handle it later if need be. This patch does not introduce any new races as such w.r.t set_capacity()/get_capacity(). v2: Add CONFIG_LBDAF test to UP preempt case as suggested by Phillip. Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Phillip Susi <psusi@ubuntu.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/genhd.c')
-rw-r--r--block/genhd.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/block/genhd.c b/block/genhd.c
index 9cf5583c90ff..cac7366957c3 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -154,7 +154,7 @@ struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter)
154 part = rcu_dereference(ptbl->part[piter->idx]); 154 part = rcu_dereference(ptbl->part[piter->idx]);
155 if (!part) 155 if (!part)
156 continue; 156 continue;
157 if (!part->nr_sects && 157 if (!part_nr_sects_read(part) &&
158 !(piter->flags & DISK_PITER_INCL_EMPTY) && 158 !(piter->flags & DISK_PITER_INCL_EMPTY) &&
159 !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 && 159 !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 &&
160 piter->idx == 0)) 160 piter->idx == 0))
@@ -191,7 +191,7 @@ EXPORT_SYMBOL_GPL(disk_part_iter_exit);
191static inline int sector_in_part(struct hd_struct *part, sector_t sector) 191static inline int sector_in_part(struct hd_struct *part, sector_t sector)
192{ 192{
193 return part->start_sect <= sector && 193 return part->start_sect <= sector &&
194 sector < part->start_sect + part->nr_sects; 194 sector < part->start_sect + part_nr_sects_read(part);
195} 195}
196 196
197/** 197/**
@@ -769,8 +769,8 @@ void __init printk_all_partitions(void)
769 769
770 printk("%s%s %10llu %s %s", is_part0 ? "" : " ", 770 printk("%s%s %10llu %s %s", is_part0 ? "" : " ",
771 bdevt_str(part_devt(part), devt_buf), 771 bdevt_str(part_devt(part), devt_buf),
772 (unsigned long long)part->nr_sects >> 1, 772 (unsigned long long)part_nr_sects_read(part) >> 1
773 disk_name(disk, part->partno, name_buf), 773 , disk_name(disk, part->partno, name_buf),
774 uuid_buf); 774 uuid_buf);
775 if (is_part0) { 775 if (is_part0) {
776 if (disk->driverfs_dev != NULL && 776 if (disk->driverfs_dev != NULL &&
@@ -862,7 +862,7 @@ static int show_partition(struct seq_file *seqf, void *v)
862 while ((part = disk_part_iter_next(&piter))) 862 while ((part = disk_part_iter_next(&piter)))
863 seq_printf(seqf, "%4d %7d %10llu %s\n", 863 seq_printf(seqf, "%4d %7d %10llu %s\n",
864 MAJOR(part_devt(part)), MINOR(part_devt(part)), 864 MAJOR(part_devt(part)), MINOR(part_devt(part)),
865 (unsigned long long)part->nr_sects >> 1, 865 (unsigned long long)part_nr_sects_read(part) >> 1,
866 disk_name(sgp, part->partno, buf)); 866 disk_name(sgp, part->partno, buf));
867 disk_part_iter_exit(&piter); 867 disk_part_iter_exit(&piter);
868 868
@@ -1268,6 +1268,16 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
1268 } 1268 }
1269 disk->part_tbl->part[0] = &disk->part0; 1269 disk->part_tbl->part[0] = &disk->part0;
1270 1270
1271 /*
1272 * set_capacity() and get_capacity() currently don't use
1273 * seqcounter to read/update the part0->nr_sects. Still init
1274 * the counter as we can read the sectors in IO submission
1275 * patch using seqence counters.
1276 *
1277 * TODO: Ideally set_capacity() and get_capacity() should be
1278 * converted to make use of bd_mutex and sequence counters.
1279 */
1280 seqcount_init(&disk->part0.nr_sects_seq);
1271 hd_ref_init(&disk->part0); 1281 hd_ref_init(&disk->part0);
1272 1282
1273 disk->minors = minors; 1283 disk->minors = minors;