xref: /linux-6.15/include/linux/part_stat.h (revision 82d00a93)
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