Merge tag 'thermal-6.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-block.git] / kernel / printk / index.c
CommitLineData
33701557
CD
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Userspace indexing of printk formats
4 */
5
6#include <linux/debugfs.h>
7#include <linux/module.h>
8#include <linux/printk.h>
9#include <linux/slab.h>
10#include <linux/string_helpers.h>
11
12#include "internal.h"
13
14extern struct pi_entry *__start_printk_index[];
15extern struct pi_entry *__stop_printk_index[];
16
17/* The base dir for module formats, typically debugfs/printk/index/ */
18static struct dentry *dfs_index;
19
20static struct pi_entry *pi_get_entry(const struct module *mod, loff_t pos)
21{
22 struct pi_entry **entries;
23 unsigned int nr_entries;
24
25#ifdef CONFIG_MODULES
26 if (mod) {
27 entries = mod->printk_index_start;
28 nr_entries = mod->printk_index_size;
5aa7eea9 29 } else
33701557 30#endif
5aa7eea9 31 {
33701557
CD
32 /* vmlinux, comes from linker symbols */
33 entries = __start_printk_index;
34 nr_entries = __stop_printk_index - __start_printk_index;
35 }
36
37 if (pos >= nr_entries)
38 return NULL;
39
40 return entries[pos];
41}
42
43static void *pi_next(struct seq_file *s, void *v, loff_t *pos)
44{
45 const struct module *mod = s->file->f_inode->i_private;
46 struct pi_entry *entry = pi_get_entry(mod, *pos);
47
48 (*pos)++;
49
50 return entry;
51}
52
53static void *pi_start(struct seq_file *s, loff_t *pos)
54{
55 /*
56 * Make show() print the header line. Do not update *pos because
57 * pi_next() still has to return the entry at index 0 later.
58 */
59 if (*pos == 0)
60 return SEQ_START_TOKEN;
61
62 return pi_next(s, NULL, pos);
63}
64
65/*
66 * We need both ESCAPE_ANY and explicit characters from ESCAPE_SPECIAL in @only
67 * because otherwise ESCAPE_NAP will cause double quotes and backslashes to be
68 * ignored for quoting.
69 */
70#define seq_escape_printf_format(s, src) \
71 seq_escape_str(s, src, ESCAPE_ANY | ESCAPE_NAP | ESCAPE_APPEND, "\"\\")
72
73static int pi_show(struct seq_file *s, void *v)
74{
75 const struct pi_entry *entry = v;
76 int level = LOGLEVEL_DEFAULT;
77 enum printk_info_flags flags = 0;
78 u16 prefix_len = 0;
79
80 if (v == SEQ_START_TOKEN) {
81 seq_puts(s, "# <level/flags> filename:line function \"format\"\n");
82 return 0;
83 }
84
85 if (!entry->fmt)
86 return 0;
87
88 if (entry->level)
89 printk_parse_prefix(entry->level, &level, &flags);
90 else
91 prefix_len = printk_parse_prefix(entry->fmt, &level, &flags);
92
93
94 if (flags & LOG_CONT) {
95 /*
96 * LOGLEVEL_DEFAULT here means "use the same level as the
97 * message we're continuing from", not the default message
98 * loglevel, so don't display it as such.
99 */
100 if (level == LOGLEVEL_DEFAULT)
101 seq_puts(s, "<c>");
102 else
103 seq_printf(s, "<%d,c>", level);
104 } else
105 seq_printf(s, "<%d>", level);
106
107 seq_printf(s, " %s:%d %s \"", entry->file, entry->line, entry->func);
108 if (entry->subsys_fmt_prefix)
109 seq_escape_printf_format(s, entry->subsys_fmt_prefix);
110 seq_escape_printf_format(s, entry->fmt + prefix_len);
111 seq_puts(s, "\"\n");
112
113 return 0;
114}
115
116static void pi_stop(struct seq_file *p, void *v) { }
117
118static const struct seq_operations dfs_index_sops = {
119 .start = pi_start,
120 .next = pi_next,
121 .show = pi_show,
122 .stop = pi_stop,
123};
124
125DEFINE_SEQ_ATTRIBUTE(dfs_index);
126
127#ifdef CONFIG_MODULES
128static const char *pi_get_module_name(struct module *mod)
129{
130 return mod ? mod->name : "vmlinux";
131}
132#else
133static const char *pi_get_module_name(struct module *mod)
134{
135 return "vmlinux";
136}
137#endif
138
0f0aa848 139static void pi_create_file(struct module *mod)
33701557
CD
140{
141 debugfs_create_file(pi_get_module_name(mod), 0444, dfs_index,
142 mod, &dfs_index_fops);
143}
144
bc17bed5 145#ifdef CONFIG_MODULES
0f0aa848 146static void pi_remove_file(struct module *mod)
33701557 147{
55bf243c 148 debugfs_lookup_and_remove(pi_get_module_name(mod), dfs_index);
33701557
CD
149}
150
33701557
CD
151static int pi_module_notify(struct notifier_block *nb, unsigned long op,
152 void *data)
153{
154 struct module *mod = data;
155
156 switch (op) {
157 case MODULE_STATE_COMING:
158 pi_create_file(mod);
159 break;
160 case MODULE_STATE_GOING:
161 pi_remove_file(mod);
162 break;
163 default: /* we don't care about other module states */
164 break;
165 }
166
167 return NOTIFY_OK;
168}
169
170static struct notifier_block module_printk_fmts_nb = {
171 .notifier_call = pi_module_notify,
172};
173
174static void __init pi_setup_module_notifier(void)
175{
176 register_module_notifier(&module_printk_fmts_nb);
177}
178#else
179static inline void __init pi_setup_module_notifier(void) { }
180#endif
181
182static int __init pi_init(void)
183{
184 struct dentry *dfs_root = debugfs_create_dir("printk", NULL);
185
186 dfs_index = debugfs_create_dir("index", dfs_root);
187 pi_setup_module_notifier();
188 pi_create_file(NULL);
189
190 return 0;
191}
192
193/* debugfs comes up on core and must be initialised first */
194postcore_initcall(pi_init);