lib: add version into /proc/allocinfo output

Add version string and a header at the beginning of /proc/allocinfo to
allow later format changes. Example output:

> head /proc/allocinfo
allocinfo - version: 1.0
# <size> <calls> <tag info>
0 0 init/main.c:1314 func:do_initcalls
0 0 init/do_mounts.c:353 func:mount_nodev_root
0 0 init/do_mounts.c:187 func:mount_root_generic
0 0 init/do_mounts.c:158 func:do_mount_root
0 0 init/initramfs.c:493 func:unpack_to_rootfs
0 0 init/initramfs.c:492 func:unpack_to_rootfs
0 0 init/initramfs.c:491 func:unpack_to_rootfs
512 1 arch/x86/events/rapl.c:681 func:init_rapl_pmus
128 1 arch/x86/events/rapl.c:571 func:rapl_cpu_online

[akpm@linux-foundation.org: remove stray newline from struct allocinfo_private]
Link: https://lkml.kernel.org/r/20240514163128.3662251-1-surenb@google.com
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by Suren Baghdasaryan and committed by Andrew Morton a38568a0 8e0545c8

+35 -17
+3 -2
Documentation/filesystems/proc.rst
··· 961 961 base. Each allocation in the code is identified by its source file, line 962 962 number, module (if originates from a loadable module) and the function calling 963 963 the allocation. The number of bytes allocated and number of calls at each 964 - location are reported. 964 + location are reported. The first line indicates the version of the file, the 965 + second line is the header listing fields in the file. 965 966 966 967 Example output. 967 968 968 969 :: 969 970 970 - > sort -rn /proc/allocinfo 971 + > tail -n +3 /proc/allocinfo | sort -rn 971 972 127664128 31168 mm/page_ext.c:270 func:alloc_page_ext 972 973 56373248 4737 mm/slub.c:2259 func:alloc_slab_page 973 974 14880768 3633 mm/readahead.c:247 func:page_cache_ra_unbounded
+32 -15
lib/alloc_tag.c
··· 16 16 DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT, 17 17 mem_alloc_profiling_key); 18 18 19 + struct allocinfo_private { 20 + struct codetag_iterator iter; 21 + bool print_header; 22 + }; 23 + 19 24 static void *allocinfo_start(struct seq_file *m, loff_t *pos) 20 25 { 21 - struct codetag_iterator *iter; 26 + struct allocinfo_private *priv; 22 27 struct codetag *ct; 23 28 loff_t node = *pos; 24 29 25 - iter = kzalloc(sizeof(*iter), GFP_KERNEL); 26 - m->private = iter; 27 - if (!iter) 30 + priv = kzalloc(sizeof(*priv), GFP_KERNEL); 31 + m->private = priv; 32 + if (!priv) 28 33 return NULL; 29 34 35 + priv->print_header = (node == 0); 30 36 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) 37 + priv->iter = codetag_get_ct_iter(alloc_tag_cttype); 38 + while ((ct = codetag_next_ct(&priv->iter)) != NULL && node) 33 39 node--; 34 40 35 - return ct ? iter : NULL; 41 + return ct ? priv : NULL; 36 42 } 37 43 38 44 static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos) 39 45 { 40 - struct codetag_iterator *iter = (struct codetag_iterator *)arg; 41 - struct codetag *ct = codetag_next_ct(iter); 46 + struct allocinfo_private *priv = (struct allocinfo_private *)arg; 47 + struct codetag *ct = codetag_next_ct(&priv->iter); 42 48 43 49 (*pos)++; 44 50 if (!ct) 45 51 return NULL; 46 52 47 - return iter; 53 + return priv; 48 54 } 49 55 50 56 static void allocinfo_stop(struct seq_file *m, void *arg) 51 57 { 52 - struct codetag_iterator *iter = (struct codetag_iterator *)m->private; 58 + struct allocinfo_private *priv = (struct allocinfo_private *)m->private; 53 59 54 - if (iter) { 60 + if (priv) { 55 61 codetag_lock_module_list(alloc_tag_cttype, false); 56 - kfree(iter); 62 + kfree(priv); 57 63 } 64 + } 65 + 66 + static void print_allocinfo_header(struct seq_buf *buf) 67 + { 68 + /* Output format version, so we can change it. */ 69 + seq_buf_printf(buf, "allocinfo - version: 1.0\n"); 70 + seq_buf_printf(buf, "# <size> <calls> <tag info>\n"); 58 71 } 59 72 60 73 static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct) ··· 84 71 85 72 static int allocinfo_show(struct seq_file *m, void *arg) 86 73 { 87 - struct codetag_iterator *iter = (struct codetag_iterator *)arg; 74 + struct allocinfo_private *priv = (struct allocinfo_private *)arg; 88 75 char *bufp; 89 76 size_t n = seq_get_buf(m, &bufp); 90 77 struct seq_buf buf; 91 78 92 79 seq_buf_init(&buf, bufp, n); 93 - alloc_tag_to_text(&buf, iter->ct); 80 + if (priv->print_header) { 81 + print_allocinfo_header(&buf); 82 + priv->print_header = false; 83 + } 84 + alloc_tag_to_text(&buf, priv->iter.ct); 94 85 seq_commit(m, seq_buf_used(&buf)); 95 86 return 0; 96 87 }