Commit d38948f6 authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] disk stats preempt safety

The per-cpu disk stats are being updated in a non-preempt-safe manner in a
couple of places.

The patch introduces introduces preempt and non-preempt versions of the
statistics code and updates the block code to use the appropriate ones.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 29c6097f
......@@ -2058,13 +2058,13 @@ void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
return;
if (rw == READ) {
disk_stat_add(rq->rq_disk, read_sectors, nr_sectors);
__disk_stat_add(rq->rq_disk, read_sectors, nr_sectors);
if (!new_io)
disk_stat_inc(rq->rq_disk, read_merges);
__disk_stat_inc(rq->rq_disk, read_merges);
} else if (rw == WRITE) {
disk_stat_add(rq->rq_disk, write_sectors, nr_sectors);
__disk_stat_add(rq->rq_disk, write_sectors, nr_sectors);
if (!new_io)
disk_stat_inc(rq->rq_disk, write_merges);
__disk_stat_inc(rq->rq_disk, write_merges);
}
if (new_io) {
disk_round_stats(rq->rq_disk);
......@@ -2110,12 +2110,12 @@ void disk_round_stats(struct gendisk *disk)
{
unsigned long now = jiffies;
disk_stat_add(disk, time_in_queue,
__disk_stat_add(disk, time_in_queue,
disk->in_flight * (now - disk->stamp));
disk->stamp = now;
if (disk->in_flight)
disk_stat_add(disk, io_ticks, (now - disk->stamp_idle));
__disk_stat_add(disk, io_ticks, (now - disk->stamp_idle));
disk->stamp_idle = now;
}
......@@ -2982,12 +2982,12 @@ void end_that_request_last(struct request *req)
unsigned long duration = jiffies - req->start_time;
switch (rq_data_dir(req)) {
case WRITE:
disk_stat_inc(disk, writes);
disk_stat_add(disk, write_ticks, duration);
__disk_stat_inc(disk, writes);
__disk_stat_add(disk, write_ticks, duration);
break;
case READ:
disk_stat_inc(disk, reads);
disk_stat_add(disk, read_ticks, duration);
__disk_stat_inc(disk, reads);
__disk_stat_add(disk, read_ticks, duration);
break;
}
disk_round_stats(disk);
......
......@@ -129,13 +129,14 @@ struct gendisk {
/*
* Macros to operate on percpu disk statistics:
* Since writes to disk_stats are serialised through the queue_lock,
* smp_processor_id() should be enough to get to the per_cpu versions
* of statistics counters
*
* The __ variants should only be called in critical sections. The full
* variants disable/enable preemption.
*/
#ifdef CONFIG_SMP
#define disk_stat_add(gendiskp, field, addnd) \
#define __disk_stat_add(gendiskp, field, addnd) \
(per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd)
#define disk_stat_read(gendiskp, field) \
({ \
typeof(gendiskp->dkstats->field) res = 0; \
......@@ -159,7 +160,8 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
}
#else
#define disk_stat_add(gendiskp, field, addnd) (gendiskp->dkstats.field += addnd)
#define __disk_stat_add(gendiskp, field, addnd) \
(gendiskp->dkstats.field += addnd)
#define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field)
static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
......@@ -167,8 +169,21 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
}
#endif
#define disk_stat_inc(gendiskp, field) disk_stat_add(gendiskp, field, 1)
#define disk_stat_add(gendiskp, field, addnd) \
do { \
preempt_disable(); \
__disk_stat_add(gendiskp, field, addnd); \
preempt_enable(); \
} while (0)
#define __disk_stat_dec(gendiskp, field) __disk_stat_add(gendiskp, field, -1)
#define disk_stat_dec(gendiskp, field) disk_stat_add(gendiskp, field, -1)
#define __disk_stat_inc(gendiskp, field) __disk_stat_add(gendiskp, field, 1)
#define disk_stat_inc(gendiskp, field) disk_stat_add(gendiskp, field, 1)
#define __disk_stat_sub(gendiskp, field, subnd) \
__disk_stat_add(gendiskp, field, -subnd)
#define disk_stat_sub(gendiskp, field, subnd) \
disk_stat_add(gendiskp, field, -subnd)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment