]> Git Repo - J-linux.git/blob - include/linux/pgalloc_tag.h
Merge tag 'riscv-for-linus-6.13-mw1' of git://git.kernel.org/pub/scm/linux/kernel...
[J-linux.git] / include / linux / pgalloc_tag.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * page allocation tagging
4  */
5 #ifndef _LINUX_PGALLOC_TAG_H
6 #define _LINUX_PGALLOC_TAG_H
7
8 #include <linux/alloc_tag.h>
9
10 #ifdef CONFIG_MEM_ALLOC_PROFILING
11
12 #include <linux/page_ext.h>
13
14 extern struct page_ext_operations page_alloc_tagging_ops;
15 extern unsigned long alloc_tag_ref_mask;
16 extern int alloc_tag_ref_offs;
17 extern struct alloc_tag_kernel_section kernel_tags;
18
19 DECLARE_STATIC_KEY_FALSE(mem_profiling_compressed);
20
21 typedef u16     pgalloc_tag_idx;
22
23 union pgtag_ref_handle {
24         union codetag_ref *ref; /* reference in page extension */
25         struct page *page;      /* reference in page flags */
26 };
27
28 /* Reserved indexes */
29 #define CODETAG_ID_NULL         0
30 #define CODETAG_ID_EMPTY        1
31 #define CODETAG_ID_FIRST        2
32
33 #ifdef CONFIG_MODULES
34
35 extern struct alloc_tag_module_section module_tags;
36
37 static inline struct alloc_tag *module_idx_to_tag(pgalloc_tag_idx idx)
38 {
39         return &module_tags.first_tag[idx - kernel_tags.count];
40 }
41
42 static inline pgalloc_tag_idx module_tag_to_idx(struct alloc_tag *tag)
43 {
44         return CODETAG_ID_FIRST + kernel_tags.count + (tag - module_tags.first_tag);
45 }
46
47 #else /* CONFIG_MODULES */
48
49 static inline struct alloc_tag *module_idx_to_tag(pgalloc_tag_idx idx)
50 {
51         pr_warn("invalid page tag reference %lu\n", (unsigned long)idx);
52         return NULL;
53 }
54
55 static inline pgalloc_tag_idx module_tag_to_idx(struct alloc_tag *tag)
56 {
57         pr_warn("invalid page tag 0x%lx\n", (unsigned long)tag);
58         return CODETAG_ID_NULL;
59 }
60
61 #endif /* CONFIG_MODULES */
62
63 static inline void idx_to_ref(pgalloc_tag_idx idx, union codetag_ref *ref)
64 {
65         switch (idx) {
66         case (CODETAG_ID_NULL):
67                 ref->ct = NULL;
68                 break;
69         case (CODETAG_ID_EMPTY):
70                 set_codetag_empty(ref);
71                 break;
72         default:
73                 idx -= CODETAG_ID_FIRST;
74                 ref->ct = idx < kernel_tags.count ?
75                         &kernel_tags.first_tag[idx].ct :
76                         &module_idx_to_tag(idx)->ct;
77                 break;
78         }
79 }
80
81 static inline pgalloc_tag_idx ref_to_idx(union codetag_ref *ref)
82 {
83         struct alloc_tag *tag;
84
85         if (!ref->ct)
86                 return CODETAG_ID_NULL;
87
88         if (is_codetag_empty(ref))
89                 return CODETAG_ID_EMPTY;
90
91         tag = ct_to_alloc_tag(ref->ct);
92         if (tag >= kernel_tags.first_tag && tag < kernel_tags.first_tag + kernel_tags.count)
93                 return CODETAG_ID_FIRST + (tag - kernel_tags.first_tag);
94
95         return module_tag_to_idx(tag);
96 }
97
98
99
100 /* Should be called only if mem_alloc_profiling_enabled() */
101 static inline bool get_page_tag_ref(struct page *page, union codetag_ref *ref,
102                                     union pgtag_ref_handle *handle)
103 {
104         if (!page)
105                 return false;
106
107         if (static_key_enabled(&mem_profiling_compressed)) {
108                 pgalloc_tag_idx idx;
109
110                 idx = (page->flags >> alloc_tag_ref_offs) & alloc_tag_ref_mask;
111                 idx_to_ref(idx, ref);
112                 handle->page = page;
113         } else {
114                 struct page_ext *page_ext;
115                 union codetag_ref *tmp;
116
117                 page_ext = page_ext_get(page);
118                 if (!page_ext)
119                         return false;
120
121                 tmp = (union codetag_ref *)page_ext_data(page_ext, &page_alloc_tagging_ops);
122                 ref->ct = tmp->ct;
123                 handle->ref = tmp;
124         }
125
126         return true;
127 }
128
129 static inline void put_page_tag_ref(union pgtag_ref_handle handle)
130 {
131         if (WARN_ON(!handle.ref))
132                 return;
133
134         if (!static_key_enabled(&mem_profiling_compressed))
135                 page_ext_put((void *)handle.ref - page_alloc_tagging_ops.offset);
136 }
137
138 static inline void update_page_tag_ref(union pgtag_ref_handle handle, union codetag_ref *ref)
139 {
140         if (static_key_enabled(&mem_profiling_compressed)) {
141                 struct page *page = handle.page;
142                 unsigned long old_flags;
143                 unsigned long flags;
144                 unsigned long idx;
145
146                 if (WARN_ON(!page || !ref))
147                         return;
148
149                 idx = (unsigned long)ref_to_idx(ref);
150                 idx = (idx & alloc_tag_ref_mask) << alloc_tag_ref_offs;
151                 do {
152                         old_flags = READ_ONCE(page->flags);
153                         flags = old_flags;
154                         flags &= ~(alloc_tag_ref_mask << alloc_tag_ref_offs);
155                         flags |= idx;
156                 } while (unlikely(!try_cmpxchg(&page->flags, &old_flags, flags)));
157         } else {
158                 if (WARN_ON(!handle.ref || !ref))
159                         return;
160
161                 handle.ref->ct = ref->ct;
162         }
163 }
164
165 static inline void clear_page_tag_ref(struct page *page)
166 {
167         if (mem_alloc_profiling_enabled()) {
168                 union pgtag_ref_handle handle;
169                 union codetag_ref ref;
170
171                 if (get_page_tag_ref(page, &ref, &handle)) {
172                         set_codetag_empty(&ref);
173                         update_page_tag_ref(handle, &ref);
174                         put_page_tag_ref(handle);
175                 }
176         }
177 }
178
179 static inline void pgalloc_tag_add(struct page *page, struct task_struct *task,
180                                    unsigned int nr)
181 {
182         if (mem_alloc_profiling_enabled()) {
183                 union pgtag_ref_handle handle;
184                 union codetag_ref ref;
185
186                 if (get_page_tag_ref(page, &ref, &handle)) {
187                         alloc_tag_add(&ref, task->alloc_tag, PAGE_SIZE * nr);
188                         update_page_tag_ref(handle, &ref);
189                         put_page_tag_ref(handle);
190                 }
191         }
192 }
193
194 static inline void pgalloc_tag_sub(struct page *page, unsigned int nr)
195 {
196         if (mem_alloc_profiling_enabled()) {
197                 union pgtag_ref_handle handle;
198                 union codetag_ref ref;
199
200                 if (get_page_tag_ref(page, &ref, &handle)) {
201                         alloc_tag_sub(&ref, PAGE_SIZE * nr);
202                         update_page_tag_ref(handle, &ref);
203                         put_page_tag_ref(handle);
204                 }
205         }
206 }
207
208 static inline struct alloc_tag *pgalloc_tag_get(struct page *page)
209 {
210         struct alloc_tag *tag = NULL;
211
212         if (mem_alloc_profiling_enabled()) {
213                 union pgtag_ref_handle handle;
214                 union codetag_ref ref;
215
216                 if (get_page_tag_ref(page, &ref, &handle)) {
217                         alloc_tag_sub_check(&ref);
218                         if (ref.ct)
219                                 tag = ct_to_alloc_tag(ref.ct);
220                         put_page_tag_ref(handle);
221                 }
222         }
223
224         return tag;
225 }
226
227 static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr)
228 {
229         if (mem_alloc_profiling_enabled() && tag)
230                 this_cpu_sub(tag->counters->bytes, PAGE_SIZE * nr);
231 }
232
233 void pgalloc_tag_split(struct folio *folio, int old_order, int new_order);
234 void pgalloc_tag_copy(struct folio *new, struct folio *old);
235
236 void __init alloc_tag_sec_init(void);
237
238 #else /* CONFIG_MEM_ALLOC_PROFILING */
239
240 static inline void clear_page_tag_ref(struct page *page) {}
241 static inline void pgalloc_tag_add(struct page *page, struct task_struct *task,
242                                    unsigned int nr) {}
243 static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {}
244 static inline struct alloc_tag *pgalloc_tag_get(struct page *page) { return NULL; }
245 static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {}
246 static inline void alloc_tag_sec_init(void) {}
247 static inline void pgalloc_tag_split(struct folio *folio, int old_order, int new_order) {}
248 static inline void pgalloc_tag_copy(struct folio *new, struct folio *old) {}
249
250 #endif /* CONFIG_MEM_ALLOC_PROFILING */
251
252 #endif /* _LINUX_PGALLOC_TAG_H */
This page took 0.041342 seconds and 4 git commands to generate.