aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);