aboutsummaryrefslogtreecommitdiffstats
path: root/block
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 /block
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>
Diffstat (limited to 'block')
-rw-r--r--block/blk-core.c52
-rw-r--r--block/blk-merge.c11
-rw-r--r--block/genhd.c20
3 files changed, 44 insertions, 39 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)),