aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-core.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/blk-core.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/blk-core.c')
-rw-r--r--block/blk-core.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index a0dc2e72fcbb..d6128d9ad601 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -60,7 +60,9 @@ static void drive_stat_acct(struct request *rq, int new_io)
60 if (!blk_fs_request(rq) || !rq->rq_disk) 60 if (!blk_fs_request(rq) || !rq->rq_disk)
61 return; 61 return;
62 62
63 part = disk_map_sector(rq->rq_disk, rq->sector); 63 rcu_read_lock();
64
65 part = disk_map_sector_rcu(rq->rq_disk, rq->sector);
64 if (!new_io) 66 if (!new_io)
65 __all_stat_inc(rq->rq_disk, part, merges[rw], rq->sector); 67 __all_stat_inc(rq->rq_disk, part, merges[rw], rq->sector);
66 else { 68 else {
@@ -71,6 +73,8 @@ static void drive_stat_acct(struct request *rq, int new_io)
71 part->in_flight++; 73 part->in_flight++;
72 } 74 }
73 } 75 }
76
77 rcu_read_unlock();
74} 78}
75 79
76void blk_queue_congestion_threshold(struct request_queue *q) 80void blk_queue_congestion_threshold(struct request_queue *q)
@@ -1557,12 +1561,14 @@ static int __end_that_request_first(struct request *req, int error,
1557 } 1561 }
1558 1562
1559 if (blk_fs_request(req) && req->rq_disk) { 1563 if (blk_fs_request(req) && req->rq_disk) {
1560 struct hd_struct *part =
1561 disk_map_sector(req->rq_disk, req->sector);
1562 const int rw = rq_data_dir(req); 1564 const int rw = rq_data_dir(req);
1565 struct hd_struct *part;
1563 1566
1567 rcu_read_lock();
1568 part = disk_map_sector_rcu(req->rq_disk, req->sector);
1564 all_stat_add(req->rq_disk, part, sectors[rw], 1569 all_stat_add(req->rq_disk, part, sectors[rw],
1565 nr_bytes >> 9, req->sector); 1570 nr_bytes >> 9, req->sector);
1571 rcu_read_unlock();
1566 } 1572 }
1567 1573
1568 total_bytes = bio_nbytes = 0; 1574 total_bytes = bio_nbytes = 0;
@@ -1746,7 +1752,11 @@ static void end_that_request_last(struct request *req, int error)
1746 if (disk && blk_fs_request(req) && req != &req->q->bar_rq) { 1752 if (disk && blk_fs_request(req) && req != &req->q->bar_rq) {
1747 unsigned long duration = jiffies - req->start_time; 1753 unsigned long duration = jiffies - req->start_time;
1748 const int rw = rq_data_dir(req); 1754 const int rw = rq_data_dir(req);
1749 struct hd_struct *part = disk_map_sector(disk, req->sector); 1755 struct hd_struct *part;
1756
1757 rcu_read_lock();
1758
1759 part = disk_map_sector_rcu(disk, req->sector);
1750 1760
1751 __all_stat_inc(disk, part, ios[rw], req->sector); 1761 __all_stat_inc(disk, part, ios[rw], req->sector);
1752 __all_stat_add(disk, part, ticks[rw], duration, req->sector); 1762 __all_stat_add(disk, part, ticks[rw], duration, req->sector);
@@ -1756,6 +1766,8 @@ static void end_that_request_last(struct request *req, int error)
1756 part_round_stats(part); 1766 part_round_stats(part);
1757 part->in_flight--; 1767 part->in_flight--;
1758 } 1768 }
1769
1770 rcu_read_unlock();
1759 } 1771 }
1760 1772
1761 if (req->end_io) 1773 if (req->end_io)