aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/genhd.h
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-08-25 06:47:21 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:06 -0400
commitc9959059161ddd7bf4670cf47367033d6b2f79c4 (patch)
tree6454db55f8e34361fe472358e10e0c5cfac1e366 /include/linux/genhd.h
parente71bf0d0ee89e51b92776391c5634938236977d5 (diff)
block: fix diskstats access
There are two variants of stat functions - ones prefixed with double underbars which don't care about preemption and ones without which disable preemption before manipulating per-cpu counters. It's unclear whether the underbarred ones assume that preemtion is disabled on entry as some callers don't do that. This patch unifies diskstats access by implementing disk_stat_lock() and disk_stat_unlock() which take care of both RCU (for partition access) and preemption (for per-cpu counter access). diskstats access should always be enclosed between the two functions. As such, there's no need for the versions which disables preemption. They're removed and double underbars ones are renamed to drop the underbars. As an extra argument is added, there's no danger of using the old version unconverted. disk_stat_lock() uses get_cpu() and returns the cpu index and all diskstat functions which access per-cpu counters now has @cpu argument to help RT. This change adds RCU or preemption operations at some places but also collapses several preemption ops into one at others. Overall, the performance difference should be negligible as all involved ops are very lightweight per-cpu ones. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'include/linux/genhd.h')
-rw-r--r--include/linux/genhd.h139
1 files changed, 57 insertions, 82 deletions
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 7fbba19e076b..ac8a901f2002 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -209,16 +209,24 @@ extern void disk_part_iter_exit(struct disk_part_iter *piter);
209extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, 209extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
210 sector_t sector); 210 sector_t sector);
211 211
212/* 212/*
213 * Macros to operate on percpu disk statistics: 213 * Macros to operate on percpu disk statistics:
214 * 214 *
215 * The __ variants should only be called in critical sections. The full 215 * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
216 * variants disable/enable preemption. 216 * and should be called between disk_stat_lock() and
217 * disk_stat_unlock().
218 *
219 * part_stat_read() can be called at any time.
220 *
221 * part_stat_{add|set_all}() and {init|free}_part_stats are for
222 * internal use only.
217 */ 223 */
218
219#ifdef CONFIG_SMP 224#ifdef CONFIG_SMP
220#define __disk_stat_add(gendiskp, field, addnd) \ 225#define disk_stat_lock() ({ rcu_read_lock(); get_cpu(); })
221 (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd) 226#define disk_stat_unlock() do { put_cpu(); rcu_read_unlock(); } while (0)
227
228#define disk_stat_add(cpu, gendiskp, field, addnd) \
229 (per_cpu_ptr(gendiskp->dkstats, cpu)->field += addnd)
222 230
223#define disk_stat_read(gendiskp, field) \ 231#define disk_stat_read(gendiskp, field) \
224({ \ 232({ \
@@ -229,7 +237,8 @@ extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
229 res; \ 237 res; \
230}) 238})
231 239
232static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) { 240static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
241{
233 int i; 242 int i;
234 243
235 for_each_possible_cpu(i) 244 for_each_possible_cpu(i)
@@ -237,14 +246,14 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
237 sizeof(struct disk_stats)); 246 sizeof(struct disk_stats));
238} 247}
239 248
240#define __part_stat_add(part, field, addnd) \ 249#define part_stat_add(cpu, part, field, addnd) \
241 (per_cpu_ptr(part->dkstats, smp_processor_id())->field += addnd) 250 (per_cpu_ptr(part->dkstats, cpu)->field += addnd)
242 251
243#define __all_stat_add(gendiskp, part, field, addnd, sector) \ 252#define all_stat_add(cpu, gendiskp, part, field, addnd, sector) \
244({ \ 253({ \
245 if (part) \ 254 if (part) \
246 __part_stat_add(part, field, addnd); \ 255 part_stat_add(cpu, part, field, addnd); \
247 __disk_stat_add(gendiskp, field, addnd); \ 256 disk_stat_add(cpu, gendiskp, field, addnd); \
248}) 257})
249 258
250#define part_stat_read(part, field) \ 259#define part_stat_read(part, field) \
@@ -264,10 +273,13 @@ static inline void part_stat_set_all(struct hd_struct *part, int value)
264 memset(per_cpu_ptr(part->dkstats, i), value, 273 memset(per_cpu_ptr(part->dkstats, i), value,
265 sizeof(struct disk_stats)); 274 sizeof(struct disk_stats));
266} 275}
267 276
268#else /* !CONFIG_SMP */ 277#else /* !CONFIG_SMP */
269#define __disk_stat_add(gendiskp, field, addnd) \ 278#define disk_stat_lock() ({ rcu_read_lock(); 0; })
270 (gendiskp->dkstats.field += addnd) 279#define disk_stat_unlock() rcu_read_unlock()
280
281#define disk_stat_add(cpu, gendiskp, field, addnd) \
282 (gendiskp->dkstats.field += addnd)
271#define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field) 283#define disk_stat_read(gendiskp, field) (gendiskp->dkstats.field)
272 284
273static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) 285static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
@@ -275,14 +287,14 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
275 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats)); 287 memset(&gendiskp->dkstats, value, sizeof (struct disk_stats));
276} 288}
277 289
278#define __part_stat_add(part, field, addnd) \ 290#define part_stat_add(cpu, part, field, addnd) \
279 (part->dkstats.field += addnd) 291 (part->dkstats.field += addnd)
280 292
281#define __all_stat_add(gendiskp, part, field, addnd, sector) \ 293#define all_stat_add(cpu, gendiskp, part, field, addnd, sector) \
282({ \ 294({ \
283 if (part) \ 295 if (part) \
284 part->dkstats.field += addnd; \ 296 part_stat_add(cpu, part, field, addnd); \
285 __disk_stat_add(gendiskp, field, addnd); \ 297 disk_stat_add(cpu, gendiskp, field, addnd); \
286}) 298})
287 299
288#define part_stat_read(part, field) (part->dkstats.field) 300#define part_stat_read(part, field) (part->dkstats.field)
@@ -294,63 +306,26 @@ static inline void part_stat_set_all(struct hd_struct *part, int value)
294 306
295#endif /* CONFIG_SMP */ 307#endif /* CONFIG_SMP */
296 308
297#define disk_stat_add(gendiskp, field, addnd) \ 309#define disk_stat_dec(cpu, gendiskp, field) \
298 do { \ 310 disk_stat_add(cpu, gendiskp, field, -1)
299 preempt_disable(); \ 311#define disk_stat_inc(cpu, gendiskp, field) \
300 __disk_stat_add(gendiskp, field, addnd); \ 312 disk_stat_add(cpu, gendiskp, field, 1)
301 preempt_enable(); \ 313#define disk_stat_sub(cpu, gendiskp, field, subnd) \
302 } while (0) 314 disk_stat_add(cpu, gendiskp, field, -subnd)
303 315
304#define __disk_stat_dec(gendiskp, field) __disk_stat_add(gendiskp, field, -1) 316#define part_stat_dec(cpu, gendiskp, field) \
305#define disk_stat_dec(gendiskp, field) disk_stat_add(gendiskp, field, -1) 317 part_stat_add(cpu, gendiskp, field, -1)
306 318#define part_stat_inc(cpu, gendiskp, field) \
307#define __disk_stat_inc(gendiskp, field) __disk_stat_add(gendiskp, field, 1) 319 part_stat_add(cpu, gendiskp, field, 1)
308#define disk_stat_inc(gendiskp, field) disk_stat_add(gendiskp, field, 1) 320#define part_stat_sub(cpu, gendiskp, field, subnd) \
309 321 part_stat_add(cpu, gendiskp, field, -subnd)
310#define __disk_stat_sub(gendiskp, field, subnd) \ 322
311 __disk_stat_add(gendiskp, field, -subnd) 323#define all_stat_dec(cpu, gendiskp, field, sector) \
312#define disk_stat_sub(gendiskp, field, subnd) \ 324 all_stat_add(cpu, gendiskp, field, -1, sector)
313 disk_stat_add(gendiskp, field, -subnd) 325#define all_stat_inc(cpu, gendiskp, part, field, sector) \
314 326 all_stat_add(cpu, gendiskp, part, field, 1, sector)
315#define part_stat_add(gendiskp, field, addnd) \ 327#define all_stat_sub(cpu, gendiskp, part, field, subnd, sector) \
316 do { \ 328 all_stat_add(cpu, gendiskp, part, field, -subnd, sector)
317 preempt_disable(); \
318 __part_stat_add(gendiskp, field, addnd);\
319 preempt_enable(); \
320 } while (0)
321
322#define __part_stat_dec(gendiskp, field) __part_stat_add(gendiskp, field, -1)
323#define part_stat_dec(gendiskp, field) part_stat_add(gendiskp, field, -1)
324
325#define __part_stat_inc(gendiskp, field) __part_stat_add(gendiskp, field, 1)
326#define part_stat_inc(gendiskp, field) part_stat_add(gendiskp, field, 1)
327
328#define __part_stat_sub(gendiskp, field, subnd) \
329 __part_stat_add(gendiskp, field, -subnd)
330#define part_stat_sub(gendiskp, field, subnd) \
331 part_stat_add(gendiskp, field, -subnd)
332
333#define all_stat_add(gendiskp, part, field, addnd, sector) \
334 do { \
335 preempt_disable(); \
336 __all_stat_add(gendiskp, part, field, addnd, sector); \
337 preempt_enable(); \
338 } while (0)
339
340#define __all_stat_dec(gendiskp, field, sector) \
341 __all_stat_add(gendiskp, field, -1, sector)
342#define all_stat_dec(gendiskp, field, sector) \
343 all_stat_add(gendiskp, field, -1, sector)
344
345#define __all_stat_inc(gendiskp, part, field, sector) \
346 __all_stat_add(gendiskp, part, field, 1, sector)
347#define all_stat_inc(gendiskp, part, field, sector) \
348 all_stat_add(gendiskp, part, field, 1, sector)
349
350#define __all_stat_sub(gendiskp, part, field, subnd, sector) \
351 __all_stat_add(gendiskp, part, field, -subnd, sector)
352#define all_stat_sub(gendiskp, part, field, subnd, sector) \
353 all_stat_add(gendiskp, part, field, -subnd, sector)
354 329
355/* Inlines to alloc and free disk stats in struct gendisk */ 330/* Inlines to alloc and free disk stats in struct gendisk */
356#ifdef CONFIG_SMP 331#ifdef CONFIG_SMP
@@ -401,8 +376,8 @@ static inline void free_part_stats(struct hd_struct *part)
401#endif /* CONFIG_SMP */ 376#endif /* CONFIG_SMP */
402 377
403/* drivers/block/ll_rw_blk.c */ 378/* drivers/block/ll_rw_blk.c */
404extern void disk_round_stats(struct gendisk *disk); 379extern void disk_round_stats(int cpu, struct gendisk *disk);
405extern void part_round_stats(struct hd_struct *part); 380extern void part_round_stats(int cpu, struct hd_struct *part);
406 381
407/* drivers/block/genhd.c */ 382/* drivers/block/genhd.c */
408extern int get_blkdev_list(char *, int); 383extern int get_blkdev_list(char *, int);