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