~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/alloc_tag.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php