]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - include/linux/page_ref.h
Merge tag 'dma-mapping-5.15-1' of git://git.infradead.org/users/hch/dma-mapping
[mirror_ubuntu-jammy-kernel.git] / include / linux / page_ref.h
CommitLineData
b2441318 1/* SPDX-License-Identifier: GPL-2.0 */
fe896d18
JK
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>
95813b8f
JK
8#include <linux/tracepoint-defs.h>
9
c65fc227
SRV
10DECLARE_TRACEPOINT(page_ref_set);
11DECLARE_TRACEPOINT(page_ref_mod);
12DECLARE_TRACEPOINT(page_ref_mod_and_test);
13DECLARE_TRACEPOINT(page_ref_mod_and_return);
14DECLARE_TRACEPOINT(page_ref_mod_unless);
15DECLARE_TRACEPOINT(page_ref_freeze);
16DECLARE_TRACEPOINT(page_ref_unfreeze);
95813b8f
JK
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 */
c65fc227 27#define page_ref_tracepoint_active(t) tracepoint_enabled(t)
95813b8f
JK
28
29extern void __page_ref_set(struct page *page, int v);
30extern void __page_ref_mod(struct page *page, int v);
31extern void __page_ref_mod_and_test(struct page *page, int v, int ret);
32extern void __page_ref_mod_and_return(struct page *page, int v, int ret);
33extern void __page_ref_mod_unless(struct page *page, int v, int u);
34extern void __page_ref_freeze(struct page *page, int v, int ret);
35extern void __page_ref_unfreeze(struct page *page, int v);
36
37#else
38
39#define page_ref_tracepoint_active(t) false
40
41static inline void __page_ref_set(struct page *page, int v)
42{
43}
44static inline void __page_ref_mod(struct page *page, int v)
45{
46}
47static inline void __page_ref_mod_and_test(struct page *page, int v, int ret)
48{
49}
50static inline void __page_ref_mod_and_return(struct page *page, int v, int ret)
51{
52}
53static inline void __page_ref_mod_unless(struct page *page, int v, int u)
54{
55}
56static inline void __page_ref_freeze(struct page *page, int v, int ret)
57{
58}
59static inline void __page_ref_unfreeze(struct page *page, int v)
60{
61}
62
63#endif
fe896d18 64
5f7dadf3 65static inline int page_ref_count(const struct page *page)
fe896d18 66{
0139aa7b 67 return atomic_read(&page->_refcount);
fe896d18
JK
68}
69
5f7dadf3 70static inline int page_count(const struct page *page)
fe896d18 71{
0139aa7b 72 return atomic_read(&compound_head(page)->_refcount);
fe896d18
JK
73}
74
75static inline void set_page_count(struct page *page, int v)
76{
0139aa7b 77 atomic_set(&page->_refcount, v);
c65fc227 78 if (page_ref_tracepoint_active(page_ref_set))
95813b8f 79 __page_ref_set(page, v);
fe896d18
JK
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 */
86static inline void init_page_count(struct page *page)
87{
88 set_page_count(page, 1);
89}
90
91static inline void page_ref_add(struct page *page, int nr)
92{
0139aa7b 93 atomic_add(nr, &page->_refcount);
c65fc227 94 if (page_ref_tracepoint_active(page_ref_mod))
95813b8f 95 __page_ref_mod(page, nr);
fe896d18
JK
96}
97
98static inline void page_ref_sub(struct page *page, int nr)
99{
0139aa7b 100 atomic_sub(nr, &page->_refcount);
c65fc227 101 if (page_ref_tracepoint_active(page_ref_mod))
95813b8f 102 __page_ref_mod(page, -nr);
fe896d18
JK
103}
104
566d774a
JH
105static inline int page_ref_sub_return(struct page *page, int nr)
106{
107 int ret = atomic_sub_return(nr, &page->_refcount);
108
c65fc227 109 if (page_ref_tracepoint_active(page_ref_mod_and_return))
566d774a
JH
110 __page_ref_mod_and_return(page, -nr, ret);
111 return ret;
112}
113
fe896d18
JK
114static inline void page_ref_inc(struct page *page)
115{
0139aa7b 116 atomic_inc(&page->_refcount);
c65fc227 117 if (page_ref_tracepoint_active(page_ref_mod))
95813b8f 118 __page_ref_mod(page, 1);
fe896d18
JK
119}
120
121static inline void page_ref_dec(struct page *page)
122{
0139aa7b 123 atomic_dec(&page->_refcount);
c65fc227 124 if (page_ref_tracepoint_active(page_ref_mod))
95813b8f 125 __page_ref_mod(page, -1);
fe896d18
JK
126}
127
128static inline int page_ref_sub_and_test(struct page *page, int nr)
129{
0139aa7b 130 int ret = atomic_sub_and_test(nr, &page->_refcount);
95813b8f 131
c65fc227 132 if (page_ref_tracepoint_active(page_ref_mod_and_test))
95813b8f
JK
133 __page_ref_mod_and_test(page, -nr, ret);
134 return ret;
fe896d18
JK
135}
136
df9b2b4a
DH
137static inline int page_ref_inc_return(struct page *page)
138{
139 int ret = atomic_inc_return(&page->_refcount);
140
c65fc227 141 if (page_ref_tracepoint_active(page_ref_mod_and_return))
df9b2b4a
DH
142 __page_ref_mod_and_return(page, 1, ret);
143 return ret;
144}
145
fe896d18
JK
146static inline int page_ref_dec_and_test(struct page *page)
147{
0139aa7b 148 int ret = atomic_dec_and_test(&page->_refcount);
95813b8f 149
c65fc227 150 if (page_ref_tracepoint_active(page_ref_mod_and_test))
95813b8f
JK
151 __page_ref_mod_and_test(page, -1, ret);
152 return ret;
fe896d18
JK
153}
154
155static inline int page_ref_dec_return(struct page *page)
156{
0139aa7b 157 int ret = atomic_dec_return(&page->_refcount);
95813b8f 158
c65fc227 159 if (page_ref_tracepoint_active(page_ref_mod_and_return))
95813b8f
JK
160 __page_ref_mod_and_return(page, -1, ret);
161 return ret;
fe896d18
JK
162}
163
164static inline int page_ref_add_unless(struct page *page, int nr, int u)
165{
0139aa7b 166 int ret = atomic_add_unless(&page->_refcount, nr, u);
95813b8f 167
c65fc227 168 if (page_ref_tracepoint_active(page_ref_mod_unless))
95813b8f
JK
169 __page_ref_mod_unless(page, nr, ret);
170 return ret;
fe896d18
JK
171}
172
173static inline int page_ref_freeze(struct page *page, int count)
174{
0139aa7b 175 int ret = likely(atomic_cmpxchg(&page->_refcount, count, 0) == count);
95813b8f 176
c65fc227 177 if (page_ref_tracepoint_active(page_ref_freeze))
95813b8f
JK
178 __page_ref_freeze(page, count, ret);
179 return ret;
fe896d18
JK
180}
181
182static inline void page_ref_unfreeze(struct page *page, int count)
183{
184 VM_BUG_ON_PAGE(page_count(page) != 0, page);
185 VM_BUG_ON(count == 0);
186
03f5d58f 187 atomic_set_release(&page->_refcount, count);
c65fc227 188 if (page_ref_tracepoint_active(page_ref_unfreeze))
95813b8f 189 __page_ref_unfreeze(page, count);
fe896d18
JK
190}
191
192#endif