1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/alloc_tag.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>
11 static struct codetag_type
*alloc_tag_cttype
;
13 DEFINE_PER_CPU(struct alloc_tag_counters
, _shared_alloc_tag
);
14 EXPORT_SYMBOL(_shared_alloc_tag
);
16 DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT
,
17 mem_alloc_profiling_key
);
19 struct allocinfo_private
{
20 struct codetag_iterator iter
;
24 static void *allocinfo_start(struct seq_file
*m
, loff_t
*pos
)
26 struct allocinfo_private
*priv
;
30 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
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
)
41 return ct
? priv
: NULL
;
44 static void *allocinfo_next(struct seq_file
*m
, void *arg
, loff_t
*pos
)
46 struct allocinfo_private
*priv
= (struct allocinfo_private
*)arg
;
47 struct codetag
*ct
= codetag_next_ct(&priv
->iter
);
56 static void allocinfo_stop(struct seq_file
*m
, void *arg
)
58 struct allocinfo_private
*priv
= (struct allocinfo_private
*)m
->private;
61 codetag_lock_module_list(alloc_tag_cttype
, false);
66 static void print_allocinfo_header(struct seq_buf
*buf
)
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");
73 static void alloc_tag_to_text(struct seq_buf
*out
, struct codetag
*ct
)
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
;
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');
85 static int allocinfo_show(struct seq_file
*m
, void *arg
)
87 struct allocinfo_private
*priv
= (struct allocinfo_private
*)arg
;
89 size_t n
= seq_get_buf(m
, &bufp
);
92 seq_buf_init(&buf
, bufp
, n
);
93 if (priv
->print_header
) {
94 print_allocinfo_header(&buf
);
95 priv
->print_header
= false;
97 alloc_tag_to_text(&buf
, priv
->iter
.ct
);
98 seq_commit(m
, seq_buf_used(&buf
));
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
,
109 size_t alloc_tag_top_users(struct codetag_bytes
*tags
, size_t count
, bool can_sleep
)
111 struct codetag_iterator iter
;
113 struct codetag_bytes n
;
114 unsigned int i
, nr
= 0;
117 codetag_lock_module_list(alloc_tag_cttype
, true);
118 else if (!codetag_trylock_module_list(alloc_tag_cttype
))
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
));
126 n
.bytes
= counter
.bytes
;
128 for (i
= 0; i
< nr
; i
++)
129 if (n
.bytes
> tags
[i
].bytes
)
134 memmove(&tags
[i
+ 1],
136 sizeof(tags
[0]) * (nr
- i
));
142 codetag_lock_module_list(alloc_tag_cttype
, false);
147 static void __init
procfs_init(void)
149 proc_create_seq("allocinfo", 0400, NULL
, &allocinfo_seq_op
);
152 static bool alloc_tag_module_unload(struct codetag_type
*cttype
,
153 struct codetag_module
*cmod
)
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
;
161 for (ct
= codetag_next_ct(&iter
); ct
; ct
= codetag_next_ct(&iter
)) {
162 if (iter
.cmod
!= cmod
)
165 tag
= ct_to_alloc_tag(ct
);
166 counter
= alloc_tag_read(tag
);
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;
174 return module_unused
;
177 #ifdef CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT
178 static bool mem_profiling_support __meminitdata
= true;
180 static bool mem_profiling_support __meminitdata
;
183 static int __init
setup_early_mem_profiling(char *str
)
190 if (!strncmp(str
, "never", 5)) {
192 mem_profiling_support
= false;
196 res
= kstrtobool(str
, &enable
);
200 mem_profiling_support
= true;
203 if (enable
!= static_key_enabled(&mem_alloc_profiling_key
)) {
205 static_branch_enable(&mem_alloc_profiling_key
);
207 static_branch_disable(&mem_alloc_profiling_key
);
212 early_param("sysctl.vm.mem_profiling", setup_early_mem_profiling
);
214 static __init
bool need_page_alloc_tagging(void)
216 return mem_profiling_support
;
219 static __init
void init_page_alloc_tagging(void)
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
,
228 EXPORT_SYMBOL(page_alloc_tagging_ops
);
231 static struct ctl_table memory_allocation_profiling_sysctls
[] = {
233 .procname
= "mem_profiling",
234 .data
= &mem_alloc_profiling_key
,
235 #ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
240 .proc_handler
= proc_do_static_key
,
244 static void __init
sysctl_init(void)
246 if (!mem_profiling_support
)
247 memory_allocation_profiling_sysctls
[0].mode
= 0444;
249 register_sysctl_init("vm", memory_allocation_profiling_sysctls
);
251 #else /* CONFIG_SYSCTL */
252 static inline void sysctl_init(void) {}
253 #endif /* CONFIG_SYSCTL */
255 static int __init
alloc_tag_init(void)
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
,
263 alloc_tag_cttype
= codetag_register_type(&desc
);
264 if (IS_ERR(alloc_tag_cttype
))
265 return PTR_ERR(alloc_tag_cttype
);
272 module_init(alloc_tag_init
);