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 91 __le32 nr_sects; /* nr of sectors in partition */ 92 92 } __attribute__((packed)); 93 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 + 94 103 struct hd_struct { 95 104 sector_t start_sect; 96 105 sector_t nr_sects; ··· 109 100 int policy, partno; 110 101 #ifdef CONFIG_FAIL_MAKE_REQUEST 111 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; 112 110 #endif 113 111 }; 114 112 ··· 127 111 #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 128 112 #define GENHD_FL_FAIL 64 129 113 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 - 114 + 139 115 struct gendisk { 140 116 int major; /* major number of driver */ 141 117 int first_minor; ··· 166 158 * The __ variants should only be called in critical sections. The full 167 159 * variants disable/enable preemption. 168 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 + 169 175 #ifdef CONFIG_SMP 170 176 #define __disk_stat_add(gendiskp, field, addnd) \ 171 177 (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd) ··· 199 177 memset(per_cpu_ptr(gendiskp->dkstats, i), value, 200 178 sizeof (struct disk_stats)); 201 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 + } 202 207 203 208 #else 204 209 #define __disk_stat_add(gendiskp, field, addnd) \ 205 210 (gendiskp->dkstats.field += addnd) 206 211 #define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field) 207 212 208 - static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) { 213 + static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) 214 + { 209 215 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats)); 210 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 + 211 236 #endif 212 237 213 238 #define disk_stat_add(gendiskp, field, addnd) \ ··· 275 206 #define disk_stat_sub(gendiskp, field, subnd) \ 276 207 disk_stat_add(gendiskp, field, -subnd) 277 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) 278 248 279 249 /* Inlines to alloc and free disk stats in struct gendisk */ 280 250 #ifdef CONFIG_SMP ··· 329 221 { 330 222 free_percpu(disk->dkstats); 331 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 + 332 238 #else /* CONFIG_SMP */ 333 239 static inline int init_disk_stats(struct gendisk *disk) 334 240 { ··· 350 228 } 351 229 352 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) 353 240 { 354 241 } 355 242 #endif /* CONFIG_SMP */