From ea5c48ab2a76559d4af39e1f7de137c0851ac0a5 Mon Sep 17 00:00:00 2001 From: Jerome Marchand Date: Fri, 8 Feb 2008 11:04:09 +0100 Subject: [PATCH] Enhanced partition statistics: core statistics This patch contain the core infrastructure of enhanced partition statistics. It adds to struct hd_struct the same stats data as struct gendisk and define basics function to manipulate them. Signed-off-by: Jerome Marchand Signed-off-by: Jens Axboe --- include/linux/genhd.h | 151 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 141 insertions(+), 10 deletions(-) diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 1dbea0ac5693..589830aca99d 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -91,6 +91,15 @@ struct partition { __le32 nr_sects; /* nr of sectors in partition */ } __attribute__((packed)); +struct disk_stats { + unsigned long sectors[2]; /* READs and WRITEs */ + unsigned long ios[2]; + unsigned long merges[2]; + unsigned long ticks[2]; + unsigned long io_ticks; + unsigned long time_in_queue; +}; + struct hd_struct { sector_t start_sect; sector_t nr_sects; @@ -100,6 +109,13 @@ struct hd_struct { int policy, partno; #ifdef CONFIG_FAIL_MAKE_REQUEST int make_it_fail; +#endif + unsigned long stamp; + int in_flight; +#ifdef CONFIG_SMP + struct disk_stats *dkstats; +#else + struct disk_stats dkstats; #endif }; @@ -111,15 +127,7 @@ struct hd_struct { #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 #define GENHD_FL_FAIL 64 -struct disk_stats { - unsigned long sectors[2]; /* READs and WRITEs */ - unsigned long ios[2]; - unsigned long merges[2]; - unsigned long ticks[2]; - unsigned long io_ticks; - unsigned long time_in_queue; -}; - + struct gendisk { int major; /* major number of driver */ int first_minor; @@ -158,6 +166,20 @@ struct gendisk { * The __ variants should only be called in critical sections. The full * variants disable/enable preemption. */ +static inline struct hd_struct *get_part(struct gendisk *gendiskp, + sector_t sector) +{ + struct hd_struct *part; + int i; + for (i = 0; i < gendiskp->minors - 1; i++) { + part = gendiskp->part[i]; + if (part && part->start_sect <= sector + && sector < part->start_sect + part->nr_sects) + return part; + } + return NULL; +} + #ifdef CONFIG_SMP #define __disk_stat_add(gendiskp, field, addnd) \ (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd) @@ -177,15 +199,62 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) { memset(per_cpu_ptr(gendiskp->dkstats, i), value, sizeof (struct disk_stats)); } + +#define __part_stat_add(part, field, addnd) \ + (per_cpu_ptr(part->dkstats, smp_processor_id())->field += addnd) + +#define __all_stat_add(gendiskp, field, addnd, sector) \ +({ \ + struct hd_struct *part = get_part(gendiskp, sector); \ + if (part) \ + __part_stat_add(part, field, addnd); \ + __disk_stat_add(gendiskp, field, addnd); \ +}) + +#define part_stat_read(part, field) \ +({ \ + typeof(part->dkstats->field) res = 0; \ + int i; \ + for_each_possible_cpu(i) \ + res += per_cpu_ptr(part->dkstats, i)->field; \ + res; \ +}) + +static inline void part_stat_set_all(struct hd_struct *part, int value) { + int i; + for_each_possible_cpu(i) + memset(per_cpu_ptr(part->dkstats, i), value, + sizeof(struct disk_stats)); +} #else #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) { +static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) +{ memset(&gendiskp->dkstats, value, sizeof (struct disk_stats)); } + +#define __part_stat_add(part, field, addnd) \ + (part->dkstats.field += addnd) + +#define __all_stat_add(gendiskp, field, addnd, sector) \ +({ \ + struct hd_struct *part = get_part(gendiskp, sector); \ + if (part) \ + part->dkstats.field += addnd; \ + __disk_stat_add(gendiskp, field, addnd); \ +}) + +#define part_stat_read(part, field) (part->dkstats.field) + +static inline void part_stat_set_all(struct hd_struct *part, int value) +{ + memset(&part->dkstats, value, sizeof(struct disk_stats)); +} + #endif #define disk_stat_add(gendiskp, field, addnd) \ @@ -206,6 +275,45 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) { #define disk_stat_sub(gendiskp, field, subnd) \ disk_stat_add(gendiskp, field, -subnd) +#define part_stat_add(gendiskp, field, addnd) \ + do { \ + preempt_disable(); \ + __part_stat_add(gendiskp, field, addnd);\ + preempt_enable(); \ + } while (0) + +#define __part_stat_dec(gendiskp, field) __part_stat_add(gendiskp, field, -1) +#define part_stat_dec(gendiskp, field) part_stat_add(gendiskp, field, -1) + +#define __part_stat_inc(gendiskp, field) __part_stat_add(gendiskp, field, 1) +#define part_stat_inc(gendiskp, field) part_stat_add(gendiskp, field, 1) + +#define __part_stat_sub(gendiskp, field, subnd) \ + __part_stat_add(gendiskp, field, -subnd) +#define part_stat_sub(gendiskp, field, subnd) \ + part_stat_add(gendiskp, field, -subnd) + +#define all_stat_add(gendiskp, field, addnd, sector) \ + do { \ + preempt_disable(); \ + __all_stat_add(gendiskp, field, addnd, sector); \ + preempt_enable(); \ + } while (0) + +#define __all_stat_dec(gendiskp, field, sector) \ + __all_stat_add(gendiskp, field, -1, sector) +#define all_stat_dec(gendiskp, field, sector) \ + all_stat_add(gendiskp, field, -1, sector) + +#define __all_stat_inc(gendiskp, field, sector) \ + __all_stat_add(gendiskp, field, 1, sector) +#define all_stat_inc(gendiskp, field, sector) \ + all_stat_add(gendiskp, field, 1, sector) + +#define __all_stat_sub(gendiskp, field, subnd, sector) \ + __all_stat_add(gendiskp, field, -subnd, sector) +#define all_stat_sub(gendiskp, field, subnd, sector) \ + all_stat_add(gendiskp, field, -subnd, sector) /* Inlines to alloc and free disk stats in struct gendisk */ #ifdef CONFIG_SMP @@ -221,6 +329,20 @@ static inline void free_disk_stats(struct gendisk *disk) { free_percpu(disk->dkstats); } + +static inline int init_part_stats(struct hd_struct *part) +{ + part->dkstats = alloc_percpu(struct disk_stats); + if (!part->dkstats) + return 0; + return 1; +} + +static inline void free_part_stats(struct hd_struct *part) +{ + free_percpu(part->dkstats); +} + #else /* CONFIG_SMP */ static inline int init_disk_stats(struct gendisk *disk) { @@ -230,6 +352,15 @@ static inline int init_disk_stats(struct gendisk *disk) static inline void free_disk_stats(struct gendisk *disk) { } + +static inline int init_part_stats(struct hd_struct *part) +{ + return 1; +} + +static inline void free_part_stats(struct hd_struct *part) +{ +} #endif /* CONFIG_SMP */ /* drivers/block/ll_rw_blk.c */ -- 2.34.1