diff options
author | Tejun Heo <tj@kernel.org> | 2008-08-25 06:56:14 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-10-09 02:56:08 -0400 |
commit | 074a7aca7afa6f230104e8e65eba3420263714a5 (patch) | |
tree | f418313e45bd55be8156c8a3e8f9a216cf63058d /block | |
parent | eddb2e26b5ee3c5da68ba4bf1921ba20e2097bff (diff) |
block: move stats from disk to part0
Move stats related fields - stamp, in_flight, dkstats - from disk to
part0 and unify stat handling such that...
* part_stat_*() now updates part0 together if the specified partition
is not part0. ie. part_stat_*() are now essentially all_stat_*().
* {disk|all}_stat_*() are gone.
* part_round_stats() is updated similary. It handles part0 stats
automatically and disk_round_stats() is killed.
* part_{inc|dec}_in_fligh() is implemented which automatically updates
part0 stats for parts other than part0.
* disk_map_sector_rcu() is updated to return part0 if no part matches.
Combined with the above changes, this makes NULL special case
handling in callers unnecessary.
* Separate stats show code paths for disk are collapsed into part
stats show code paths.
* Rename disk_stat_lock/unlock() to part_stat_lock/unlock()
While at it, reposition stat handling macros a bit and add missing
parentheses around macro parameters.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-core.c | 84 | ||||
-rw-r--r-- | block/blk-merge.c | 12 | ||||
-rw-r--r-- | block/genhd.c | 97 |
3 files changed, 62 insertions, 131 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 505ec61067df..98138f002524 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -61,21 +61,17 @@ static void drive_stat_acct(struct request *rq, int new_io) | |||
61 | if (!blk_fs_request(rq) || !rq->rq_disk) | 61 | if (!blk_fs_request(rq) || !rq->rq_disk) |
62 | return; | 62 | return; |
63 | 63 | ||
64 | cpu = disk_stat_lock(); | 64 | cpu = part_stat_lock(); |
65 | part = disk_map_sector_rcu(rq->rq_disk, rq->sector); | 65 | part = disk_map_sector_rcu(rq->rq_disk, rq->sector); |
66 | 66 | ||
67 | if (!new_io) | 67 | if (!new_io) |
68 | all_stat_inc(cpu, rq->rq_disk, part, merges[rw], rq->sector); | 68 | part_stat_inc(cpu, part, merges[rw]); |
69 | else { | 69 | else { |
70 | disk_round_stats(cpu, rq->rq_disk); | 70 | part_round_stats(cpu, part); |
71 | rq->rq_disk->in_flight++; | 71 | part_inc_in_flight(part); |
72 | if (part) { | ||
73 | part_round_stats(cpu, part); | ||
74 | part->in_flight++; | ||
75 | } | ||
76 | } | 72 | } |
77 | 73 | ||
78 | disk_stat_unlock(); | 74 | part_stat_unlock(); |
79 | } | 75 | } |
80 | 76 | ||
81 | void blk_queue_congestion_threshold(struct request_queue *q) | 77 | void blk_queue_congestion_threshold(struct request_queue *q) |
@@ -983,8 +979,22 @@ static inline void add_request(struct request_queue *q, struct request *req) | |||
983 | __elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0); | 979 | __elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0); |
984 | } | 980 | } |
985 | 981 | ||
986 | /* | 982 | static void part_round_stats_single(int cpu, struct hd_struct *part, |
987 | * disk_round_stats() - Round off the performance stats on a struct | 983 | unsigned long now) |
984 | { | ||
985 | if (now == part->stamp) | ||
986 | return; | ||
987 | |||
988 | if (part->in_flight) { | ||
989 | __part_stat_add(cpu, part, time_in_queue, | ||
990 | part->in_flight * (now - part->stamp)); | ||
991 | __part_stat_add(cpu, part, io_ticks, (now - part->stamp)); | ||
992 | } | ||
993 | part->stamp = now; | ||
994 | } | ||
995 | |||
996 | /** | ||
997 | * part_round_stats() - Round off the performance stats on a struct | ||
988 | * disk_stats. | 998 | * disk_stats. |
989 | * | 999 | * |
990 | * The average IO queue length and utilisation statistics are maintained | 1000 | * The average IO queue length and utilisation statistics are maintained |
@@ -998,36 +1008,15 @@ static inline void add_request(struct request_queue *q, struct request *req) | |||
998 | * /proc/diskstats. This accounts immediately for all queue usage up to | 1008 | * /proc/diskstats. This accounts immediately for all queue usage up to |
999 | * the current jiffies and restarts the counters again. | 1009 | * the current jiffies and restarts the counters again. |
1000 | */ | 1010 | */ |
1001 | void disk_round_stats(int cpu, struct gendisk *disk) | ||
1002 | { | ||
1003 | unsigned long now = jiffies; | ||
1004 | |||
1005 | if (now == disk->stamp) | ||
1006 | return; | ||
1007 | |||
1008 | if (disk->in_flight) { | ||
1009 | disk_stat_add(cpu, disk, time_in_queue, | ||
1010 | disk->in_flight * (now - disk->stamp)); | ||
1011 | disk_stat_add(cpu, disk, io_ticks, (now - disk->stamp)); | ||
1012 | } | ||
1013 | disk->stamp = now; | ||
1014 | } | ||
1015 | EXPORT_SYMBOL_GPL(disk_round_stats); | ||
1016 | |||
1017 | void part_round_stats(int cpu, struct hd_struct *part) | 1011 | void part_round_stats(int cpu, struct hd_struct *part) |
1018 | { | 1012 | { |
1019 | unsigned long now = jiffies; | 1013 | unsigned long now = jiffies; |
1020 | 1014 | ||
1021 | if (now == part->stamp) | 1015 | if (part->partno) |
1022 | return; | 1016 | part_round_stats_single(cpu, &part_to_disk(part)->part0, now); |
1023 | 1017 | part_round_stats_single(cpu, part, now); | |
1024 | if (part->in_flight) { | ||
1025 | part_stat_add(cpu, part, time_in_queue, | ||
1026 | part->in_flight * (now - part->stamp)); | ||
1027 | part_stat_add(cpu, part, io_ticks, (now - part->stamp)); | ||
1028 | } | ||
1029 | part->stamp = now; | ||
1030 | } | 1018 | } |
1019 | EXPORT_SYMBOL_GPL(part_round_stats); | ||
1031 | 1020 | ||
1032 | /* | 1021 | /* |
1033 | * queue lock must be held | 1022 | * queue lock must be held |
@@ -1567,11 +1556,10 @@ static int __end_that_request_first(struct request *req, int error, | |||
1567 | struct hd_struct *part; | 1556 | struct hd_struct *part; |
1568 | int cpu; | 1557 | int cpu; |
1569 | 1558 | ||
1570 | cpu = disk_stat_lock(); | 1559 | cpu = part_stat_lock(); |
1571 | part = disk_map_sector_rcu(req->rq_disk, req->sector); | 1560 | part = disk_map_sector_rcu(req->rq_disk, req->sector); |
1572 | all_stat_add(cpu, req->rq_disk, part, sectors[rw], | 1561 | part_stat_add(cpu, part, sectors[rw], nr_bytes >> 9); |
1573 | nr_bytes >> 9, req->sector); | 1562 | part_stat_unlock(); |
1574 | disk_stat_unlock(); | ||
1575 | } | 1563 | } |
1576 | 1564 | ||
1577 | total_bytes = bio_nbytes = 0; | 1565 | total_bytes = bio_nbytes = 0; |
@@ -1758,19 +1746,15 @@ static void end_that_request_last(struct request *req, int error) | |||
1758 | struct hd_struct *part; | 1746 | struct hd_struct *part; |
1759 | int cpu; | 1747 | int cpu; |
1760 | 1748 | ||
1761 | cpu = disk_stat_lock(); | 1749 | cpu = part_stat_lock(); |
1762 | part = disk_map_sector_rcu(disk, req->sector); | 1750 | part = disk_map_sector_rcu(disk, req->sector); |
1763 | 1751 | ||
1764 | all_stat_inc(cpu, disk, part, ios[rw], req->sector); | 1752 | part_stat_inc(cpu, part, ios[rw]); |
1765 | all_stat_add(cpu, disk, part, ticks[rw], duration, req->sector); | 1753 | part_stat_add(cpu, part, ticks[rw], duration); |
1766 | disk_round_stats(cpu, disk); | 1754 | part_round_stats(cpu, part); |
1767 | disk->in_flight--; | 1755 | part_dec_in_flight(part); |
1768 | if (part) { | ||
1769 | part_round_stats(cpu, part); | ||
1770 | part->in_flight--; | ||
1771 | } | ||
1772 | 1756 | ||
1773 | disk_stat_unlock(); | 1757 | part_stat_unlock(); |
1774 | } | 1758 | } |
1775 | 1759 | ||
1776 | if (req->end_io) | 1760 | if (req->end_io) |
diff --git a/block/blk-merge.c b/block/blk-merge.c index d926a24bf1fd..c77196d55899 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c | |||
@@ -390,17 +390,13 @@ static int attempt_merge(struct request_queue *q, struct request *req, | |||
390 | struct hd_struct *part; | 390 | struct hd_struct *part; |
391 | int cpu; | 391 | int cpu; |
392 | 392 | ||
393 | cpu = disk_stat_lock(); | 393 | cpu = part_stat_lock(); |
394 | part = disk_map_sector_rcu(req->rq_disk, req->sector); | 394 | part = disk_map_sector_rcu(req->rq_disk, req->sector); |
395 | 395 | ||
396 | disk_round_stats(cpu, req->rq_disk); | 396 | part_round_stats(cpu, part); |
397 | req->rq_disk->in_flight--; | 397 | part_dec_in_flight(part); |
398 | if (part) { | ||
399 | part_round_stats(cpu, part); | ||
400 | part->in_flight--; | ||
401 | } | ||
402 | 398 | ||
403 | disk_stat_unlock(); | 399 | part_stat_unlock(); |
404 | } | 400 | } |
405 | 401 | ||
406 | req->ioprio = ioprio_best(req->ioprio, next->ioprio); | 402 | req->ioprio = ioprio_best(req->ioprio, next->ioprio); |
diff --git a/block/genhd.c b/block/genhd.c index 06a252f2b967..e1cb96fb883e 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -176,7 +176,7 @@ EXPORT_SYMBOL_GPL(disk_part_iter_exit); | |||
176 | * while preemption is disabled. | 176 | * while preemption is disabled. |
177 | * | 177 | * |
178 | * RETURNS: | 178 | * RETURNS: |
179 | * Found partition on success, NULL if there's no matching partition. | 179 | * Found partition on success, part0 is returned if no partition matches |
180 | */ | 180 | */ |
181 | struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector) | 181 | struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector) |
182 | { | 182 | { |
@@ -189,7 +189,7 @@ struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector) | |||
189 | sector < part->start_sect + part->nr_sects) | 189 | sector < part->start_sect + part->nr_sects) |
190 | return part; | 190 | return part; |
191 | } | 191 | } |
192 | return NULL; | 192 | return &disk->part0; |
193 | } | 193 | } |
194 | EXPORT_SYMBOL_GPL(disk_map_sector_rcu); | 194 | EXPORT_SYMBOL_GPL(disk_map_sector_rcu); |
195 | 195 | ||
@@ -580,24 +580,24 @@ void __init printk_all_partitions(void) | |||
580 | * numbers in hex - the same format as the root= | 580 | * numbers in hex - the same format as the root= |
581 | * option takes. | 581 | * option takes. |
582 | */ | 582 | */ |
583 | printk("%s %10llu %s", | 583 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); |
584 | bdevt_str(disk_devt(disk), devt_buf), | 584 | while ((part = disk_part_iter_next(&piter))) { |
585 | (unsigned long long)get_capacity(disk) >> 1, | 585 | bool is_part0 = part == &disk->part0; |
586 | disk_name(disk, 0, name_buf)); | ||
587 | if (disk->driverfs_dev != NULL && | ||
588 | disk->driverfs_dev->driver != NULL) | ||
589 | printk(" driver: %s\n", | ||
590 | disk->driverfs_dev->driver->name); | ||
591 | else | ||
592 | printk(" (driver?)\n"); | ||
593 | 586 | ||
594 | /* now show the partitions */ | 587 | printk("%s%s %10llu %s", is_part0 ? "" : " ", |
595 | disk_part_iter_init(&piter, disk, 0); | ||
596 | while ((part = disk_part_iter_next(&piter))) | ||
597 | printk(" %s %10llu %s\n", | ||
598 | bdevt_str(part_devt(part), devt_buf), | 588 | bdevt_str(part_devt(part), devt_buf), |
599 | (unsigned long long)part->nr_sects >> 1, | 589 | (unsigned long long)part->nr_sects >> 1, |
600 | disk_name(disk, part->partno, name_buf)); | 590 | disk_name(disk, part->partno, name_buf)); |
591 | if (is_part0) { | ||
592 | if (disk->driverfs_dev != NULL && | ||
593 | disk->driverfs_dev->driver != NULL) | ||
594 | printk(" driver: %s\n", | ||
595 | disk->driverfs_dev->driver->name); | ||
596 | else | ||
597 | printk(" (driver?)\n"); | ||
598 | } else | ||
599 | printk("\n"); | ||
600 | } | ||
601 | disk_part_iter_exit(&piter); | 601 | disk_part_iter_exit(&piter); |
602 | } | 602 | } |
603 | class_dev_iter_exit(&iter); | 603 | class_dev_iter_exit(&iter); |
@@ -674,12 +674,7 @@ static int show_partition(struct seq_file *seqf, void *v) | |||
674 | return 0; | 674 | return 0; |
675 | 675 | ||
676 | /* show the full disk and all non-0 size partitions of it */ | 676 | /* show the full disk and all non-0 size partitions of it */ |
677 | seq_printf(seqf, "%4d %7d %10llu %s\n", | 677 | disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0); |
678 | MAJOR(disk_devt(sgp)), MINOR(disk_devt(sgp)), | ||
679 | (unsigned long long)get_capacity(sgp) >> 1, | ||
680 | disk_name(sgp, 0, buf)); | ||
681 | |||
682 | disk_part_iter_init(&piter, sgp, 0); | ||
683 | while ((part = disk_part_iter_next(&piter))) | 678 | while ((part = disk_part_iter_next(&piter))) |
684 | seq_printf(seqf, "%4d %7d %10llu %s\n", | 679 | seq_printf(seqf, "%4d %7d %10llu %s\n", |
685 | MAJOR(part_devt(part)), MINOR(part_devt(part)), | 680 | MAJOR(part_devt(part)), MINOR(part_devt(part)), |
@@ -768,40 +763,13 @@ static ssize_t disk_capability_show(struct device *dev, | |||
768 | return sprintf(buf, "%x\n", disk->flags); | 763 | return sprintf(buf, "%x\n", disk->flags); |
769 | } | 764 | } |
770 | 765 | ||
771 | static ssize_t disk_stat_show(struct device *dev, | ||
772 | struct device_attribute *attr, char *buf) | ||
773 | { | ||
774 | struct gendisk *disk = dev_to_disk(dev); | ||
775 | int cpu; | ||
776 | |||
777 | cpu = disk_stat_lock(); | ||
778 | disk_round_stats(cpu, disk); | ||
779 | disk_stat_unlock(); | ||
780 | return sprintf(buf, | ||
781 | "%8lu %8lu %8llu %8u " | ||
782 | "%8lu %8lu %8llu %8u " | ||
783 | "%8u %8u %8u" | ||
784 | "\n", | ||
785 | disk_stat_read(disk, ios[READ]), | ||
786 | disk_stat_read(disk, merges[READ]), | ||
787 | (unsigned long long)disk_stat_read(disk, sectors[READ]), | ||
788 | jiffies_to_msecs(disk_stat_read(disk, ticks[READ])), | ||
789 | disk_stat_read(disk, ios[WRITE]), | ||
790 | disk_stat_read(disk, merges[WRITE]), | ||
791 | (unsigned long long)disk_stat_read(disk, sectors[WRITE]), | ||
792 | jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])), | ||
793 | disk->in_flight, | ||
794 | jiffies_to_msecs(disk_stat_read(disk, io_ticks)), | ||
795 | jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); | ||
796 | } | ||
797 | |||
798 | static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); | 766 | static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); |
799 | static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); | 767 | static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); |
800 | static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); | 768 | static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); |
801 | static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); | 769 | static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); |
802 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); | 770 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); |
803 | static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); | 771 | static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); |
804 | static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); | 772 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); |
805 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 773 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
806 | static struct device_attribute dev_attr_fail = | 774 | static struct device_attribute dev_attr_fail = |
807 | __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); | 775 | __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); |
@@ -836,7 +804,7 @@ static void disk_release(struct device *dev) | |||
836 | 804 | ||
837 | kfree(disk->random); | 805 | kfree(disk->random); |
838 | kfree(disk->__part); | 806 | kfree(disk->__part); |
839 | free_disk_stats(disk); | 807 | free_part_stats(&disk->part0); |
840 | kfree(disk); | 808 | kfree(disk); |
841 | } | 809 | } |
842 | struct class block_class = { | 810 | struct class block_class = { |
@@ -873,28 +841,11 @@ static int diskstats_show(struct seq_file *seqf, void *v) | |||
873 | "\n\n"); | 841 | "\n\n"); |
874 | */ | 842 | */ |
875 | 843 | ||
876 | cpu = disk_stat_lock(); | 844 | disk_part_iter_init(&piter, gp, DISK_PITER_INCL_PART0); |
877 | disk_round_stats(cpu, gp); | ||
878 | disk_stat_unlock(); | ||
879 | seq_printf(seqf, "%4d %7d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n", | ||
880 | MAJOR(disk_devt(gp)), MINOR(disk_devt(gp)), | ||
881 | disk_name(gp, 0, buf), | ||
882 | disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]), | ||
883 | (unsigned long long)disk_stat_read(gp, sectors[0]), | ||
884 | jiffies_to_msecs(disk_stat_read(gp, ticks[0])), | ||
885 | disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]), | ||
886 | (unsigned long long)disk_stat_read(gp, sectors[1]), | ||
887 | jiffies_to_msecs(disk_stat_read(gp, ticks[1])), | ||
888 | gp->in_flight, | ||
889 | jiffies_to_msecs(disk_stat_read(gp, io_ticks)), | ||
890 | jiffies_to_msecs(disk_stat_read(gp, time_in_queue))); | ||
891 | |||
892 | /* now show all non-0 size partitions of it */ | ||
893 | disk_part_iter_init(&piter, gp, 0); | ||
894 | while ((hd = disk_part_iter_next(&piter))) { | 845 | while ((hd = disk_part_iter_next(&piter))) { |
895 | cpu = disk_stat_lock(); | 846 | cpu = part_stat_lock(); |
896 | part_round_stats(cpu, hd); | 847 | part_round_stats(cpu, hd); |
897 | disk_stat_unlock(); | 848 | part_stat_unlock(); |
898 | seq_printf(seqf, "%4d %7d %s %lu %lu %llu " | 849 | seq_printf(seqf, "%4d %7d %s %lu %lu %llu " |
899 | "%u %lu %lu %llu %u %u %u %u\n", | 850 | "%u %lu %lu %llu %u %u %u %u\n", |
900 | MAJOR(part_devt(hd)), MINOR(part_devt(hd)), | 851 | MAJOR(part_devt(hd)), MINOR(part_devt(hd)), |
@@ -1000,7 +951,7 @@ struct gendisk *alloc_disk_ext_node(int minors, int ext_minors, int node_id) | |||
1000 | int tot_minors = minors + ext_minors; | 951 | int tot_minors = minors + ext_minors; |
1001 | int size = tot_minors * sizeof(struct hd_struct *); | 952 | int size = tot_minors * sizeof(struct hd_struct *); |
1002 | 953 | ||
1003 | if (!init_disk_stats(disk)) { | 954 | if (!init_part_stats(&disk->part0)) { |
1004 | kfree(disk); | 955 | kfree(disk); |
1005 | return NULL; | 956 | return NULL; |
1006 | } | 957 | } |
@@ -1008,7 +959,7 @@ struct gendisk *alloc_disk_ext_node(int minors, int ext_minors, int node_id) | |||
1008 | disk->__part = kmalloc_node(size, GFP_KERNEL | __GFP_ZERO, | 959 | disk->__part = kmalloc_node(size, GFP_KERNEL | __GFP_ZERO, |
1009 | node_id); | 960 | node_id); |
1010 | if (!disk->__part) { | 961 | if (!disk->__part) { |
1011 | free_disk_stats(disk); | 962 | free_part_stats(&disk->part0); |
1012 | kfree(disk); | 963 | kfree(disk); |
1013 | return NULL; | 964 | return NULL; |
1014 | } | 965 | } |