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 : DECLARE_TRACEPOINT(page_ref_set);
11 : DECLARE_TRACEPOINT(page_ref_mod);
12 : DECLARE_TRACEPOINT(page_ref_mod_and_test);
13 : DECLARE_TRACEPOINT(page_ref_mod_and_return);
14 : DECLARE_TRACEPOINT(page_ref_mod_unless);
15 : DECLARE_TRACEPOINT(page_ref_freeze);
16 : DECLARE_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) tracepoint_enabled(t)
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 2332248 : static inline int page_ref_count(struct page *page)
66 : {
67 2332248 : return atomic_read(&page->_refcount);
68 : }
69 :
70 71429 : static inline int page_count(struct page *page)
71 : {
72 71429 : return atomic_read(&compound_head(page)->_refcount);
73 : }
74 :
75 745289 : static inline void set_page_count(struct page *page, int v)
76 : {
77 482181 : atomic_set(&page->_refcount, v);
78 288683 : if (page_ref_tracepoint_active(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 263108 : static inline void init_page_count(struct page *page)
87 : {
88 263108 : set_page_count(page, 1);
89 : }
90 :
91 1987 : static inline void page_ref_add(struct page *page, int nr)
92 : {
93 1987 : atomic_add(nr, &page->_refcount);
94 1987 : if (page_ref_tracepoint_active(page_ref_mod))
95 : __page_ref_mod(page, nr);
96 1987 : }
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(page_ref_mod))
102 : __page_ref_mod(page, -nr);
103 0 : }
104 :
105 : static inline int page_ref_sub_return(struct page *page, int nr)
106 : {
107 : int ret = atomic_sub_return(nr, &page->_refcount);
108 :
109 : if (page_ref_tracepoint_active(page_ref_mod_and_return))
110 : __page_ref_mod_and_return(page, -nr, ret);
111 : return ret;
112 : }
113 :
114 241500 : static inline void page_ref_inc(struct page *page)
115 : {
116 241500 : atomic_inc(&page->_refcount);
117 241532 : if (page_ref_tracepoint_active(page_ref_mod))
118 : __page_ref_mod(page, 1);
119 241532 : }
120 :
121 : static inline void page_ref_dec(struct page *page)
122 : {
123 : atomic_dec(&page->_refcount);
124 : if (page_ref_tracepoint_active(page_ref_mod))
125 : __page_ref_mod(page, -1);
126 : }
127 :
128 0 : static inline int page_ref_sub_and_test(struct page *page, int nr)
129 : {
130 0 : int ret = atomic_sub_and_test(nr, &page->_refcount);
131 :
132 0 : if (page_ref_tracepoint_active(page_ref_mod_and_test))
133 : __page_ref_mod_and_test(page, -nr, ret);
134 0 : return ret;
135 : }
136 :
137 : static inline int page_ref_inc_return(struct page *page)
138 : {
139 : int ret = atomic_inc_return(&page->_refcount);
140 :
141 : if (page_ref_tracepoint_active(page_ref_mod_and_return))
142 : __page_ref_mod_and_return(page, 1, ret);
143 : return ret;
144 : }
145 :
146 1175515 : static inline int page_ref_dec_and_test(struct page *page)
147 : {
148 1175515 : int ret = atomic_dec_and_test(&page->_refcount);
149 :
150 1175680 : if (page_ref_tracepoint_active(page_ref_mod_and_test))
151 : __page_ref_mod_and_test(page, -1, ret);
152 1175680 : return ret;
153 : }
154 :
155 : static inline int page_ref_dec_return(struct page *page)
156 : {
157 : int ret = atomic_dec_return(&page->_refcount);
158 :
159 : if (page_ref_tracepoint_active(page_ref_mod_and_return))
160 : __page_ref_mod_and_return(page, -1, ret);
161 : return ret;
162 : }
163 :
164 2 : static inline int page_ref_add_unless(struct page *page, int nr, int u)
165 : {
166 2 : int ret = atomic_add_unless(&page->_refcount, nr, u);
167 :
168 2 : if (page_ref_tracepoint_active(page_ref_mod_unless))
169 : __page_ref_mod_unless(page, nr, ret);
170 2 : return ret;
171 : }
172 :
173 0 : static inline int page_ref_freeze(struct page *page, int count)
174 : {
175 0 : int ret = likely(atomic_cmpxchg(&page->_refcount, count, 0) == count);
176 :
177 0 : if (page_ref_tracepoint_active(page_ref_freeze))
178 : __page_ref_freeze(page, count, ret);
179 0 : return ret;
180 : }
181 :
182 0 : static inline void page_ref_unfreeze(struct page *page, int count)
183 : {
184 0 : VM_BUG_ON_PAGE(page_count(page) != 0, page);
185 0 : VM_BUG_ON(count == 0);
186 :
187 0 : atomic_set_release(&page->_refcount, count);
188 0 : if (page_ref_tracepoint_active(page_ref_unfreeze))
189 : __page_ref_unfreeze(page, count);
190 0 : }
191 :
192 : #endif
|