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 <jmarchan@redhat.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

authored by Jerome Marchand and committed by Jens Axboe ea5c48ab 63a71386

+141 -10
+141 -10
include/linux/genhd.h
··· 91 __le32 nr_sects; /* nr of sectors in partition */ 92 } __attribute__((packed)); 93 94 struct hd_struct { 95 sector_t start_sect; 96 sector_t nr_sects; ··· 109 int policy, partno; 110 #ifdef CONFIG_FAIL_MAKE_REQUEST 111 int make_it_fail; 112 #endif 113 }; 114 ··· 127 #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 128 #define GENHD_FL_FAIL 64 129 130 - struct disk_stats { 131 - unsigned long sectors[2]; /* READs and WRITEs */ 132 - unsigned long ios[2]; 133 - unsigned long merges[2]; 134 - unsigned long ticks[2]; 135 - unsigned long io_ticks; 136 - unsigned long time_in_queue; 137 - }; 138 - 139 struct gendisk { 140 int major; /* major number of driver */ 141 int first_minor; ··· 166 * The __ variants should only be called in critical sections. The full 167 * variants disable/enable preemption. 168 */ 169 #ifdef CONFIG_SMP 170 #define __disk_stat_add(gendiskp, field, addnd) \ 171 (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd) ··· 199 memset(per_cpu_ptr(gendiskp->dkstats, i), value, 200 sizeof (struct disk_stats)); 201 } 202 203 #else 204 #define __disk_stat_add(gendiskp, field, addnd) \ 205 (gendiskp->dkstats.field += addnd) 206 #define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field) 207 208 - static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) { 209 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats)); 210 } 211 #endif 212 213 #define disk_stat_add(gendiskp, field, addnd) \ ··· 275 #define disk_stat_sub(gendiskp, field, subnd) \ 276 disk_stat_add(gendiskp, field, -subnd) 277 278 279 /* Inlines to alloc and free disk stats in struct gendisk */ 280 #ifdef CONFIG_SMP ··· 329 { 330 free_percpu(disk->dkstats); 331 } 332 #else /* CONFIG_SMP */ 333 static inline int init_disk_stats(struct gendisk *disk) 334 { ··· 350 } 351 352 static inline void free_disk_stats(struct gendisk *disk) 353 { 354 } 355 #endif /* CONFIG_SMP */
··· 91 __le32 nr_sects; /* nr of sectors in partition */ 92 } __attribute__((packed)); 93 94 + struct 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 + 103 struct hd_struct { 104 sector_t start_sect; 105 sector_t nr_sects; ··· 100 int policy, partno; 101 #ifdef CONFIG_FAIL_MAKE_REQUEST 102 int make_it_fail; 103 + #endif 104 + unsigned long stamp; 105 + int in_flight; 106 + #ifdef CONFIG_SMP 107 + struct disk_stats *dkstats; 108 + #else 109 + struct disk_stats dkstats; 110 #endif 111 }; 112 ··· 111 #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 112 #define GENHD_FL_FAIL 64 113 114 + 115 struct gendisk { 116 int major; /* major number of driver */ 117 int first_minor; ··· 158 * The __ variants should only be called in critical sections. The full 159 * variants disable/enable preemption. 160 */ 161 + static inline struct hd_struct *get_part(struct gendisk *gendiskp, 162 + sector_t sector) 163 + { 164 + struct hd_struct *part; 165 + int i; 166 + for (i = 0; i < gendiskp->minors - 1; i++) { 167 + part = gendiskp->part[i]; 168 + if (part && part->start_sect <= sector 169 + && sector < part->start_sect + part->nr_sects) 170 + return part; 171 + } 172 + return NULL; 173 + } 174 + 175 #ifdef CONFIG_SMP 176 #define __disk_stat_add(gendiskp, field, addnd) \ 177 (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd) ··· 177 memset(per_cpu_ptr(gendiskp->dkstats, i), value, 178 sizeof (struct disk_stats)); 179 } 180 + 181 + #define __part_stat_add(part, field, addnd) \ 182 + (per_cpu_ptr(part->dkstats, smp_processor_id())->field += addnd) 183 + 184 + #define __all_stat_add(gendiskp, field, addnd, sector) \ 185 + ({ \ 186 + struct hd_struct *part = get_part(gendiskp, sector); \ 187 + if (part) \ 188 + __part_stat_add(part, field, addnd); \ 189 + __disk_stat_add(gendiskp, field, addnd); \ 190 + }) 191 + 192 + #define part_stat_read(part, field) \ 193 + ({ \ 194 + typeof(part->dkstats->field) res = 0; \ 195 + int i; \ 196 + for_each_possible_cpu(i) \ 197 + res += per_cpu_ptr(part->dkstats, i)->field; \ 198 + res; \ 199 + }) 200 + 201 + static inline void part_stat_set_all(struct hd_struct *part, int value) { 202 + int i; 203 + for_each_possible_cpu(i) 204 + memset(per_cpu_ptr(part->dkstats, i), value, 205 + sizeof(struct disk_stats)); 206 + } 207 208 #else 209 #define __disk_stat_add(gendiskp, field, addnd) \ 210 (gendiskp->dkstats.field += addnd) 211 #define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field) 212 213 + static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) 214 + { 215 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats)); 216 } 217 + 218 + #define __part_stat_add(part, field, addnd) \ 219 + (part->dkstats.field += addnd) 220 + 221 + #define __all_stat_add(gendiskp, field, addnd, sector) \ 222 + ({ \ 223 + struct hd_struct *part = get_part(gendiskp, sector); \ 224 + if (part) \ 225 + part->dkstats.field += addnd; \ 226 + __disk_stat_add(gendiskp, field, addnd); \ 227 + }) 228 + 229 + #define part_stat_read(part, field) (part->dkstats.field) 230 + 231 + static inline void part_stat_set_all(struct hd_struct *part, int value) 232 + { 233 + memset(&part->dkstats, value, sizeof(struct disk_stats)); 234 + } 235 + 236 #endif 237 238 #define disk_stat_add(gendiskp, field, addnd) \ ··· 206 #define disk_stat_sub(gendiskp, field, subnd) \ 207 disk_stat_add(gendiskp, field, -subnd) 208 209 + #define part_stat_add(gendiskp, field, addnd) \ 210 + do { \ 211 + preempt_disable(); \ 212 + __part_stat_add(gendiskp, field, addnd);\ 213 + preempt_enable(); \ 214 + } while (0) 215 + 216 + #define __part_stat_dec(gendiskp, field) __part_stat_add(gendiskp, field, -1) 217 + #define part_stat_dec(gendiskp, field) part_stat_add(gendiskp, field, -1) 218 + 219 + #define __part_stat_inc(gendiskp, field) __part_stat_add(gendiskp, field, 1) 220 + #define part_stat_inc(gendiskp, field) part_stat_add(gendiskp, field, 1) 221 + 222 + #define __part_stat_sub(gendiskp, field, subnd) \ 223 + __part_stat_add(gendiskp, field, -subnd) 224 + #define part_stat_sub(gendiskp, field, subnd) \ 225 + part_stat_add(gendiskp, field, -subnd) 226 + 227 + #define all_stat_add(gendiskp, field, addnd, sector) \ 228 + do { \ 229 + preempt_disable(); \ 230 + __all_stat_add(gendiskp, field, addnd, sector); \ 231 + preempt_enable(); \ 232 + } while (0) 233 + 234 + #define __all_stat_dec(gendiskp, field, sector) \ 235 + __all_stat_add(gendiskp, field, -1, sector) 236 + #define all_stat_dec(gendiskp, field, sector) \ 237 + all_stat_add(gendiskp, field, -1, sector) 238 + 239 + #define __all_stat_inc(gendiskp, field, sector) \ 240 + __all_stat_add(gendiskp, field, 1, sector) 241 + #define all_stat_inc(gendiskp, field, sector) \ 242 + all_stat_add(gendiskp, field, 1, sector) 243 + 244 + #define __all_stat_sub(gendiskp, field, subnd, sector) \ 245 + __all_stat_add(gendiskp, field, -subnd, sector) 246 + #define all_stat_sub(gendiskp, field, subnd, sector) \ 247 + all_stat_add(gendiskp, field, -subnd, sector) 248 249 /* Inlines to alloc and free disk stats in struct gendisk */ 250 #ifdef CONFIG_SMP ··· 221 { 222 free_percpu(disk->dkstats); 223 } 224 + 225 + static inline int init_part_stats(struct hd_struct *part) 226 + { 227 + part->dkstats = alloc_percpu(struct disk_stats); 228 + if (!part->dkstats) 229 + return 0; 230 + return 1; 231 + } 232 + 233 + static inline void free_part_stats(struct hd_struct *part) 234 + { 235 + free_percpu(part->dkstats); 236 + } 237 + 238 #else /* CONFIG_SMP */ 239 static inline int init_disk_stats(struct gendisk *disk) 240 { ··· 228 } 229 230 static inline void free_disk_stats(struct gendisk *disk) 231 + { 232 + } 233 + 234 + static inline int init_part_stats(struct hd_struct *part) 235 + { 236 + return 1; 237 + } 238 + 239 + static inline void free_part_stats(struct hd_struct *part) 240 { 241 } 242 #endif /* CONFIG_SMP */