aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/procfs-diskstats22
-rw-r--r--Documentation/ABI/testing/sysfs-block28
-rw-r--r--Documentation/iostats.txt15
-rw-r--r--block/blk-core.c61
-rw-r--r--block/blk-merge.c6
-rw-r--r--block/genhd.c28
-rw-r--r--drivers/block/aoe/aoecmd.c12
-rw-r--r--fs/partitions/check.c31
-rw-r--r--include/linux/blkdev.h4
-rw-r--r--include/linux/genhd.h153
10 files changed, 316 insertions, 44 deletions
diff --git a/Documentation/ABI/testing/procfs-diskstats b/Documentation/ABI/testing/procfs-diskstats
new file mode 100644
index 000000000000..99233902e09e
--- /dev/null
+++ b/Documentation/ABI/testing/procfs-diskstats
@@ -0,0 +1,22 @@
1What: /proc/diskstats
2Date: February 2008
3Contact: Jerome Marchand <jmarchan@redhat.com>
4Description:
5 The /proc/diskstats file displays the I/O statistics
6 of block devices. Each line contains the following 14
7 fields:
8 1 - major number
9 2 - minor mumber
10 3 - device name
11 4 - reads completed succesfully
12 5 - reads merged
13 6 - sectors read
14 7 - time spent reading (ms)
15 8 - writes completed
16 9 - writes merged
17 10 - sectors written
18 11 - time spent writing (ms)
19 12 - I/Os currently in progress
20 13 - time spent doing I/Os (ms)
21 14 - weighted time spent doing I/Os (ms)
22 For more details refer to Documentation/iostats.txt
diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block
new file mode 100644
index 000000000000..4bd9ea539129
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-block
@@ -0,0 +1,28 @@
1What: /sys/block/<disk>/stat
2Date: February 2008
3Contact: Jerome Marchand <jmarchan@redhat.com>
4Description:
5 The /sys/block/<disk>/stat files displays the I/O
6 statistics of disk <disk>. They contain 11 fields:
7 1 - reads completed succesfully
8 2 - reads merged
9 3 - sectors read
10 4 - time spent reading (ms)
11 5 - writes completed
12 6 - writes merged
13 7 - sectors written
14 8 - time spent writing (ms)
15 9 - I/Os currently in progress
16 10 - time spent doing I/Os (ms)
17 11 - weighted time spent doing I/Os (ms)
18 For more details refer Documentation/iostats.txt
19
20
21What: /sys/block/<disk>/<part>/stat
22Date: February 2008
23Contact: Jerome Marchand <jmarchan@redhat.com>
24Description:
25 The /sys/block/<disk>/<part>/stat files display the
26 I/O statistics of partition <part>. The format is the
27 same as the above-written /sys/block/<disk>/stat
28 format.
diff --git a/Documentation/iostats.txt b/Documentation/iostats.txt
index b963c3b4afa5..5925c3cd030d 100644
--- a/Documentation/iostats.txt
+++ b/Documentation/iostats.txt
@@ -58,7 +58,7 @@ they should not wrap twice before you notice them.
58Each set of stats only applies to the indicated device; if you want 58Each set of stats only applies to the indicated device; if you want
59system-wide stats you'll have to find all the devices and sum them all up. 59system-wide stats you'll have to find all the devices and sum them all up.
60 60
61Field 1 -- # of reads issued 61Field 1 -- # of reads completed
62 This is the total number of reads completed successfully. 62 This is the total number of reads completed successfully.
63Field 2 -- # of reads merged, field 6 -- # of writes merged 63Field 2 -- # of reads merged, field 6 -- # of writes merged
64 Reads and writes which are adjacent to each other may be merged for 64 Reads and writes which are adjacent to each other may be merged for
@@ -132,6 +132,19 @@ words, the number of reads for partitions is counted slightly before time
132of queuing for partitions, and at completion for whole disks. This is 132of queuing for partitions, and at completion for whole disks. This is
133a subtle distinction that is probably uninteresting for most cases. 133a subtle distinction that is probably uninteresting for most cases.
134 134
135More significant is the error induced by counting the numbers of
136reads/writes before merges for partitions and after for disks. Since a
137typical workload usually contains a lot of successive and adjacent requests,
138the number of reads/writes issued can be several times higher than the
139number of reads/writes completed.
140
141In 2.6.25, the full statistic set is again available for partitions and
142disk and partition statistics are consistent again. Since we still don't
143keep record of the partition-relative address, an operation is attributed to
144the partition which contains the first sector of the request after the
145eventual merges. As requests can be merged across partition, this could lead
146to some (probably insignificant) innacuracy.
147
135Additional notes 148Additional notes
136---------------- 149----------------
137 150
diff --git a/block/blk-core.c b/block/blk-core.c
index 4afb39c82339..e9754dc98ec4 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -60,10 +60,15 @@ static void drive_stat_acct(struct request *rq, int new_io)
60 return; 60 return;
61 61
62 if (!new_io) { 62 if (!new_io) {
63 __disk_stat_inc(rq->rq_disk, merges[rw]); 63 __all_stat_inc(rq->rq_disk, merges[rw], rq->sector);
64 } else { 64 } else {
65 struct hd_struct *part = get_part(rq->rq_disk, rq->sector);
65 disk_round_stats(rq->rq_disk); 66 disk_round_stats(rq->rq_disk);
66 rq->rq_disk->in_flight++; 67 rq->rq_disk->in_flight++;
68 if (part) {
69 part_round_stats(part);
70 part->in_flight++;
71 }
67 } 72 }
68} 73}
69 74
@@ -102,27 +107,38 @@ struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
102} 107}
103EXPORT_SYMBOL(blk_get_backing_dev_info); 108EXPORT_SYMBOL(blk_get_backing_dev_info);
104 109
110/*
111 * We can't just memset() the structure, since the allocation path
112 * already stored some information in the request.
113 */
105void rq_init(struct request_queue *q, struct request *rq) 114void rq_init(struct request_queue *q, struct request *rq)
106{ 115{
107 INIT_LIST_HEAD(&rq->queuelist); 116 INIT_LIST_HEAD(&rq->queuelist);
108 INIT_LIST_HEAD(&rq->donelist); 117 INIT_LIST_HEAD(&rq->donelist);
109 118 rq->q = q;
110 rq->errors = 0; 119 rq->sector = rq->hard_sector = (sector_t) -1;
120 rq->nr_sectors = rq->hard_nr_sectors = 0;
121 rq->current_nr_sectors = rq->hard_cur_sectors = 0;
111 rq->bio = rq->biotail = NULL; 122 rq->bio = rq->biotail = NULL;
112 INIT_HLIST_NODE(&rq->hash); 123 INIT_HLIST_NODE(&rq->hash);
113 RB_CLEAR_NODE(&rq->rb_node); 124 RB_CLEAR_NODE(&rq->rb_node);
125 rq->rq_disk = NULL;
126 rq->nr_phys_segments = 0;
127 rq->nr_hw_segments = 0;
114 rq->ioprio = 0; 128 rq->ioprio = 0;
129 rq->special = NULL;
115 rq->buffer = NULL; 130 rq->buffer = NULL;
131 rq->tag = -1;
132 rq->errors = 0;
116 rq->ref_count = 1; 133 rq->ref_count = 1;
117 rq->q = q; 134 rq->cmd_len = 0;
118 rq->special = NULL; 135 memset(rq->cmd, 0, sizeof(rq->cmd));
119 rq->data_len = 0; 136 rq->data_len = 0;
137 rq->sense_len = 0;
120 rq->data = NULL; 138 rq->data = NULL;
121 rq->nr_phys_segments = 0;
122 rq->sense = NULL; 139 rq->sense = NULL;
123 rq->end_io = NULL; 140 rq->end_io = NULL;
124 rq->end_io_data = NULL; 141 rq->end_io_data = NULL;
125 rq->completion_data = NULL;
126 rq->next_rq = NULL; 142 rq->next_rq = NULL;
127} 143}
128 144
@@ -986,6 +1002,21 @@ void disk_round_stats(struct gendisk *disk)
986} 1002}
987EXPORT_SYMBOL_GPL(disk_round_stats); 1003EXPORT_SYMBOL_GPL(disk_round_stats);
988 1004
1005void part_round_stats(struct hd_struct *part)
1006{
1007 unsigned long now = jiffies;
1008
1009 if (now == part->stamp)
1010 return;
1011
1012 if (part->in_flight) {
1013 __part_stat_add(part, time_in_queue,
1014 part->in_flight * (now - part->stamp));
1015 __part_stat_add(part, io_ticks, (now - part->stamp));
1016 }
1017 part->stamp = now;
1018}
1019
989/* 1020/*
990 * queue lock must be held 1021 * queue lock must be held
991 */ 1022 */
@@ -1188,10 +1219,6 @@ static inline void blk_partition_remap(struct bio *bio)
1188 1219
1189 if (bio_sectors(bio) && bdev != bdev->bd_contains) { 1220 if (bio_sectors(bio) && bdev != bdev->bd_contains) {
1190 struct hd_struct *p = bdev->bd_part; 1221 struct hd_struct *p = bdev->bd_part;
1191 const int rw = bio_data_dir(bio);
1192
1193 p->sectors[rw] += bio_sectors(bio);
1194 p->ios[rw]++;
1195 1222
1196 bio->bi_sector += p->start_sect; 1223 bio->bi_sector += p->start_sect;
1197 bio->bi_bdev = bdev->bd_contains; 1224 bio->bi_bdev = bdev->bd_contains;
@@ -1519,7 +1546,8 @@ static int __end_that_request_first(struct request *req, int error,
1519 if (blk_fs_request(req) && req->rq_disk) { 1546 if (blk_fs_request(req) && req->rq_disk) {
1520 const int rw = rq_data_dir(req); 1547 const int rw = rq_data_dir(req);
1521 1548
1522 disk_stat_add(req->rq_disk, sectors[rw], nr_bytes >> 9); 1549 all_stat_add(req->rq_disk, sectors[rw],
1550 nr_bytes >> 9, req->sector);
1523 } 1551 }
1524 1552
1525 total_bytes = bio_nbytes = 0; 1553 total_bytes = bio_nbytes = 0;
@@ -1704,11 +1732,16 @@ static void end_that_request_last(struct request *req, int error)
1704 if (disk && blk_fs_request(req) && req != &req->q->bar_rq) { 1732 if (disk && blk_fs_request(req) && req != &req->q->bar_rq) {
1705 unsigned long duration = jiffies - req->start_time; 1733 unsigned long duration = jiffies - req->start_time;
1706 const int rw = rq_data_dir(req); 1734 const int rw = rq_data_dir(req);
1735 struct hd_struct *part = get_part(disk, req->sector);
1707 1736
1708 __disk_stat_inc(disk, ios[rw]); 1737 __all_stat_inc(disk, ios[rw], req->sector);
1709 __disk_stat_add(disk, ticks[rw], duration); 1738 __all_stat_add(disk, ticks[rw], duration, req->sector);
1710 disk_round_stats(disk); 1739 disk_round_stats(disk);
1711 disk->in_flight--; 1740 disk->in_flight--;
1741 if (part) {
1742 part_round_stats(part);
1743 part->in_flight--;
1744 }
1712 } 1745 }
1713 1746
1714 if (req->end_io) 1747 if (req->end_io)
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 845ef8131108..d3b84bbb776a 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -454,8 +454,14 @@ static int attempt_merge(struct request_queue *q, struct request *req,
454 elv_merge_requests(q, req, next); 454 elv_merge_requests(q, req, next);
455 455
456 if (req->rq_disk) { 456 if (req->rq_disk) {
457 struct hd_struct *part
458 = get_part(req->rq_disk, req->sector);
457 disk_round_stats(req->rq_disk); 459 disk_round_stats(req->rq_disk);
458 req->rq_disk->in_flight--; 460 req->rq_disk->in_flight--;
461 if (part) {
462 part_round_stats(part);
463 part->in_flight--;
464 }
459 } 465 }
460 466
461 req->ioprio = ioprio_best(req->ioprio, next->ioprio); 467 req->ioprio = ioprio_best(req->ioprio, next->ioprio);
diff --git a/block/genhd.c b/block/genhd.c
index de2ebb2fab43..53f2238e69c8 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -584,12 +584,28 @@ static int diskstats_show(struct seq_file *s, void *v)
584 for (n = 0; n < gp->minors - 1; n++) { 584 for (n = 0; n < gp->minors - 1; n++) {
585 struct hd_struct *hd = gp->part[n]; 585 struct hd_struct *hd = gp->part[n];
586 586
587 if (hd && hd->nr_sects) 587 if (!hd || !hd->nr_sects)
588 seq_printf(s, "%4d %4d %s %u %u %u %u\n", 588 continue;
589 gp->major, n + gp->first_minor + 1, 589
590 disk_name(gp, n + 1, buf), 590 preempt_disable();
591 hd->ios[0], hd->sectors[0], 591 part_round_stats(hd);
592 hd->ios[1], hd->sectors[1]); 592 preempt_enable();
593 seq_printf(s, "%4d %4d %s %lu %lu %llu "
594 "%u %lu %lu %llu %u %u %u %u\n",
595 gp->major, n + gp->first_minor + 1,
596 disk_name(gp, n + 1, buf),
597 part_stat_read(hd, ios[0]),
598 part_stat_read(hd, merges[0]),
599 (unsigned long long)part_stat_read(hd, sectors[0]),
600 jiffies_to_msecs(part_stat_read(hd, ticks[0])),
601 part_stat_read(hd, ios[1]),
602 part_stat_read(hd, merges[1]),
603 (unsigned long long)part_stat_read(hd, sectors[1]),
604 jiffies_to_msecs(part_stat_read(hd, ticks[1])),
605 hd->in_flight,
606 jiffies_to_msecs(part_stat_read(hd, io_ticks)),
607 jiffies_to_msecs(part_stat_read(hd, time_in_queue))
608 );
593 } 609 }
594 610
595 return 0; 611 return 0;
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 44beb17e8090..d00293ba3b45 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -751,15 +751,15 @@ gettgt(struct aoedev *d, char *addr)
751} 751}
752 752
753static inline void 753static inline void
754diskstats(struct gendisk *disk, struct bio *bio, ulong duration) 754diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector)
755{ 755{
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 758
759 disk_stat_inc(disk, ios[rw]); 759 all_stat_inc(disk, ios[rw], sector);
760 disk_stat_add(disk, ticks[rw], duration); 760 all_stat_add(disk, ticks[rw], duration, sector);
761 disk_stat_add(disk, sectors[rw], n_sect); 761 all_stat_add(disk, sectors[rw], n_sect, sector);
762 disk_stat_add(disk, io_ticks, duration); 762 all_stat_add(disk, io_ticks, duration, sector);
763} 763}
764 764
765void 765void
@@ -879,7 +879,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
879 } 879 }
880 880
881 if (buf && --buf->nframesout == 0 && buf->resid == 0) { 881 if (buf && --buf->nframesout == 0 && buf->resid == 0) {
882 diskstats(d->gd, buf->bio, jiffies - buf->stime); 882 diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector);
883 n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; 883 n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
884 bio_endio(buf->bio, n); 884 bio_endio(buf->bio, n);
885 mempool_free(buf, d->bufpool); 885 mempool_free(buf, d->bufpool);
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 9a64045ff845..03f808c5b79d 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -18,6 +18,7 @@
18#include <linux/fs.h> 18#include <linux/fs.h>
19#include <linux/kmod.h> 19#include <linux/kmod.h>
20#include <linux/ctype.h> 20#include <linux/ctype.h>
21#include <linux/genhd.h>
21 22
22#include "check.h" 23#include "check.h"
23 24
@@ -215,9 +216,25 @@ static ssize_t part_stat_show(struct device *dev,
215{ 216{
216 struct hd_struct *p = dev_to_part(dev); 217 struct hd_struct *p = dev_to_part(dev);
217 218
218 return sprintf(buf, "%8u %8llu %8u %8llu\n", 219 preempt_disable();
219 p->ios[0], (unsigned long long)p->sectors[0], 220 part_round_stats(p);
220 p->ios[1], (unsigned long long)p->sectors[1]); 221 preempt_enable();
222 return sprintf(buf,
223 "%8lu %8lu %8llu %8u "
224 "%8lu %8lu %8llu %8u "
225 "%8u %8u %8u"
226 "\n",
227 part_stat_read(p, ios[READ]),
228 part_stat_read(p, merges[READ]),
229 (unsigned long long)part_stat_read(p, sectors[READ]),
230 jiffies_to_msecs(part_stat_read(p, ticks[READ])),
231 part_stat_read(p, ios[WRITE]),
232 part_stat_read(p, merges[WRITE]),
233 (unsigned long long)part_stat_read(p, sectors[WRITE]),
234 jiffies_to_msecs(part_stat_read(p, ticks[WRITE])),
235 p->in_flight,
236 jiffies_to_msecs(part_stat_read(p, io_ticks)),
237 jiffies_to_msecs(part_stat_read(p, time_in_queue)));
221} 238}
222 239
223#ifdef CONFIG_FAIL_MAKE_REQUEST 240#ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -273,6 +290,7 @@ static struct attribute_group *part_attr_groups[] = {
273static void part_release(struct device *dev) 290static void part_release(struct device *dev)
274{ 291{
275 struct hd_struct *p = dev_to_part(dev); 292 struct hd_struct *p = dev_to_part(dev);
293 free_part_stats(p);
276 kfree(p); 294 kfree(p);
277} 295}
278 296
@@ -312,8 +330,7 @@ void delete_partition(struct gendisk *disk, int part)
312 disk->part[part-1] = NULL; 330 disk->part[part-1] = NULL;
313 p->start_sect = 0; 331 p->start_sect = 0;
314 p->nr_sects = 0; 332 p->nr_sects = 0;
315 p->ios[0] = p->ios[1] = 0; 333 part_stat_set_all(p, 0);
316 p->sectors[0] = p->sectors[1] = 0;
317 kobject_put(p->holder_dir); 334 kobject_put(p->holder_dir);
318 device_del(&p->dev); 335 device_del(&p->dev);
319 put_device(&p->dev); 336 put_device(&p->dev);
@@ -336,6 +353,10 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
336 if (!p) 353 if (!p)
337 return; 354 return;
338 355
356 if (!init_part_stats(p)) {
357 kfree(p);
358 return;
359 }
339 p->start_sect = start; 360 p->start_sect = start;
340 p->nr_sects = len; 361 p->nr_sects = len;
341 p->partno = part; 362 p->partno = part;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 90392a9d7a9c..e1888cc5b8ae 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -137,7 +137,9 @@ enum rq_flag_bits {
137#define BLK_MAX_CDB 16 137#define BLK_MAX_CDB 16
138 138
139/* 139/*
140 * try to put the fields that are referenced together in the same cacheline 140 * try to put the fields that are referenced together in the same cacheline.
141 * if you modify this structure, be sure to check block/blk-core.c:rq_init()
142 * as well!
141 */ 143 */
142struct request { 144struct request {
143 struct list_head queuelist; 145 struct list_head queuelist;
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 1dbea0ac5693..09a3b18918c7 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -91,16 +91,31 @@ struct partition {
91 __le32 nr_sects; /* nr of sectors in partition */ 91 __le32 nr_sects; /* nr of sectors in partition */
92} __attribute__((packed)); 92} __attribute__((packed));
93 93
94struct disk_stats {
95 unsigned long sectors[2]; /* READs and WRITEs */
96 unsigned long ios[2];
97 unsigned long merges[2];
98 unsigned long ticks[2];
99 unsigned long io_ticks;
100 unsigned long time_in_queue;
101};
102
94struct hd_struct { 103struct hd_struct {
95 sector_t start_sect; 104 sector_t start_sect;
96 sector_t nr_sects; 105 sector_t nr_sects;
97 struct device dev; 106 struct device dev;
98 struct kobject *holder_dir; 107 struct kobject *holder_dir;
99 unsigned ios[2], sectors[2]; /* READs and WRITEs */
100 int policy, partno; 108 int policy, partno;
101#ifdef CONFIG_FAIL_MAKE_REQUEST 109#ifdef CONFIG_FAIL_MAKE_REQUEST
102 int make_it_fail; 110 int make_it_fail;
103#endif 111#endif
112 unsigned long stamp;
113 int in_flight;
114#ifdef CONFIG_SMP
115 struct disk_stats *dkstats;
116#else
117 struct disk_stats dkstats;
118#endif
104}; 119};
105 120
106#define GENHD_FL_REMOVABLE 1 121#define GENHD_FL_REMOVABLE 1
@@ -111,15 +126,7 @@ struct hd_struct {
111#define GENHD_FL_SUPPRESS_PARTITION_INFO 32 126#define GENHD_FL_SUPPRESS_PARTITION_INFO 32
112#define GENHD_FL_FAIL 64 127#define GENHD_FL_FAIL 64
113 128
114struct disk_stats { 129
115 unsigned long sectors[2]; /* READs and WRITEs */
116 unsigned long ios[2];
117 unsigned long merges[2];
118 unsigned long ticks[2];
119 unsigned long io_ticks;
120 unsigned long time_in_queue;
121};
122
123struct gendisk { 130struct gendisk {
124 int major; /* major number of driver */ 131 int major; /* major number of driver */
125 int first_minor; 132 int first_minor;
@@ -158,6 +165,20 @@ struct gendisk {
158 * The __ variants should only be called in critical sections. The full 165 * The __ variants should only be called in critical sections. The full
159 * variants disable/enable preemption. 166 * variants disable/enable preemption.
160 */ 167 */
168static inline struct hd_struct *get_part(struct gendisk *gendiskp,
169 sector_t sector)
170{
171 struct hd_struct *part;
172 int i;
173 for (i = 0; i < gendiskp->minors - 1; i++) {
174 part = gendiskp->part[i];
175 if (part && part->start_sect <= sector
176 && sector < part->start_sect + part->nr_sects)
177 return part;
178 }
179 return NULL;
180}
181
161#ifdef CONFIG_SMP 182#ifdef CONFIG_SMP
162#define __disk_stat_add(gendiskp, field, addnd) \ 183#define __disk_stat_add(gendiskp, field, addnd) \
163 (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd) 184 (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd)
@@ -177,15 +198,62 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
177 memset(per_cpu_ptr(gendiskp->dkstats, i), value, 198 memset(per_cpu_ptr(gendiskp->dkstats, i), value,
178 sizeof (struct disk_stats)); 199 sizeof (struct disk_stats));
179} 200}
201
202#define __part_stat_add(part, field, addnd) \
203 (per_cpu_ptr(part->dkstats, smp_processor_id())->field += addnd)
204
205#define __all_stat_add(gendiskp, field, addnd, sector) \
206({ \
207 struct hd_struct *part = get_part(gendiskp, sector); \
208 if (part) \
209 __part_stat_add(part, field, addnd); \
210 __disk_stat_add(gendiskp, field, addnd); \
211})
212
213#define part_stat_read(part, field) \
214({ \
215 typeof(part->dkstats->field) res = 0; \
216 int i; \
217 for_each_possible_cpu(i) \
218 res += per_cpu_ptr(part->dkstats, i)->field; \
219 res; \
220})
221
222static inline void part_stat_set_all(struct hd_struct *part, int value) {
223 int i;
224 for_each_possible_cpu(i)
225 memset(per_cpu_ptr(part->dkstats, i), value,
226 sizeof(struct disk_stats));
227}
180 228
181#else 229#else
182#define __disk_stat_add(gendiskp, field, addnd) \ 230#define __disk_stat_add(gendiskp, field, addnd) \
183 (gendiskp->dkstats.field += addnd) 231 (gendiskp->dkstats.field += addnd)
184#define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field) 232#define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field)
185 233
186static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) { 234static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
235{
187 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats)); 236 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats));
188} 237}
238
239#define __part_stat_add(part, field, addnd) \
240 (part->dkstats.field += addnd)
241
242#define __all_stat_add(gendiskp, field, addnd, sector) \
243({ \
244 struct hd_struct *part = get_part(gendiskp, sector); \
245 if (part) \
246 part->dkstats.field += addnd; \
247 __disk_stat_add(gendiskp, field, addnd); \
248})
249
250#define part_stat_read(part, field) (part->dkstats.field)
251
252static inline void part_stat_set_all(struct hd_struct *part, int value)
253{
254 memset(&part->dkstats, value, sizeof(struct disk_stats));
255}
256
189#endif 257#endif
190 258
191#define disk_stat_add(gendiskp, field, addnd) \ 259#define disk_stat_add(gendiskp, field, addnd) \
@@ -206,6 +274,45 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
206#define disk_stat_sub(gendiskp, field, subnd) \ 274#define disk_stat_sub(gendiskp, field, subnd) \
207 disk_stat_add(gendiskp, field, -subnd) 275 disk_stat_add(gendiskp, field, -subnd)
208 276
277#define part_stat_add(gendiskp, field, addnd) \
278 do { \
279 preempt_disable(); \
280 __part_stat_add(gendiskp, field, addnd);\
281 preempt_enable(); \
282 } while (0)
283
284#define __part_stat_dec(gendiskp, field) __part_stat_add(gendiskp, field, -1)
285#define part_stat_dec(gendiskp, field) part_stat_add(gendiskp, field, -1)
286
287#define __part_stat_inc(gendiskp, field) __part_stat_add(gendiskp, field, 1)
288#define part_stat_inc(gendiskp, field) part_stat_add(gendiskp, field, 1)
289
290#define __part_stat_sub(gendiskp, field, subnd) \
291 __part_stat_add(gendiskp, field, -subnd)
292#define part_stat_sub(gendiskp, field, subnd) \
293 part_stat_add(gendiskp, field, -subnd)
294
295#define all_stat_add(gendiskp, field, addnd, sector) \
296 do { \
297 preempt_disable(); \
298 __all_stat_add(gendiskp, field, addnd, sector); \
299 preempt_enable(); \
300 } while (0)
301
302#define __all_stat_dec(gendiskp, field, sector) \
303 __all_stat_add(gendiskp, field, -1, sector)
304#define all_stat_dec(gendiskp, field, sector) \
305 all_stat_add(gendiskp, field, -1, sector)
306
307#define __all_stat_inc(gendiskp, field, sector) \
308 __all_stat_add(gendiskp, field, 1, sector)
309#define all_stat_inc(gendiskp, field, sector) \
310 all_stat_add(gendiskp, field, 1, sector)
311
312#define __all_stat_sub(gendiskp, field, subnd, sector) \
313 __all_stat_add(gendiskp, field, -subnd, sector)
314#define all_stat_sub(gendiskp, field, subnd, sector) \
315 all_stat_add(gendiskp, field, -subnd, sector)
209 316
210/* Inlines to alloc and free disk stats in struct gendisk */ 317/* Inlines to alloc and free disk stats in struct gendisk */
211#ifdef CONFIG_SMP 318#ifdef CONFIG_SMP
@@ -221,6 +328,20 @@ static inline void free_disk_stats(struct gendisk *disk)
221{ 328{
222 free_percpu(disk->dkstats); 329 free_percpu(disk->dkstats);
223} 330}
331
332static inline int init_part_stats(struct hd_struct *part)
333{
334 part->dkstats = alloc_percpu(struct disk_stats);
335 if (!part->dkstats)
336 return 0;
337 return 1;
338}
339
340static inline void free_part_stats(struct hd_struct *part)
341{
342 free_percpu(part->dkstats);
343}
344
224#else /* CONFIG_SMP */ 345#else /* CONFIG_SMP */
225static inline int init_disk_stats(struct gendisk *disk) 346static inline int init_disk_stats(struct gendisk *disk)
226{ 347{
@@ -230,10 +351,20 @@ static inline int init_disk_stats(struct gendisk *disk)
230static inline void free_disk_stats(struct gendisk *disk) 351static inline void free_disk_stats(struct gendisk *disk)
231{ 352{
232} 353}
354
355static inline int init_part_stats(struct hd_struct *part)
356{
357 return 1;
358}
359
360static inline void free_part_stats(struct hd_struct *part)
361{
362}
233#endif /* CONFIG_SMP */ 363#endif /* CONFIG_SMP */
234 364
235/* drivers/block/ll_rw_blk.c */ 365/* drivers/block/ll_rw_blk.c */
236extern void disk_round_stats(struct gendisk *disk); 366extern void disk_round_stats(struct gendisk *disk);
367extern void part_round_stats(struct hd_struct *part);
237 368
238/* drivers/block/genhd.c */ 369/* drivers/block/genhd.c */
239extern int get_blkdev_list(char *, int); 370extern int get_blkdev_list(char *, int);