xref: /linux-6.15/lib/alloc_tag.c (revision dcfe378c)
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 static void __init procfs_init(void)
93 {
94 	proc_create_seq("allocinfo", 0444, NULL, &allocinfo_seq_op);
95 }
96 
97 static bool alloc_tag_module_unload(struct codetag_type *cttype,
98 				    struct codetag_module *cmod)
99 {
100 	struct codetag_iterator iter = codetag_get_ct_iter(cttype);
101 	struct alloc_tag_counters counter;
102 	bool module_unused = true;
103 	struct alloc_tag *tag;
104 	struct codetag *ct;
105 
106 	for (ct = codetag_next_ct(&iter); ct; ct = codetag_next_ct(&iter)) {
107 		if (iter.cmod != cmod)
108 			continue;
109 
110 		tag = ct_to_alloc_tag(ct);
111 		counter = alloc_tag_read(tag);
112 
113 		if (WARN(counter.bytes,
114 			 "%s:%u module %s func:%s has %llu allocated at module unload",
115 			 ct->filename, ct->lineno, ct->modname, ct->function, counter.bytes))
116 			module_unused = false;
117 	}
118 
119 	return module_unused;
120 }
121 
122 static __init bool need_page_alloc_tagging(void)
123 {
124 	return true;
125 }
126 
127 static __init void init_page_alloc_tagging(void)
128 {
129 }
130 
131 struct page_ext_operations page_alloc_tagging_ops = {
132 	.size = sizeof(union codetag_ref),
133 	.need = need_page_alloc_tagging,
134 	.init = init_page_alloc_tagging,
135 };
136 EXPORT_SYMBOL(page_alloc_tagging_ops);
137 
138 static struct ctl_table memory_allocation_profiling_sysctls[] = {
139 	{
140 		.procname	= "mem_profiling",
141 		.data		= &mem_alloc_profiling_key,
142 #ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
143 		.mode		= 0444,
144 #else
145 		.mode		= 0644,
146 #endif
147 		.proc_handler	= proc_do_static_key,
148 	},
149 	{ }
150 };
151 
152 static int __init alloc_tag_init(void)
153 {
154 	const struct codetag_type_desc desc = {
155 		.section	= "alloc_tags",
156 		.tag_size	= sizeof(struct alloc_tag),
157 		.module_unload	= alloc_tag_module_unload,
158 	};
159 
160 	alloc_tag_cttype = codetag_register_type(&desc);
161 	if (IS_ERR(alloc_tag_cttype))
162 		return PTR_ERR(alloc_tag_cttype);
163 
164 	register_sysctl_init("vm", memory_allocation_profiling_sysctls);
165 	procfs_init();
166 
167 	return 0;
168 }
169 module_init(alloc_tag_init);
170