1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _LINUX_PART_STAT_H 3 #define _LINUX_PART_STAT_H 4 5 #include <linux/genhd.h> 6 7 /* 8 * Macros to operate on percpu disk statistics: 9 * 10 * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters 11 * and should be called between disk_stat_lock() and 12 * disk_stat_unlock(). 13 * 14 * part_stat_read() can be called at any time. 15 * 16 * part_stat_{add|set_all}() and {init|free}_part_stats are for 17 * internal use only. 18 */ 19 #ifdef CONFIG_SMP 20 #define part_stat_lock() ({ rcu_read_lock(); get_cpu(); }) 21 #define part_stat_unlock() do { put_cpu(); rcu_read_unlock(); } while (0) 22 23 #define part_stat_get_cpu(part, field, cpu) \ 24 (per_cpu_ptr((part)->dkstats, (cpu))->field) 25 26 #define part_stat_get(part, field) \ 27 part_stat_get_cpu(part, field, smp_processor_id()) 28 29 #define part_stat_read(part, field) \ 30 ({ \ 31 typeof((part)->dkstats->field) res = 0; \ 32 unsigned int _cpu; \ 33 for_each_possible_cpu(_cpu) \ 34 res += per_cpu_ptr((part)->dkstats, _cpu)->field; \ 35 res; \ 36 }) 37 38 static inline void part_stat_set_all(struct hd_struct *part, int value) 39 { 40 int i; 41 42 for_each_possible_cpu(i) 43 memset(per_cpu_ptr(part->dkstats, i), value, 44 sizeof(struct disk_stats)); 45 } 46 47 static inline int init_part_stats(struct hd_struct *part) 48 { 49 part->dkstats = alloc_percpu(struct disk_stats); 50 if (!part->dkstats) 51 return 0; 52 return 1; 53 } 54 55 static inline void free_part_stats(struct hd_struct *part) 56 { 57 free_percpu(part->dkstats); 58 } 59 60 #else /* !CONFIG_SMP */ 61 #define part_stat_lock() ({ rcu_read_lock(); 0; }) 62 #define part_stat_unlock() rcu_read_unlock() 63 64 #define part_stat_get(part, field) ((part)->dkstats.field) 65 #define part_stat_get_cpu(part, field, cpu) part_stat_get(part, field) 66 #define part_stat_read(part, field) part_stat_get(part, field) 67 68 static inline void part_stat_set_all(struct hd_struct *part, int value) 69 { 70 memset(&part->dkstats, value, sizeof(struct disk_stats)); 71 } 72 73 static inline int init_part_stats(struct hd_struct *part) 74 { 75 return 1; 76 } 77 78 static inline void free_part_stats(struct hd_struct *part) 79 { 80 } 81 82 #endif /* CONFIG_SMP */ 83 84 #define part_stat_read_accum(part, field) \ 85 (part_stat_read(part, field[STAT_READ]) + \ 86 part_stat_read(part, field[STAT_WRITE]) + \ 87 part_stat_read(part, field[STAT_DISCARD])) 88 89 #define __part_stat_add(part, field, addnd) \ 90 (part_stat_get(part, field) += (addnd)) 91 92 #define part_stat_add(part, field, addnd) do { \ 93 __part_stat_add((part), field, addnd); \ 94 if ((part)->partno) \ 95 __part_stat_add(&part_to_disk((part))->part0, \ 96 field, addnd); \ 97 } while (0) 98 99 #define part_stat_dec(gendiskp, field) \ 100 part_stat_add(gendiskp, field, -1) 101 #define part_stat_inc(gendiskp, field) \ 102 part_stat_add(gendiskp, field, 1) 103 #define part_stat_sub(gendiskp, field, subnd) \ 104 part_stat_add(gendiskp, field, -subnd) 105 106 #define part_stat_local_dec(gendiskp, field) \ 107 local_dec(&(part_stat_get(gendiskp, field))) 108 #define part_stat_local_inc(gendiskp, field) \ 109 local_inc(&(part_stat_get(gendiskp, field))) 110 #define part_stat_local_read(gendiskp, field) \ 111 local_read(&(part_stat_get(gendiskp, field))) 112 #define part_stat_local_read_cpu(gendiskp, field, cpu) \ 113 local_read(&(part_stat_get_cpu(gendiskp, field, cpu))) 114 115 #endif /* _LINUX_PART_STAT_H */ 116