]> Git Repo - J-linux.git/blob - lib/alloc_tag.c
Merge patch series "riscv: Extension parsing fixes"
[J-linux.git] / lib / alloc_tag.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/alloc_tag.h>
3 #include <linux/fs.h>
4 #include <linux/gfp.h>
5 #include <linux/module.h>
6 #include <linux/page_ext.h>
7 #include <linux/proc_fs.h>
8 #include <linux/seq_buf.h>
9 #include <linux/seq_file.h>
10
11 static struct codetag_type *alloc_tag_cttype;
12
13 DEFINE_PER_CPU(struct alloc_tag_counters, _shared_alloc_tag);
14 EXPORT_SYMBOL(_shared_alloc_tag);
15
16 DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,
17                         mem_alloc_profiling_key);
18
19 static void *allocinfo_start(struct seq_file *m, loff_t *pos)
20 {
21         struct codetag_iterator *iter;
22         struct codetag *ct;
23         loff_t node = *pos;
24
25         iter = kzalloc(sizeof(*iter), GFP_KERNEL);
26         m->private = iter;
27         if (!iter)
28                 return NULL;
29
30         codetag_lock_module_list(alloc_tag_cttype, true);
31         *iter = codetag_get_ct_iter(alloc_tag_cttype);
32         while ((ct = codetag_next_ct(iter)) != NULL && node)
33                 node--;
34
35         return ct ? iter : NULL;
36 }
37
38 static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos)
39 {
40         struct codetag_iterator *iter = (struct codetag_iterator *)arg;
41         struct codetag *ct = codetag_next_ct(iter);
42
43         (*pos)++;
44         if (!ct)
45                 return NULL;
46
47         return iter;
48 }
49
50 static void allocinfo_stop(struct seq_file *m, void *arg)
51 {
52         struct codetag_iterator *iter = (struct codetag_iterator *)m->private;
53
54         if (iter) {
55                 codetag_lock_module_list(alloc_tag_cttype, false);
56                 kfree(iter);
57         }
58 }
59
60 static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct)
61 {
62         struct alloc_tag *tag = ct_to_alloc_tag(ct);
63         struct alloc_tag_counters counter = alloc_tag_read(tag);
64         s64 bytes = counter.bytes;
65
66         seq_buf_printf(out, "%12lli %8llu ", bytes, counter.calls);
67         codetag_to_text(out, ct);
68         seq_buf_putc(out, ' ');
69         seq_buf_putc(out, '\n');
70 }
71
72 static int allocinfo_show(struct seq_file *m, void *arg)
73 {
74         struct codetag_iterator *iter = (struct codetag_iterator *)arg;
75         char *bufp;
76         size_t n = seq_get_buf(m, &bufp);
77         struct seq_buf buf;
78
79         seq_buf_init(&buf, bufp, n);
80         alloc_tag_to_text(&buf, iter->ct);
81         seq_commit(m, seq_buf_used(&buf));
82         return 0;
83 }
84
85 static const struct seq_operations allocinfo_seq_op = {
86         .start  = allocinfo_start,
87         .next   = allocinfo_next,
88         .stop   = allocinfo_stop,
89         .show   = allocinfo_show,
90 };
91
92 size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep)
93 {
94         struct codetag_iterator iter;
95         struct codetag *ct;
96         struct codetag_bytes n;
97         unsigned int i, nr = 0;
98
99         if (can_sleep)
100                 codetag_lock_module_list(alloc_tag_cttype, true);
101         else if (!codetag_trylock_module_list(alloc_tag_cttype))
102                 return 0;
103
104         iter = codetag_get_ct_iter(alloc_tag_cttype);
105         while ((ct = codetag_next_ct(&iter))) {
106                 struct alloc_tag_counters counter = alloc_tag_read(ct_to_alloc_tag(ct));
107
108                 n.ct    = ct;
109                 n.bytes = counter.bytes;
110
111                 for (i = 0; i < nr; i++)
112                         if (n.bytes > tags[i].bytes)
113                                 break;
114
115                 if (i < count) {
116                         nr -= nr == count;
117                         memmove(&tags[i + 1],
118                                 &tags[i],
119                                 sizeof(tags[0]) * (nr - i));
120                         nr++;
121                         tags[i] = n;
122                 }
123         }
124
125         codetag_lock_module_list(alloc_tag_cttype, false);
126
127         return nr;
128 }
129
130 static void __init procfs_init(void)
131 {
132         proc_create_seq("allocinfo", 0400, NULL, &allocinfo_seq_op);
133 }
134
135 static bool alloc_tag_module_unload(struct codetag_type *cttype,
136                                     struct codetag_module *cmod)
137 {
138         struct codetag_iterator iter = codetag_get_ct_iter(cttype);
139         struct alloc_tag_counters counter;
140         bool module_unused = true;
141         struct alloc_tag *tag;
142         struct codetag *ct;
143
144         for (ct = codetag_next_ct(&iter); ct; ct = codetag_next_ct(&iter)) {
145                 if (iter.cmod != cmod)
146                         continue;
147
148                 tag = ct_to_alloc_tag(ct);
149                 counter = alloc_tag_read(tag);
150
151                 if (WARN(counter.bytes,
152                          "%s:%u module %s func:%s has %llu allocated at module unload",
153                          ct->filename, ct->lineno, ct->modname, ct->function, counter.bytes))
154                         module_unused = false;
155         }
156
157         return module_unused;
158 }
159
160 #ifdef CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT
161 static bool mem_profiling_support __meminitdata = true;
162 #else
163 static bool mem_profiling_support __meminitdata;
164 #endif
165
166 static int __init setup_early_mem_profiling(char *str)
167 {
168         bool enable;
169
170         if (!str || !str[0])
171                 return -EINVAL;
172
173         if (!strncmp(str, "never", 5)) {
174                 enable = false;
175                 mem_profiling_support = false;
176         } else {
177                 int res;
178
179                 res = kstrtobool(str, &enable);
180                 if (res)
181                         return res;
182
183                 mem_profiling_support = true;
184         }
185
186         if (enable != static_key_enabled(&mem_alloc_profiling_key)) {
187                 if (enable)
188                         static_branch_enable(&mem_alloc_profiling_key);
189                 else
190                         static_branch_disable(&mem_alloc_profiling_key);
191         }
192
193         return 0;
194 }
195 early_param("sysctl.vm.mem_profiling", setup_early_mem_profiling);
196
197 static __init bool need_page_alloc_tagging(void)
198 {
199         return mem_profiling_support;
200 }
201
202 static __init void init_page_alloc_tagging(void)
203 {
204 }
205
206 struct page_ext_operations page_alloc_tagging_ops = {
207         .size = sizeof(union codetag_ref),
208         .need = need_page_alloc_tagging,
209         .init = init_page_alloc_tagging,
210 };
211 EXPORT_SYMBOL(page_alloc_tagging_ops);
212
213 static struct ctl_table memory_allocation_profiling_sysctls[] = {
214         {
215                 .procname       = "mem_profiling",
216                 .data           = &mem_alloc_profiling_key,
217 #ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
218                 .mode           = 0444,
219 #else
220                 .mode           = 0644,
221 #endif
222                 .proc_handler   = proc_do_static_key,
223         },
224         { }
225 };
226
227 static int __init alloc_tag_init(void)
228 {
229         const struct codetag_type_desc desc = {
230                 .section        = "alloc_tags",
231                 .tag_size       = sizeof(struct alloc_tag),
232                 .module_unload  = alloc_tag_module_unload,
233         };
234
235         alloc_tag_cttype = codetag_register_type(&desc);
236         if (IS_ERR(alloc_tag_cttype))
237                 return PTR_ERR(alloc_tag_cttype);
238
239         if (!mem_profiling_support)
240                 memory_allocation_profiling_sysctls[0].mode = 0444;
241         register_sysctl_init("vm", memory_allocation_profiling_sysctls);
242         procfs_init();
243
244         return 0;
245 }
246 module_init(alloc_tag_init);
This page took 0.039939 seconds and 4 git commands to generate.