Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */
2 : : #ifndef _LINUX_PAGE_REF_H
3 : : #define _LINUX_PAGE_REF_H
4 : :
5 : : #include <linux/atomic.h>
6 : : #include <linux/mm_types.h>
7 : : #include <linux/page-flags.h>
8 : : #include <linux/tracepoint-defs.h>
9 : :
10 : : extern struct tracepoint __tracepoint_page_ref_set;
11 : : extern struct tracepoint __tracepoint_page_ref_mod;
12 : : extern struct tracepoint __tracepoint_page_ref_mod_and_test;
13 : : extern struct tracepoint __tracepoint_page_ref_mod_and_return;
14 : : extern struct tracepoint __tracepoint_page_ref_mod_unless;
15 : : extern struct tracepoint __tracepoint_page_ref_freeze;
16 : : extern struct tracepoint __tracepoint_page_ref_unfreeze;
17 : :
18 : : #ifdef CONFIG_DEBUG_PAGE_REF
19 : :
20 : : /*
21 : : * Ideally we would want to use the trace_<tracepoint>_enabled() helper
22 : : * functions. But due to include header file issues, that is not
23 : : * feasible. Instead we have to open code the static key functions.
24 : : *
25 : : * See trace_##name##_enabled(void) in include/linux/tracepoint.h
26 : : */
27 : : #define page_ref_tracepoint_active(t) static_key_false(&(t).key)
28 : :
29 : : extern void __page_ref_set(struct page *page, int v);
30 : : extern void __page_ref_mod(struct page *page, int v);
31 : : extern void __page_ref_mod_and_test(struct page *page, int v, int ret);
32 : : extern void __page_ref_mod_and_return(struct page *page, int v, int ret);
33 : : extern void __page_ref_mod_unless(struct page *page, int v, int u);
34 : : extern void __page_ref_freeze(struct page *page, int v, int ret);
35 : : extern void __page_ref_unfreeze(struct page *page, int v);
36 : :
37 : : #else
38 : :
39 : : #define page_ref_tracepoint_active(t) false
40 : :
41 : : static inline void __page_ref_set(struct page *page, int v)
42 : : {
43 : : }
44 : : static inline void __page_ref_mod(struct page *page, int v)
45 : : {
46 : : }
47 : : static inline void __page_ref_mod_and_test(struct page *page, int v, int ret)
48 : : {
49 : : }
50 : : static inline void __page_ref_mod_and_return(struct page *page, int v, int ret)
51 : : {
52 : : }
53 : : static inline void __page_ref_mod_unless(struct page *page, int v, int u)
54 : : {
55 : : }
56 : : static inline void __page_ref_freeze(struct page *page, int v, int ret)
57 : : {
58 : : }
59 : : static inline void __page_ref_unfreeze(struct page *page, int v)
60 : : {
61 : : }
62 : :
63 : : #endif
64 : :
65 : 12345666 : static inline int page_ref_count(struct page *page)
66 : : {
67 : 12345666 : return atomic_read(&page->_refcount);
68 : : }
69 : :
70 : 794 : static inline int page_count(struct page *page)
71 : : {
72 [ - + - - : 794 : return atomic_read(&compound_head(page)->_refcount);
- + # # #
# ]
73 : : }
74 : :
75 : 11513420 : static inline void set_page_count(struct page *page, int v)
76 : : {
77 : 11471030 : atomic_set(&page->_refcount, v);
78 [ # # ]: 11513420 : if (page_ref_tracepoint_active(__tracepoint_page_ref_set))
79 : : __page_ref_set(page, v);
80 : : }
81 : :
82 : : /*
83 : : * Setup the page count before being freed into the page allocator for
84 : : * the first time (boot or memory hotplug)
85 : : */
86 : 42390 : static inline void init_page_count(struct page *page)
87 : : {
88 : 42390 : set_page_count(page, 1);
89 : : }
90 : :
91 : 39476 : static inline void page_ref_add(struct page *page, int nr)
92 : : {
93 : 39476 : atomic_add(nr, &page->_refcount);
94 [ # # ]: 39476 : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod))
95 : : __page_ref_mod(page, nr);
96 : : }
97 : :
98 : 0 : static inline void page_ref_sub(struct page *page, int nr)
99 : : {
100 : 0 : atomic_sub(nr, &page->_refcount);
101 [ # # ]: 0 : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod))
102 : : __page_ref_mod(page, -nr);
103 : 0 : }
104 : :
105 : 4674428 : static inline void page_ref_inc(struct page *page)
106 : : {
107 : 4674278 : atomic_inc(&page->_refcount);
108 [ - + - + : 4674278 : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod))
+ + + + ]
109 : : __page_ref_mod(page, 1);
110 : 0 : }
111 : :
112 : : static inline void page_ref_dec(struct page *page)
113 : : {
114 : : atomic_dec(&page->_refcount);
115 : : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod))
116 : : __page_ref_mod(page, -1);
117 : : }
118 : :
119 : 0 : static inline int page_ref_sub_and_test(struct page *page, int nr)
120 : : {
121 : 0 : int ret = atomic_sub_and_test(nr, &page->_refcount);
122 : :
123 : 0 : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_test))
124 : : __page_ref_mod_and_test(page, -nr, ret);
125 [ # # # # ]: 0 : return ret;
126 : : }
127 : :
128 : : static inline int page_ref_inc_return(struct page *page)
129 : : {
130 : : int ret = atomic_inc_return(&page->_refcount);
131 : :
132 : : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_return))
133 : : __page_ref_mod_and_return(page, 1, ret);
134 : : return ret;
135 : : }
136 : :
137 : 25068844 : static inline int page_ref_dec_and_test(struct page *page)
138 : : {
139 : 25068844 : int ret = atomic_dec_and_test(&page->_refcount);
140 : :
141 : 25068844 : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_test))
142 : : __page_ref_mod_and_test(page, -1, ret);
143 [ + + + - : 25068844 : return ret;
# # ]
144 : : }
145 : :
146 : : static inline int page_ref_dec_return(struct page *page)
147 : : {
148 : : int ret = atomic_dec_return(&page->_refcount);
149 : :
150 : : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_return))
151 : : __page_ref_mod_and_return(page, -1, ret);
152 : : return ret;
153 : : }
154 : :
155 : 17799293 : static inline int page_ref_add_unless(struct page *page, int nr, int u)
156 : : {
157 : 17799293 : int ret = atomic_add_unless(&page->_refcount, nr, u);
158 : :
159 : 17799293 : if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_unless))
160 : : __page_ref_mod_unless(page, nr, ret);
161 [ - + - + : 17799293 : return ret;
- - - + -
+ - + ]
162 : : }
163 : :
164 : 0 : static inline int page_ref_freeze(struct page *page, int count)
165 : : {
166 : 0 : int ret = likely(atomic_cmpxchg(&page->_refcount, count, 0) == count);
167 : :
168 : 0 : if (page_ref_tracepoint_active(__tracepoint_page_ref_freeze))
169 : : __page_ref_freeze(page, count, ret);
170 [ # # # # ]: 0 : return ret;
171 : : }
172 : :
173 : 0 : static inline void page_ref_unfreeze(struct page *page, int count)
174 : : {
175 : 0 : VM_BUG_ON_PAGE(page_count(page) != 0, page);
176 : 0 : VM_BUG_ON(count == 0);
177 : :
178 : 0 : atomic_set_release(&page->_refcount, count);
179 : 0 : if (page_ref_tracepoint_active(__tracepoint_page_ref_unfreeze))
180 : : __page_ref_unfreeze(page, count);
181 : : }
182 : :
183 : : #endif
|