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