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