aboutsummaryrefslogtreecommitdiffstats
path: root/block/ioctl.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-09-03 03:03:02 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:06 -0400
commite71bf0d0ee89e51b92776391c5634938236977d5 (patch)
tree9fc62352a40ad388deebdd8ed497cab926cf0470 /block/ioctl.c
parentf331c0296f2a9fee0d396a70598b954062603015 (diff)
block: fix disk->part[] dereferencing race
disk->part[] is protected by its matching bdev's lock. However, non-critical accesses like collecting stats and printing out sysfs and proc information used to be performed without any locking. As partitions can come and go dynamically, partitions can go away underneath those non-critical accesses. As some of those accesses are writes, this theoretically can lead to silent corruption. This patch fixes the race by using RCU for the partition array and dev reference counter to hold partitions. * Rename disk->part[] to disk->__part[] to make sure no one outside genhd layer proper accesses it directly. * Use RCU for disk->__part[] dereferencing. * Implement disk_{get|put}_part() which can be used to get and put partitions from gendisk respectively. * Iterators are implemented to help iterate through all partitions safely. * Functions which require RCU readlock are marked with _rcu suffix. * Use disk_put_part() in __blkdev_put() instead of directly putting the contained kobject. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block/ioctl.c')
-rw-r--r--block/ioctl.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/block/ioctl.c b/block/ioctl.c
index 403f7d7e0c28..a5f672ad55f6 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -12,11 +12,12 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
12{ 12{
13 struct block_device *bdevp; 13 struct block_device *bdevp;
14 struct gendisk *disk; 14 struct gendisk *disk;
15 struct hd_struct *part;
15 struct blkpg_ioctl_arg a; 16 struct blkpg_ioctl_arg a;
16 struct blkpg_partition p; 17 struct blkpg_partition p;
18 struct disk_part_iter piter;
17 long long start, length; 19 long long start, length;
18 int partno; 20 int partno;
19 int i;
20 int err; 21 int err;
21 22
22 if (!capable(CAP_SYS_ADMIN)) 23 if (!capable(CAP_SYS_ADMIN))
@@ -47,28 +48,33 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
47 mutex_lock(&bdev->bd_mutex); 48 mutex_lock(&bdev->bd_mutex);
48 49
49 /* overlap? */ 50 /* overlap? */
50 for (i = 0; i < disk_max_parts(disk); i++) { 51 disk_part_iter_init(&piter, disk,
51 struct hd_struct *s = disk->part[i]; 52 DISK_PITER_INCL_EMPTY);
52 53 while ((part = disk_part_iter_next(&piter))) {
53 if (!s) 54 if (!(start + length <= part->start_sect ||
54 continue; 55 start >= part->start_sect + part->nr_sects)) {
55 if (!(start+length <= s->start_sect || 56 disk_part_iter_exit(&piter);
56 start >= s->start_sect + s->nr_sects)) {
57 mutex_unlock(&bdev->bd_mutex); 57 mutex_unlock(&bdev->bd_mutex);
58 return -EBUSY; 58 return -EBUSY;
59 } 59 }
60 } 60 }
61 disk_part_iter_exit(&piter);
62
61 /* all seems OK */ 63 /* all seems OK */
62 err = add_partition(disk, partno, start, length, 64 err = add_partition(disk, partno, start, length,
63 ADDPART_FLAG_NONE); 65 ADDPART_FLAG_NONE);
64 mutex_unlock(&bdev->bd_mutex); 66 mutex_unlock(&bdev->bd_mutex);
65 return err; 67 return err;
66 case BLKPG_DEL_PARTITION: 68 case BLKPG_DEL_PARTITION:
67 if (!disk->part[partno - 1]) 69 part = disk_get_part(disk, partno);
70 if (!part)
68 return -ENXIO; 71 return -ENXIO;
69 bdevp = bdget_disk(disk, partno); 72
73 bdevp = bdget(part_devt(part));
74 disk_put_part(part);
70 if (!bdevp) 75 if (!bdevp)
71 return -ENOMEM; 76 return -ENOMEM;
77
72 mutex_lock(&bdevp->bd_mutex); 78 mutex_lock(&bdevp->bd_mutex);
73 if (bdevp->bd_openers) { 79 if (bdevp->bd_openers) {
74 mutex_unlock(&bdevp->bd_mutex); 80 mutex_unlock(&bdevp->bd_mutex);