xref: /linux/lib/alloc_tag.c (revision 61307b7be41a1f1039d1d1368810a1d92cb97b44)
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);
247