aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-08-25 06:47:21 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:06 -0400
commitc9959059161ddd7bf4670cf47367033d6b2f79c4 (patch)
tree6454db55f8e34361fe472358e10e0c5cfac1e366
parente71bf0d0ee89e51b92776391c5634938236977d5 (diff)
block: fix diskstats access
There are two variants of stat functions - ones prefixed with double underbars which don't care about preemption and ones without which disable preemption before manipulating per-cpu counters. It's unclear whether the underbarred ones assume that preemtion is disabled on entry as some callers don't do that. This patch unifies diskstats access by implementing disk_stat_lock() and disk_stat_unlock() which take care of both RCU (for partition access) and preemption (for per-cpu counter access). diskstats access should always be enclosed between the two functions. As such, there's no need for the versions which disables preemption. They're removed and double underbars ones are renamed to drop the underbars. As an extra argument is added, there's no danger of using the old version unconverted. disk_stat_lock() uses get_cpu() and returns the cpu index and all diskstat functions which access per-cpu counters now has @cpu argument to help RT. This change adds RCU or preemption operations at some places but also collapses several preemption ops into one at others. Overall, the performance difference should be negligible as all involved ops are very lightweight per-cpu ones. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--block/blk-core.c52
-rw-r--r--block/blk-merge.c11
-rw-r--r--block/genhd.c20
-rw-r--r--drivers/block/aoe/aoecmd.c15
-rw-r--r--drivers/md/dm.c26
-rw-r--r--drivers/md/linear.c7
-rw-r--r--drivers/md/multipath.c7
-rw-r--r--drivers/md/raid0.c7
-rw-r--r--drivers/md/raid1.c8
-rw-r--r--drivers/md/raid10.c7
-rw-r--r--drivers/md/raid5.c8
-rw-r--r--fs/partitions/check.c7
-rw-r--r--include/linux/genhd.h139
13 files changed, 158 insertions, 156 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index d6128d9ad601..e0a5ee36849c 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -56,25 +56,26 @@ static void drive_stat_acct(struct request *rq, int new_io)
56{ 56{
57 struct hd_struct *part; 57 struct hd_struct *part;
58 int rw = rq_data_dir(rq); 58 int rw = rq_data_dir(rq);
59 int cpu;
59 60
60 if (!blk_fs_request(rq) || !rq->rq_disk) 61 if (!blk_fs_request(rq) || !rq->rq_disk)
61 return; 62 return;
62 63
63 rcu_read_lock(); 64 cpu = disk_stat_lock();
64
65 part = disk_map_sector_rcu(rq->rq_disk, rq->sector); 65 part = disk_map_sector_rcu(rq->rq_disk, rq->sector);
66
66 if (!new_io) 67 if (!new_io)
67 __all_stat_inc(rq->rq_disk, part, merges[rw], rq->sector); 68 all_stat_inc(cpu, rq->rq_disk, part, merges[rw], rq->sector);
68 else { 69 else {
69 disk_round_stats(rq->rq_disk); 70 disk_round_stats(cpu, rq->rq_disk);
70 rq->rq_disk->in_flight++; 71 rq->rq_disk->in_flight++;
71 if (part) { 72 if (part) {
72 part_round_stats(part); 73 part_round_stats(cpu, part);
73 part->in_flight++; 74 part->in_flight++;
74 } 75 }
75 } 76 }
76 77
77 rcu_read_unlock(); 78 disk_stat_unlock();
78} 79}
79 80
80void blk_queue_congestion_threshold(struct request_queue *q) 81void blk_queue_congestion_threshold(struct request_queue *q)
@@ -997,7 +998,7 @@ static inline void add_request(struct request_queue *q, struct request *req)
997 * /proc/diskstats. This accounts immediately for all queue usage up to 998 * /proc/diskstats. This accounts immediately for all queue usage up to
998 * the current jiffies and restarts the counters again. 999 * the current jiffies and restarts the counters again.
999 */ 1000 */
1000void disk_round_stats(struct gendisk *disk) 1001void disk_round_stats(int cpu, struct gendisk *disk)
1001{ 1002{
1002 unsigned long now = jiffies; 1003 unsigned long now = jiffies;
1003 1004
@@ -1005,15 +1006,15 @@ void disk_round_stats(struct gendisk *disk)
1005 return; 1006 return;
1006 1007
1007 if (disk->in_flight) { 1008 if (disk->in_flight) {
1008 __disk_stat_add(disk, time_in_queue, 1009 disk_stat_add(cpu, disk, time_in_queue,
1009 disk->in_flight * (now - disk->stamp)); 1010 disk->in_flight * (now - disk->stamp));
1010 __disk_stat_add(disk, io_ticks, (now - disk->stamp)); 1011 disk_stat_add(cpu, disk, io_ticks, (now - disk->stamp));
1011 } 1012 }
1012 disk->stamp = now; 1013 disk->stamp = now;
1013} 1014}
1014EXPORT_SYMBOL_GPL(disk_round_stats); 1015EXPORT_SYMBOL_GPL(disk_round_stats);
1015 1016
1016void part_round_stats(struct hd_struct *part) 1017void part_round_stats(int cpu, struct hd_struct *part)
1017{ 1018{
1018 unsigned long now = jiffies; 1019 unsigned long now = jiffies;
1019 1020
@@ -1021,9 +1022,9 @@ void part_round_stats(struct hd_struct *part)
1021 return; 1022 return;
1022 1023
1023 if (part->in_flight) { 1024 if (part->in_flight) {
1024 __part_stat_add(part, time_in_queue, 1025 part_stat_add(cpu, part, time_in_queue,
1025 part->in_flight * (now - part->stamp)); 1026 part->in_flight * (now - part->stamp));
1026 __part_stat_add(part, io_ticks, (now - part->stamp)); 1027 part_stat_add(cpu, part, io_ticks, (now - part->stamp));
1027 } 1028 }
1028 part->stamp = now; 1029 part->stamp = now;
1029} 1030}
@@ -1563,12 +1564,13 @@ static int __end_that_request_first(struct request *req, int error,
1563 if (blk_fs_request(req) && req->rq_disk) { 1564 if (blk_fs_request(req) && req->rq_disk) {
1564 const int rw = rq_data_dir(req); 1565 const int rw = rq_data_dir(req);
1565 struct hd_struct *part; 1566 struct hd_struct *part;
1567 int cpu;
1566 1568
1567 rcu_read_lock(); 1569 cpu = disk_stat_lock();
1568 part = disk_map_sector_rcu(req->rq_disk, req->sector); 1570 part = disk_map_sector_rcu(req->rq_disk, req->sector);
1569 all_stat_add(req->rq_disk, part, sectors[rw], 1571 all_stat_add(cpu, req->rq_disk, part, sectors[rw],
1570 nr_bytes >> 9, req->sector); 1572 nr_bytes >> 9, req->sector);
1571 rcu_read_unlock(); 1573 disk_stat_unlock();
1572 } 1574 }
1573 1575
1574 total_bytes = bio_nbytes = 0; 1576 total_bytes = bio_nbytes = 0;
@@ -1753,21 +1755,21 @@ static void end_that_request_last(struct request *req, int error)
1753 unsigned long duration = jiffies - req->start_time; 1755 unsigned long duration = jiffies - req->start_time;
1754 const int rw = rq_data_dir(req); 1756 const int rw = rq_data_dir(req);
1755 struct hd_struct *part; 1757 struct hd_struct *part;
1758 int cpu;
1756 1759
1757 rcu_read_lock(); 1760 cpu = disk_stat_lock();
1758
1759 part = disk_map_sector_rcu(disk, req->sector); 1761 part = disk_map_sector_rcu(disk, req->sector);
1760 1762
1761 __all_stat_inc(disk, part, ios[rw], req->sector); 1763 all_stat_inc(cpu, disk, part, ios[rw], req->sector);
1762 __all_stat_add(disk, part, ticks[rw], duration, req->sector); 1764 all_stat_add(cpu, disk, part, ticks[rw], duration, req->sector);
1763 disk_round_stats(disk); 1765 disk_round_stats(cpu, disk);
1764 disk->in_flight--; 1766 disk->in_flight--;
1765 if (part) { 1767 if (part) {
1766 part_round_stats(part); 1768 part_round_stats(cpu, part);
1767 part->in_flight--; 1769 part->in_flight--;
1768 } 1770 }
1769 1771
1770 rcu_read_unlock(); 1772 disk_stat_unlock();
1771 } 1773 }
1772 1774
1773 if (req->end_io) 1775 if (req->end_io)
diff --git a/block/blk-merge.c b/block/blk-merge.c
index eb2a3ca58303..d926a24bf1fd 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -388,18 +388,19 @@ static int attempt_merge(struct request_queue *q, struct request *req,
388 388
389 if (req->rq_disk) { 389 if (req->rq_disk) {
390 struct hd_struct *part; 390 struct hd_struct *part;
391 int cpu;
391 392
392 rcu_read_lock(); 393 cpu = disk_stat_lock();
393
394 part = disk_map_sector_rcu(req->rq_disk, req->sector); 394 part = disk_map_sector_rcu(req->rq_disk, req->sector);
395 disk_round_stats(req->rq_disk); 395
396 disk_round_stats(cpu, req->rq_disk);
396 req->rq_disk->in_flight--; 397 req->rq_disk->in_flight--;
397 if (part) { 398 if (part) {
398 part_round_stats(part); 399 part_round_stats(cpu, part);
399 part->in_flight--; 400 part->in_flight--;
400 } 401 }
401 402
402 rcu_read_unlock(); 403 disk_stat_unlock();
403 } 404 }
404 405
405 req->ioprio = ioprio_best(req->ioprio, next->ioprio); 406 req->ioprio = ioprio_best(req->ioprio, next->ioprio);
diff --git a/block/genhd.c b/block/genhd.c
index b431d6543942..430626e440f0 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -633,10 +633,11 @@ static ssize_t disk_stat_show(struct device *dev,
633 struct device_attribute *attr, char *buf) 633 struct device_attribute *attr, char *buf)
634{ 634{
635 struct gendisk *disk = dev_to_disk(dev); 635 struct gendisk *disk = dev_to_disk(dev);
636 int cpu;
636 637
637 preempt_disable(); 638 cpu = disk_stat_lock();
638 disk_round_stats(disk); 639 disk_round_stats(cpu, disk);
639 preempt_enable(); 640 disk_stat_unlock();
640 return sprintf(buf, 641 return sprintf(buf,
641 "%8lu %8lu %8llu %8u " 642 "%8lu %8lu %8llu %8u "
642 "%8lu %8lu %8llu %8u " 643 "%8lu %8lu %8llu %8u "
@@ -749,6 +750,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)
749 struct disk_part_iter piter; 750 struct disk_part_iter piter;
750 struct hd_struct *hd; 751 struct hd_struct *hd;
751 char buf[BDEVNAME_SIZE]; 752 char buf[BDEVNAME_SIZE];
753 int cpu;
752 754
753 /* 755 /*
754 if (&gp->dev.kobj.entry == block_class.devices.next) 756 if (&gp->dev.kobj.entry == block_class.devices.next)
@@ -758,9 +760,9 @@ static int diskstats_show(struct seq_file *seqf, void *v)
758 "\n\n"); 760 "\n\n");
759 */ 761 */
760 762
761 preempt_disable(); 763 cpu = disk_stat_lock();
762 disk_round_stats(gp); 764 disk_round_stats(cpu, gp);
763 preempt_enable(); 765 disk_stat_unlock();
764 seq_printf(seqf, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n", 766 seq_printf(seqf, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
765 MAJOR(disk_devt(gp)), MINOR(disk_devt(gp)), 767 MAJOR(disk_devt(gp)), MINOR(disk_devt(gp)),
766 disk_name(gp, 0, buf), 768 disk_name(gp, 0, buf),
@@ -777,9 +779,9 @@ static int diskstats_show(struct seq_file *seqf, void *v)
777 /* now show all non-0 size partitions of it */ 779 /* now show all non-0 size partitions of it */
778 disk_part_iter_init(&piter, gp, 0); 780 disk_part_iter_init(&piter, gp, 0);
779 while ((hd = disk_part_iter_next(&piter))) { 781 while ((hd = disk_part_iter_next(&piter))) {
780 preempt_disable(); 782 cpu = disk_stat_lock();
781 part_round_stats(hd); 783 part_round_stats(cpu, hd);
782 preempt_enable(); 784 disk_stat_unlock();
783 seq_printf(seqf, "%4d %4d %s %lu %lu %llu " 785 seq_printf(seqf, "%4d %4d %s %lu %lu %llu "
784 "%u %lu %lu %llu %u %u %u %u\n", 786 "%u %lu %lu %llu %u %u %u %u\n",
785 MAJOR(part_devt(hd)), MINOR(part_devt(hd)), 787 MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 84c03d65dcc5..17eed8c025d0 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -756,16 +756,17 @@ diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector
756 unsigned long n_sect = bio->bi_size >> 9; 756 unsigned long n_sect = bio->bi_size >> 9;
757 const int rw = bio_data_dir(bio); 757 const int rw = bio_data_dir(bio);
758 struct hd_struct *part; 758 struct hd_struct *part;
759 int cpu;
759 760
760 rcu_read_lock(); 761 cpu = disk_stat_lock();
761
762 part = disk_map_sector_rcu(disk, sector); 762 part = disk_map_sector_rcu(disk, sector);
763 all_stat_inc(disk, part, ios[rw], sector);
764 all_stat_add(disk, part, ticks[rw], duration, sector);
765 all_stat_add(disk, part, sectors[rw], n_sect, sector);
766 all_stat_add(disk, part, io_ticks, duration, sector);
767 763
768 rcu_read_unlock(); 764 all_stat_inc(cpu, disk, part, ios[rw], sector);
765 all_stat_add(cpu, disk, part, ticks[rw], duration, sector);
766 all_stat_add(cpu, disk, part, sectors[rw], n_sect, sector);
767 all_stat_add(cpu, disk, part, io_ticks, duration, sector);
768
769 disk_stat_unlock();
769} 770}
770 771
771void 772void
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index a78caad29996..653624792eaf 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -377,12 +377,13 @@ static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
377static void start_io_acct(struct dm_io *io) 377static void start_io_acct(struct dm_io *io)
378{ 378{
379 struct mapped_device *md = io->md; 379 struct mapped_device *md = io->md;
380 int cpu;
380 381
381 io->start_time = jiffies; 382 io->start_time = jiffies;
382 383
383 preempt_disable(); 384 cpu = disk_stat_lock();
384 disk_round_stats(dm_disk(md)); 385 disk_round_stats(cpu, dm_disk(md));
385 preempt_enable(); 386 disk_stat_unlock();
386 dm_disk(md)->in_flight = atomic_inc_return(&md->pending); 387 dm_disk(md)->in_flight = atomic_inc_return(&md->pending);
387} 388}
388 389
@@ -391,15 +392,15 @@ static int end_io_acct(struct dm_io *io)
391 struct mapped_device *md = io->md; 392 struct mapped_device *md = io->md;
392 struct bio *bio = io->bio; 393 struct bio *bio = io->bio;
393 unsigned long duration = jiffies - io->start_time; 394 unsigned long duration = jiffies - io->start_time;
394 int pending; 395 int pending, cpu;
395 int rw = bio_data_dir(bio); 396 int rw = bio_data_dir(bio);
396 397
397 preempt_disable(); 398 cpu = disk_stat_lock();
398 disk_round_stats(dm_disk(md)); 399 disk_round_stats(cpu, dm_disk(md));
399 preempt_enable(); 400 disk_stat_add(cpu, dm_disk(md), ticks[rw], duration);
400 dm_disk(md)->in_flight = pending = atomic_dec_return(&md->pending); 401 disk_stat_unlock();
401 402
402 disk_stat_add(dm_disk(md), ticks[rw], duration); 403 dm_disk(md)->in_flight = pending = atomic_dec_return(&md->pending);
403 404
404 return !pending; 405 return !pending;
405} 406}
@@ -885,6 +886,7 @@ static int dm_request(struct request_queue *q, struct bio *bio)
885 int r = -EIO; 886 int r = -EIO;
886 int rw = bio_data_dir(bio); 887 int rw = bio_data_dir(bio);
887 struct mapped_device *md = q->queuedata; 888 struct mapped_device *md = q->queuedata;
889 int cpu;
888 890
889 /* 891 /*
890 * There is no use in forwarding any barrier request since we can't 892 * There is no use in forwarding any barrier request since we can't
@@ -897,8 +899,10 @@ static int dm_request(struct request_queue *q, struct bio *bio)
897 899
898 down_read(&md->io_lock); 900 down_read(&md->io_lock);
899 901
900 disk_stat_inc(dm_disk(md), ios[rw]); 902 cpu = disk_stat_lock();
901 disk_stat_add(dm_disk(md), sectors[rw], bio_sectors(bio)); 903 disk_stat_inc(cpu, dm_disk(md), ios[rw]);
904 disk_stat_add(cpu, dm_disk(md), sectors[rw], bio_sectors(bio));
905 disk_stat_unlock();
902 906
903 /* 907 /*
904 * If we're suspended we have to queue 908 * If we're suspended we have to queue
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index b1eebf88c209..00cbc8e47294 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -318,14 +318,17 @@ static int linear_make_request (struct request_queue *q, struct bio *bio)
318 mddev_t *mddev = q->queuedata; 318 mddev_t *mddev = q->queuedata;
319 dev_info_t *tmp_dev; 319 dev_info_t *tmp_dev;
320 sector_t block; 320 sector_t block;
321 int cpu;
321 322
322 if (unlikely(bio_barrier(bio))) { 323 if (unlikely(bio_barrier(bio))) {
323 bio_endio(bio, -EOPNOTSUPP); 324 bio_endio(bio, -EOPNOTSUPP);
324 return 0; 325 return 0;
325 } 326 }
326 327
327 disk_stat_inc(mddev->gendisk, ios[rw]); 328 cpu = disk_stat_lock();
328 disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio)); 329 disk_stat_inc(cpu, mddev->gendisk, ios[rw]);
330 disk_stat_add(cpu, mddev->gendisk, sectors[rw], bio_sectors(bio));
331 disk_stat_unlock();
329 332
330 tmp_dev = which_dev(mddev, bio->bi_sector); 333 tmp_dev = which_dev(mddev, bio->bi_sector);
331 block = bio->bi_sector >> 1; 334 block = bio->bi_sector >> 1;
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index c4779ccba1c3..182f5a94cdc5 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -147,6 +147,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio)
147 struct multipath_bh * mp_bh; 147 struct multipath_bh * mp_bh;
148 struct multipath_info *multipath; 148 struct multipath_info *multipath;
149 const int rw = bio_data_dir(bio); 149 const int rw = bio_data_dir(bio);
150 int cpu;
150 151
151 if (unlikely(bio_barrier(bio))) { 152 if (unlikely(bio_barrier(bio))) {
152 bio_endio(bio, -EOPNOTSUPP); 153 bio_endio(bio, -EOPNOTSUPP);
@@ -158,8 +159,10 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio)
158 mp_bh->master_bio = bio; 159 mp_bh->master_bio = bio;
159 mp_bh->mddev = mddev; 160 mp_bh->mddev = mddev;
160 161
161 disk_stat_inc(mddev->gendisk, ios[rw]); 162 cpu = disk_stat_lock();
162 disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio)); 163 disk_stat_inc(cpu, mddev->gendisk, ios[rw]);
164 disk_stat_add(cpu, mddev->gendisk, sectors[rw], bio_sectors(bio));
165 disk_stat_unlock();
163 166
164 mp_bh->path = multipath_map(conf); 167 mp_bh->path = multipath_map(conf);
165 if (mp_bh->path < 0) { 168 if (mp_bh->path < 0) {
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 183610635661..e26030fa59ab 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -399,14 +399,17 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio)
399 sector_t chunk; 399 sector_t chunk;
400 sector_t block, rsect; 400 sector_t block, rsect;
401 const int rw = bio_data_dir(bio); 401 const int rw = bio_data_dir(bio);
402 int cpu;
402 403
403 if (unlikely(bio_barrier(bio))) { 404 if (unlikely(bio_barrier(bio))) {
404 bio_endio(bio, -EOPNOTSUPP); 405 bio_endio(bio, -EOPNOTSUPP);
405 return 0; 406 return 0;
406 } 407 }
407 408
408 disk_stat_inc(mddev->gendisk, ios[rw]); 409 cpu = disk_stat_lock();
409 disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio)); 410 disk_stat_inc(cpu, mddev->gendisk, ios[rw]);
411 disk_stat_add(cpu, mddev->gendisk, sectors[rw], bio_sectors(bio));
412 disk_stat_unlock();
410 413
411 chunk_size = mddev->chunk_size >> 10; 414 chunk_size = mddev->chunk_size >> 10;
412 chunk_sects = mddev->chunk_size >> 9; 415 chunk_sects = mddev->chunk_size >> 9;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 0b82030c265d..babb13036f93 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -779,7 +779,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
779 struct page **behind_pages = NULL; 779 struct page **behind_pages = NULL;
780 const int rw = bio_data_dir(bio); 780 const int rw = bio_data_dir(bio);
781 const int do_sync = bio_sync(bio); 781 const int do_sync = bio_sync(bio);
782 int do_barriers; 782 int cpu, do_barriers;
783 mdk_rdev_t *blocked_rdev; 783 mdk_rdev_t *blocked_rdev;
784 784
785 /* 785 /*
@@ -804,8 +804,10 @@ static int make_request(struct request_queue *q, struct bio * bio)
804 804
805 bitmap = mddev->bitmap; 805 bitmap = mddev->bitmap;
806 806
807 disk_stat_inc(mddev->gendisk, ios[rw]); 807 cpu = disk_stat_lock();
808 disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio)); 808 disk_stat_inc(cpu, mddev->gendisk, ios[rw]);
809 disk_stat_add(cpu, mddev->gendisk, sectors[rw], bio_sectors(bio));
810 disk_stat_unlock();
809 811
810 /* 812 /*
811 * make_request() can abort the operation when READA is being 813 * make_request() can abort the operation when READA is being
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index d3b9aa096285..5ec80da0a9d7 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -789,6 +789,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
789 mirror_info_t *mirror; 789 mirror_info_t *mirror;
790 r10bio_t *r10_bio; 790 r10bio_t *r10_bio;
791 struct bio *read_bio; 791 struct bio *read_bio;
792 int cpu;
792 int i; 793 int i;
793 int chunk_sects = conf->chunk_mask + 1; 794 int chunk_sects = conf->chunk_mask + 1;
794 const int rw = bio_data_dir(bio); 795 const int rw = bio_data_dir(bio);
@@ -843,8 +844,10 @@ static int make_request(struct request_queue *q, struct bio * bio)
843 */ 844 */
844 wait_barrier(conf); 845 wait_barrier(conf);
845 846
846 disk_stat_inc(mddev->gendisk, ios[rw]); 847 cpu = disk_stat_lock();
847 disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio)); 848 disk_stat_inc(cpu, mddev->gendisk, ios[rw]);
849 disk_stat_add(cpu, mddev->gendisk, sectors[rw], bio_sectors(bio));
850 disk_stat_unlock();
848 851
849 r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO); 852 r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
850 853
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 37e546528f9c..5899f211515f 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3387,7 +3387,7 @@ static int make_request(struct request_queue *q, struct bio * bi)
3387 sector_t logical_sector, last_sector; 3387 sector_t logical_sector, last_sector;
3388 struct stripe_head *sh; 3388 struct stripe_head *sh;
3389 const int rw = bio_data_dir(bi); 3389 const int rw = bio_data_dir(bi);
3390 int remaining; 3390 int cpu, remaining;
3391 3391
3392 if (unlikely(bio_barrier(bi))) { 3392 if (unlikely(bio_barrier(bi))) {
3393 bio_endio(bi, -EOPNOTSUPP); 3393 bio_endio(bi, -EOPNOTSUPP);
@@ -3396,8 +3396,10 @@ static int make_request(struct request_queue *q, struct bio * bi)
3396 3396
3397 md_write_start(mddev, bi); 3397 md_write_start(mddev, bi);
3398 3398
3399 disk_stat_inc(mddev->gendisk, ios[rw]); 3399 cpu = disk_stat_lock();
3400 disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi)); 3400 disk_stat_inc(cpu, mddev->gendisk, ios[rw]);
3401 disk_stat_add(cpu, mddev->gendisk, sectors[rw], bio_sectors(bi));
3402 disk_stat_unlock();
3401 3403
3402 if (rw == READ && 3404 if (rw == READ &&
3403 mddev->reshape_position == MaxSector && 3405 mddev->reshape_position == MaxSector &&
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 96c8bf41e455..c442f0aadac3 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -219,10 +219,11 @@ static ssize_t part_stat_show(struct device *dev,
219 struct device_attribute *attr, char *buf) 219 struct device_attribute *attr, char *buf)
220{ 220{
221 struct hd_struct *p = dev_to_part(dev); 221 struct hd_struct *p = dev_to_part(dev);
222 int cpu;
222 223
223 preempt_disable(); 224 cpu = disk_stat_lock();
224 part_round_stats(p); 225 part_round_stats(cpu, p);
225 preempt_enable(); 226 disk_stat_unlock();
226 return sprintf(buf, 227 return sprintf(buf,
227 "%8lu %8lu %8llu %8u " 228 "%8lu %8lu %8llu %8u "
228 "%8lu %8lu %8llu %8u " 229 "%8lu %8lu %8llu %8u "
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 7fbba19e076b..ac8a901f2002 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -209,16 +209,24 @@ extern void disk_part_iter_exit(struct disk_part_iter *piter);
209extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, 209extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
210 sector_t sector); 210 sector_t sector);
211 211
212/* 212/*
213 * Macros to operate on percpu disk statistics: 213 * Macros to operate on percpu disk statistics:
214 * 214 *
215 * The __ variants should only be called in critical sections. The full 215 * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
216 * variants disable/enable preemption. 216 * and should be called between disk_stat_lock() and
217 * disk_stat_unlock().
218 *
219 * part_stat_read() can be called at any time.
220 *
221 * part_stat_{add|set_all}() and {init|free}_part_stats are for
222 * internal use only.
217 */ 223 */
218
219#ifdef CONFIG_SMP 224#ifdef CONFIG_SMP
220#define __disk_stat_add(gendiskp, field, addnd) \ 225#define disk_stat_lock() ({ rcu_read_lock(); get_cpu(); })
221 (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd) 226#define disk_stat_unlock() do { put_cpu(); rcu_read_unlock(); } while (0)
227
228#define disk_stat_add(cpu, gendiskp, field, addnd) \
229 (per_cpu_ptr(gendiskp->dkstats, cpu)->field += addnd)
222 230
223#define disk_stat_read(gendiskp, field) \ 231#define disk_stat_read(gendiskp, field) \
224({ \ 232({ \
@@ -229,7 +237,8 @@ extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
229 res; \ 237 res; \
230}) 238})
231 239
232static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) { 240static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
241{
233 int i; 242 int i;
234 243
235 for_each_possible_cpu(i) 244 for_each_possible_cpu(i)
@@ -237,14 +246,14 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
237 sizeof(struct disk_stats)); 246 sizeof(struct disk_stats));
238} 247}
239 248
240#define __part_stat_add(part, field, addnd) \ 249#define part_stat_add(cpu, part, field, addnd) \
241 (per_cpu_ptr(part->dkstats, smp_processor_id())->field += addnd) 250 (per_cpu_ptr(part->dkstats, cpu)->field += addnd)
242 251
243#define __all_stat_add(gendiskp, part, field, addnd, sector) \ 252#define all_stat_add(cpu, gendiskp, part, field, addnd, sector) \
244({ \ 253({ \
245 if (part) \ 254 if (part) \
246 __part_stat_add(part, field, addnd); \ 255 part_stat_add(cpu, part, field, addnd); \
247 __disk_stat_add(gendiskp, field, addnd); \ 256 disk_stat_add(cpu, gendiskp, field, addnd); \
248}) 257})
249 258
250#define part_stat_read(part, field) \ 259#define part_stat_read(part, field) \
@@ -264,10 +273,13 @@ static inline void part_stat_set_all(struct hd_struct *part, int value)
264 memset(per_cpu_ptr(part->dkstats, i), value, 273 memset(per_cpu_ptr(part->dkstats, i), value,
265 sizeof(struct disk_stats)); 274 sizeof(struct disk_stats));
266} 275}
267 276
268#else /* !CONFIG_SMP */ 277#else /* !CONFIG_SMP */
269#define __disk_stat_add(gendiskp, field, addnd) \ 278#define disk_stat_lock() ({ rcu_read_lock(); 0; })
270 (gendiskp->dkstats.field += addnd) 279#define disk_stat_unlock() rcu_read_unlock()
280
281#define disk_stat_add(cpu, gendiskp, field, addnd) \
282 (gendiskp->dkstats.field += addnd)
271#define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field) 283#define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field)
272 284
273static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) 285static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
@@ -275,14 +287,14 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
275 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats)); 287 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats));
276} 288}
277 289
278#define __part_stat_add(part, field, addnd) \ 290#define part_stat_add(cpu, part, field, addnd) \
279 (part->dkstats.field += addnd) 291 (part->dkstats.field += addnd)
280 292
281#define __all_stat_add(gendiskp, part, field, addnd, sector) \ 293#define all_stat_add(cpu, gendiskp, part, field, addnd, sector) \
282({ \ 294({ \
283 if (part) \ 295 if (part) \
284 part->dkstats.field += addnd; \ 296 part_stat_add(cpu, part, field, addnd); \
285 __disk_stat_add(gendiskp, field, addnd); \ 297 disk_stat_add(cpu, gendiskp, field, addnd); \
286}) 298})
287 299
288#define part_stat_read(part, field) (part->dkstats.field) 300#define part_stat_read(part, field) (part->dkstats.field)
@@ -294,63 +306,26 @@ static inline void part_stat_set_all(struct hd_struct *part, int value)
294 306
295#endif /* CONFIG_SMP */ 307#endif /* CONFIG_SMP */
296 308
297#define disk_stat_add(gendiskp, field, addnd) \ 309#define disk_stat_dec(cpu, gendiskp, field) \
298 do { \ 310 disk_stat_add(cpu, gendiskp, field, -1)
299 preempt_disable(); \ 311#define disk_stat_inc(cpu, gendiskp, field) \
300 __disk_stat_add(gendiskp, field, addnd); \ 312 disk_stat_add(cpu, gendiskp, field, 1)
301 preempt_enable(); \ 313#define disk_stat_sub(cpu, gendiskp, field, subnd) \
302 } while (0) 314 disk_stat_add(cpu, gendiskp, field, -subnd)
303 315
304#define __disk_stat_dec(gendiskp, field) __disk_stat_add(gendiskp, field, -1) 316#define part_stat_dec(cpu, gendiskp, field) \
305#define disk_stat_dec(gendiskp, field) disk_stat_add(gendiskp, field, -1) 317 part_stat_add(cpu, gendiskp, field, -1)
306 318#define part_stat_inc(cpu, gendiskp, field) \
307#define __disk_stat_inc(gendiskp, field) __disk_stat_add(gendiskp, field, 1) 319 part_stat_add(cpu, gendiskp, field, 1)
308#define disk_stat_inc(gendiskp, field) disk_stat_add(gendiskp, field, 1) 320#define part_stat_sub(cpu, gendiskp, field, subnd) \
309 321 part_stat_add(cpu, gendiskp, field, -subnd)
310#define __disk_stat_sub(gendiskp, field, subnd) \ 322
311 __disk_stat_add(gendiskp, field, -subnd) 323#define all_stat_dec(cpu, gendiskp, field, sector) \
312#define disk_stat_sub(gendiskp, field, subnd) \ 324 all_stat_add(cpu, gendiskp, field, -1, sector)
313 disk_stat_add(gendiskp, field, -subnd) 325#define all_stat_inc(cpu, gendiskp, part, field, sector) \
314 326 all_stat_add(cpu, gendiskp, part, field, 1, sector)
315#define part_stat_add(gendiskp, field, addnd) \ 327#define all_stat_sub(cpu, gendiskp, part, field, subnd, sector) \
316 do { \ 328 all_stat_add(cpu, gendiskp, part, field, -subnd, sector)
317 preempt_disable(); \
318 __part_stat_add(gendiskp, field, addnd);\
319 preempt_enable(); \
320 } while (0)
321
322#define __part_stat_dec(gendiskp, field) __part_stat_add(gendiskp, field, -1)
323#define part_stat_dec(gendiskp, field) part_stat_add(gendiskp, field, -1)
324
325#define __part_stat_inc(gendiskp, field) __part_stat_add(gendiskp, field, 1)
326#define part_stat_inc(gendiskp, field) part_stat_add(gendiskp, field, 1)
327
328#define __part_stat_sub(gendiskp, field, subnd) \
329 __part_stat_add(gendiskp, field, -subnd)
330#define part_stat_sub(gendiskp, field, subnd) \
331 part_stat_add(gendiskp, field, -subnd)
332
333#define all_stat_add(gendiskp, part, field, addnd, sector) \
334 do { \
335 preempt_disable(); \
336 __all_stat_add(gendiskp, part, field, addnd, sector); \
337 preempt_enable(); \
338 } while (0)
339
340#define __all_stat_dec(gendiskp, field, sector) \
341 __all_stat_add(gendiskp, field, -1, sector)
342#define all_stat_dec(gendiskp, field, sector) \
343 all_stat_add(gendiskp, field, -1, sector)
344
345#define __all_stat_inc(gendiskp, part, field, sector) \
346 __all_stat_add(gendiskp, part, field, 1, sector)
347#define all_stat_inc(gendiskp, part, field, sector) \
348 all_stat_add(gendiskp, part, field, 1, sector)
349
350#define __all_stat_sub(gendiskp, part, field, subnd, sector) \
351 __all_stat_add(gendiskp, part, field, -subnd, sector)
352#define all_stat_sub(gendiskp, part, field, subnd, sector) \
353 all_stat_add(gendiskp, part, field, -subnd, sector)
354 329
355/* Inlines to alloc and free disk stats in struct gendisk */ 330/* Inlines to alloc and free disk stats in struct gendisk */
356#ifdef CONFIG_SMP 331#ifdef CONFIG_SMP
@@ -401,8 +376,8 @@ static inline void free_part_stats(struct hd_struct *part)
401#endif /* CONFIG_SMP */ 376#endif /* CONFIG_SMP */
402 377
403/* drivers/block/ll_rw_blk.c */ 378/* drivers/block/ll_rw_blk.c */
404extern void disk_round_stats(struct gendisk *disk); 379extern void disk_round_stats(int cpu, struct gendisk *disk);
405extern void part_round_stats(struct hd_struct *part); 380extern void part_round_stats(int cpu, struct hd_struct *part);
406 381
407/* drivers/block/genhd.c */ 382/* drivers/block/genhd.c */
408extern int get_blkdev_list(char *, int); 383extern int get_blkdev_list(char *, int);