1bcea3f96SSteven Rostedt (VMware) // SPDX-License-Identifier: GPL-2.0
2769b0441SFrederic Weisbecker /*
3769b0441SFrederic Weisbecker * trace binary printk
4769b0441SFrederic Weisbecker *
5769b0441SFrederic Weisbecker * Copyright (C) 2008 Lai Jiangshan <laijs@cn.fujitsu.com>
6769b0441SFrederic Weisbecker *
7769b0441SFrederic Weisbecker */
87975a2beSSteven Rostedt #include <linux/seq_file.h>
917911ff3SSteven Rostedt (VMware) #include <linux/security.h>
107975a2beSSteven Rostedt #include <linux/uaccess.h>
11769b0441SFrederic Weisbecker #include <linux/kernel.h>
12769b0441SFrederic Weisbecker #include <linux/ftrace.h>
13769b0441SFrederic Weisbecker #include <linux/string.h>
147975a2beSSteven Rostedt #include <linux/module.h>
157975a2beSSteven Rostedt #include <linux/mutex.h>
16769b0441SFrederic Weisbecker #include <linux/ctype.h>
17769b0441SFrederic Weisbecker #include <linux/list.h>
18769b0441SFrederic Weisbecker #include <linux/slab.h>
19769b0441SFrederic Weisbecker
20769b0441SFrederic Weisbecker #include "trace.h"
21769b0441SFrederic Weisbecker
22769b0441SFrederic Weisbecker #ifdef CONFIG_MODULES
23769b0441SFrederic Weisbecker
24769b0441SFrederic Weisbecker /*
25769b0441SFrederic Weisbecker * modules trace_printk()'s formats are autosaved in struct trace_bprintk_fmt
26769b0441SFrederic Weisbecker * which are queued on trace_bprintk_fmt_list.
27769b0441SFrederic Weisbecker */
28769b0441SFrederic Weisbecker static LIST_HEAD(trace_bprintk_fmt_list);
29769b0441SFrederic Weisbecker
30769b0441SFrederic Weisbecker /* serialize accesses to trace_bprintk_fmt_list */
31769b0441SFrederic Weisbecker static DEFINE_MUTEX(btrace_mutex);
32769b0441SFrederic Weisbecker
33769b0441SFrederic Weisbecker struct trace_bprintk_fmt {
34769b0441SFrederic Weisbecker struct list_head list;
350588fa30SSteven Rostedt const char *fmt;
36769b0441SFrederic Weisbecker };
37769b0441SFrederic Weisbecker
lookup_format(const char * fmt)38769b0441SFrederic Weisbecker static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
39769b0441SFrederic Weisbecker {
40769b0441SFrederic Weisbecker struct trace_bprintk_fmt *pos;
4170c8217aSSteven Rostedt (Red Hat)
4270c8217aSSteven Rostedt (Red Hat) if (!fmt)
4370c8217aSSteven Rostedt (Red Hat) return ERR_PTR(-EINVAL);
4470c8217aSSteven Rostedt (Red Hat)
45769b0441SFrederic Weisbecker list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
46769b0441SFrederic Weisbecker if (!strcmp(pos->fmt, fmt))
47769b0441SFrederic Weisbecker return pos;
48769b0441SFrederic Weisbecker }
49769b0441SFrederic Weisbecker return NULL;
50769b0441SFrederic Weisbecker }
51769b0441SFrederic Weisbecker
52769b0441SFrederic Weisbecker static
hold_module_trace_bprintk_format(const char ** start,const char ** end)53769b0441SFrederic Weisbecker void hold_module_trace_bprintk_format(const char **start, const char **end)
54769b0441SFrederic Weisbecker {
55769b0441SFrederic Weisbecker const char **iter;
560588fa30SSteven Rostedt char *fmt;
57769b0441SFrederic Weisbecker
5807d777feSSteven Rostedt /* allocate the trace_printk per cpu buffers */
5907d777feSSteven Rostedt if (start != end)
6007d777feSSteven Rostedt trace_printk_init_buffers();
6107d777feSSteven Rostedt
62769b0441SFrederic Weisbecker mutex_lock(&btrace_mutex);
63769b0441SFrederic Weisbecker for (iter = start; iter < end; iter++) {
64769b0441SFrederic Weisbecker struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
65769b0441SFrederic Weisbecker if (tb_fmt) {
6670c8217aSSteven Rostedt (Red Hat) if (!IS_ERR(tb_fmt))
67769b0441SFrederic Weisbecker *iter = tb_fmt->fmt;
68769b0441SFrederic Weisbecker continue;
69769b0441SFrederic Weisbecker }
70769b0441SFrederic Weisbecker
713a301d7cSSteven Rostedt fmt = NULL;
720588fa30SSteven Rostedt tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL);
733a301d7cSSteven Rostedt if (tb_fmt) {
740588fa30SSteven Rostedt fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL);
753a301d7cSSteven Rostedt if (fmt) {
76769b0441SFrederic Weisbecker list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
770588fa30SSteven Rostedt strcpy(fmt, *iter);
780588fa30SSteven Rostedt tb_fmt->fmt = fmt;
793a301d7cSSteven Rostedt } else
800588fa30SSteven Rostedt kfree(tb_fmt);
81769b0441SFrederic Weisbecker }
823a301d7cSSteven Rostedt *iter = fmt;
833a301d7cSSteven Rostedt
840588fa30SSteven Rostedt }
85769b0441SFrederic Weisbecker mutex_unlock(&btrace_mutex);
86769b0441SFrederic Weisbecker }
87769b0441SFrederic Weisbecker
module_trace_bprintk_format_notify(struct notifier_block * self,unsigned long val,void * data)88769b0441SFrederic Weisbecker static int module_trace_bprintk_format_notify(struct notifier_block *self,
89769b0441SFrederic Weisbecker unsigned long val, void *data)
90769b0441SFrederic Weisbecker {
91769b0441SFrederic Weisbecker struct module *mod = data;
92769b0441SFrederic Weisbecker if (mod->num_trace_bprintk_fmt) {
93769b0441SFrederic Weisbecker const char **start = mod->trace_bprintk_fmt_start;
94769b0441SFrederic Weisbecker const char **end = start + mod->num_trace_bprintk_fmt;
95769b0441SFrederic Weisbecker
96769b0441SFrederic Weisbecker if (val == MODULE_STATE_COMING)
97769b0441SFrederic Weisbecker hold_module_trace_bprintk_format(start, end);
98769b0441SFrederic Weisbecker }
990340a6b7SPeter Zijlstra return NOTIFY_OK;
100769b0441SFrederic Weisbecker }
101769b0441SFrederic Weisbecker
1021813dc37SSteven Rostedt /*
1031813dc37SSteven Rostedt * The debugfs/tracing/printk_formats file maps the addresses with
1041813dc37SSteven Rostedt * the ASCII formats that are used in the bprintk events in the
1051813dc37SSteven Rostedt * buffer. For userspace tools to be able to decode the events from
1061813dc37SSteven Rostedt * the buffer, they need to be able to map the address with the format.
1071813dc37SSteven Rostedt *
1081813dc37SSteven Rostedt * The addresses of the bprintk formats are in their own section
1091813dc37SSteven Rostedt * __trace_printk_fmt. But for modules we copy them into a link list.
1101813dc37SSteven Rostedt * The code to print the formats and their addresses passes around the
1111813dc37SSteven Rostedt * address of the fmt string. If the fmt address passed into the seq
1121813dc37SSteven Rostedt * functions is within the kernel core __trace_printk_fmt section, then
1131813dc37SSteven Rostedt * it simply uses the next pointer in the list.
1141813dc37SSteven Rostedt *
1151813dc37SSteven Rostedt * When the fmt pointer is outside the kernel core __trace_printk_fmt
1161813dc37SSteven Rostedt * section, then we need to read the link list pointers. The trick is
1171813dc37SSteven Rostedt * we pass the address of the string to the seq function just like
1181813dc37SSteven Rostedt * we do for the kernel core formats. To get back the structure that
119ca9184f0SAndy Shevchenko * holds the format, we simply use container_of() and then go to the
1201813dc37SSteven Rostedt * next format in the list.
1211813dc37SSteven Rostedt */
1221813dc37SSteven Rostedt static const char **
find_next_mod_format(int start_index,void * v,const char ** fmt,loff_t * pos)1231813dc37SSteven Rostedt find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
1241813dc37SSteven Rostedt {
1251813dc37SSteven Rostedt struct trace_bprintk_fmt *mod_fmt;
1261813dc37SSteven Rostedt
1271813dc37SSteven Rostedt if (list_empty(&trace_bprintk_fmt_list))
1281813dc37SSteven Rostedt return NULL;
1291813dc37SSteven Rostedt
1301813dc37SSteven Rostedt /*
1311813dc37SSteven Rostedt * v will point to the address of the fmt record from t_next
1321813dc37SSteven Rostedt * v will be NULL from t_start.
1331813dc37SSteven Rostedt * If this is the first pointer or called from start
1341813dc37SSteven Rostedt * then we need to walk the list.
1351813dc37SSteven Rostedt */
1361813dc37SSteven Rostedt if (!v || start_index == *pos) {
1371813dc37SSteven Rostedt struct trace_bprintk_fmt *p;
1381813dc37SSteven Rostedt
1391813dc37SSteven Rostedt /* search the module list */
1401813dc37SSteven Rostedt list_for_each_entry(p, &trace_bprintk_fmt_list, list) {
1411813dc37SSteven Rostedt if (start_index == *pos)
1421813dc37SSteven Rostedt return &p->fmt;
1431813dc37SSteven Rostedt start_index++;
1441813dc37SSteven Rostedt }
1451813dc37SSteven Rostedt /* pos > index */
1461813dc37SSteven Rostedt return NULL;
1471813dc37SSteven Rostedt }
1481813dc37SSteven Rostedt
1491813dc37SSteven Rostedt /*
1501813dc37SSteven Rostedt * v points to the address of the fmt field in the mod list
1511813dc37SSteven Rostedt * structure that holds the module print format.
1521813dc37SSteven Rostedt */
1531813dc37SSteven Rostedt mod_fmt = container_of(v, typeof(*mod_fmt), fmt);
1541813dc37SSteven Rostedt if (mod_fmt->list.next == &trace_bprintk_fmt_list)
1551813dc37SSteven Rostedt return NULL;
1561813dc37SSteven Rostedt
1571813dc37SSteven Rostedt mod_fmt = container_of(mod_fmt->list.next, typeof(*mod_fmt), list);
1581813dc37SSteven Rostedt
1591813dc37SSteven Rostedt return &mod_fmt->fmt;
1601813dc37SSteven Rostedt }
1611813dc37SSteven Rostedt
format_mod_start(void)1621813dc37SSteven Rostedt static void format_mod_start(void)
1631813dc37SSteven Rostedt {
1641813dc37SSteven Rostedt mutex_lock(&btrace_mutex);
1651813dc37SSteven Rostedt }
1661813dc37SSteven Rostedt
format_mod_stop(void)1671813dc37SSteven Rostedt static void format_mod_stop(void)
1681813dc37SSteven Rostedt {
1691813dc37SSteven Rostedt mutex_unlock(&btrace_mutex);
1701813dc37SSteven Rostedt }
1711813dc37SSteven Rostedt
172769b0441SFrederic Weisbecker #else /* !CONFIG_MODULES */
173769b0441SFrederic Weisbecker __init static int
module_trace_bprintk_format_notify(struct notifier_block * self,unsigned long val,void * data)174769b0441SFrederic Weisbecker module_trace_bprintk_format_notify(struct notifier_block *self,
175769b0441SFrederic Weisbecker unsigned long val, void *data)
176769b0441SFrederic Weisbecker {
1770340a6b7SPeter Zijlstra return NOTIFY_OK;
178769b0441SFrederic Weisbecker }
1791813dc37SSteven Rostedt static inline const char **
find_next_mod_format(int start_index,void * v,const char ** fmt,loff_t * pos)1801813dc37SSteven Rostedt find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
1811813dc37SSteven Rostedt {
1821813dc37SSteven Rostedt return NULL;
1831813dc37SSteven Rostedt }
format_mod_start(void)1841813dc37SSteven Rostedt static inline void format_mod_start(void) { }
format_mod_stop(void)1851813dc37SSteven Rostedt static inline void format_mod_stop(void) { }
186769b0441SFrederic Weisbecker #endif /* CONFIG_MODULES */
187769b0441SFrederic Weisbecker
188b9f9108cSSteven Rostedt (Red Hat) static bool __read_mostly trace_printk_enabled = true;
189b9f9108cSSteven Rostedt (Red Hat)
trace_printk_control(bool enabled)190b9f9108cSSteven Rostedt (Red Hat) void trace_printk_control(bool enabled)
191b9f9108cSSteven Rostedt (Red Hat) {
192b9f9108cSSteven Rostedt (Red Hat) trace_printk_enabled = enabled;
193b9f9108cSSteven Rostedt (Red Hat) }
194769b0441SFrederic Weisbecker
195769b0441SFrederic Weisbecker __initdata_or_module static
196769b0441SFrederic Weisbecker struct notifier_block module_trace_bprintk_format_nb = {
197769b0441SFrederic Weisbecker .notifier_call = module_trace_bprintk_format_notify,
198769b0441SFrederic Weisbecker };
199769b0441SFrederic Weisbecker
__trace_bprintk(unsigned long ip,const char * fmt,...)20048ead020SFrederic Weisbecker int __trace_bprintk(unsigned long ip, const char *fmt, ...)
201769b0441SFrederic Weisbecker {
202769b0441SFrederic Weisbecker int ret;
203769b0441SFrederic Weisbecker va_list ap;
204769b0441SFrederic Weisbecker
205769b0441SFrederic Weisbecker if (unlikely(!fmt))
206769b0441SFrederic Weisbecker return 0;
207769b0441SFrederic Weisbecker
208b9f9108cSSteven Rostedt (Red Hat) if (!trace_printk_enabled)
209769b0441SFrederic Weisbecker return 0;
210769b0441SFrederic Weisbecker
211769b0441SFrederic Weisbecker va_start(ap, fmt);
21240ce74f1SSteven Rostedt ret = trace_vbprintk(ip, fmt, ap);
21348ead020SFrederic Weisbecker va_end(ap);
21448ead020SFrederic Weisbecker return ret;
21548ead020SFrederic Weisbecker }
21648ead020SFrederic Weisbecker EXPORT_SYMBOL_GPL(__trace_bprintk);
21748ead020SFrederic Weisbecker
__ftrace_vbprintk(unsigned long ip,const char * fmt,va_list ap)21848ead020SFrederic Weisbecker int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap)
21948ead020SFrederic Weisbecker {
22048ead020SFrederic Weisbecker if (unlikely(!fmt))
22148ead020SFrederic Weisbecker return 0;
22248ead020SFrederic Weisbecker
223b9f9108cSSteven Rostedt (Red Hat) if (!trace_printk_enabled)
22448ead020SFrederic Weisbecker return 0;
22548ead020SFrederic Weisbecker
22640ce74f1SSteven Rostedt return trace_vbprintk(ip, fmt, ap);
22748ead020SFrederic Weisbecker }
22848ead020SFrederic Weisbecker EXPORT_SYMBOL_GPL(__ftrace_vbprintk);
22948ead020SFrederic Weisbecker
__trace_printk(unsigned long ip,const char * fmt,...)23048ead020SFrederic Weisbecker int __trace_printk(unsigned long ip, const char *fmt, ...)
23148ead020SFrederic Weisbecker {
23248ead020SFrederic Weisbecker int ret;
23348ead020SFrederic Weisbecker va_list ap;
23448ead020SFrederic Weisbecker
235b9f9108cSSteven Rostedt (Red Hat) if (!trace_printk_enabled)
23648ead020SFrederic Weisbecker return 0;
23748ead020SFrederic Weisbecker
23848ead020SFrederic Weisbecker va_start(ap, fmt);
23940ce74f1SSteven Rostedt ret = trace_vprintk(ip, fmt, ap);
240769b0441SFrederic Weisbecker va_end(ap);
241769b0441SFrederic Weisbecker return ret;
242769b0441SFrederic Weisbecker }
243769b0441SFrederic Weisbecker EXPORT_SYMBOL_GPL(__trace_printk);
244769b0441SFrederic Weisbecker
__ftrace_vprintk(unsigned long ip,const char * fmt,va_list ap)245769b0441SFrederic Weisbecker int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
246769b0441SFrederic Weisbecker {
247b9f9108cSSteven Rostedt (Red Hat) if (!trace_printk_enabled)
248769b0441SFrederic Weisbecker return 0;
249769b0441SFrederic Weisbecker
25040ce74f1SSteven Rostedt return trace_vprintk(ip, fmt, ap);
251769b0441SFrederic Weisbecker }
252769b0441SFrederic Weisbecker EXPORT_SYMBOL_GPL(__ftrace_vprintk);
253769b0441SFrederic Weisbecker
trace_is_tracepoint_string(const char * str)2549a6944feSSteven Rostedt (VMware) bool trace_is_tracepoint_string(const char *str)
2559a6944feSSteven Rostedt (VMware) {
2569a6944feSSteven Rostedt (VMware) const char **ptr = __start___tracepoint_str;
2579a6944feSSteven Rostedt (VMware)
2589a6944feSSteven Rostedt (VMware) for (ptr = __start___tracepoint_str; ptr < __stop___tracepoint_str; ptr++) {
2599a6944feSSteven Rostedt (VMware) if (str == *ptr)
2609a6944feSSteven Rostedt (VMware) return true;
2619a6944feSSteven Rostedt (VMware) }
2629a6944feSSteven Rostedt (VMware) return false;
2639a6944feSSteven Rostedt (VMware) }
2649a6944feSSteven Rostedt (VMware)
find_next(void * v,loff_t * pos)2651813dc37SSteven Rostedt static const char **find_next(void *v, loff_t *pos)
2661813dc37SSteven Rostedt {
2671813dc37SSteven Rostedt const char **fmt = v;
2681813dc37SSteven Rostedt int start_index;
269102c9323SSteven Rostedt (Red Hat) int last_index;
2701813dc37SSteven Rostedt
2711813dc37SSteven Rostedt start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
2721813dc37SSteven Rostedt
2731813dc37SSteven Rostedt if (*pos < start_index)
274db5e7eccSSteven Rostedt return __start___trace_bprintk_fmt + *pos;
2751813dc37SSteven Rostedt
276102c9323SSteven Rostedt (Red Hat) /*
277102c9323SSteven Rostedt (Red Hat) * The __tracepoint_str section is treated the same as the
278102c9323SSteven Rostedt (Red Hat) * __trace_printk_fmt section. The difference is that the
279102c9323SSteven Rostedt (Red Hat) * __trace_printk_fmt section should only be used by trace_printk()
280102c9323SSteven Rostedt (Red Hat) * in a debugging environment, as if anything exists in that section
281102c9323SSteven Rostedt (Red Hat) * the trace_prink() helper buffers are allocated, which would just
282102c9323SSteven Rostedt (Red Hat) * waste space in a production environment.
283102c9323SSteven Rostedt (Red Hat) *
284102c9323SSteven Rostedt (Red Hat) * The __tracepoint_str sections on the other hand are used by
285102c9323SSteven Rostedt (Red Hat) * tracepoints which need to map pointers to their strings to
286102c9323SSteven Rostedt (Red Hat) * the ASCII text for userspace.
287102c9323SSteven Rostedt (Red Hat) */
288102c9323SSteven Rostedt (Red Hat) last_index = start_index;
289102c9323SSteven Rostedt (Red Hat) start_index = __stop___tracepoint_str - __start___tracepoint_str;
290102c9323SSteven Rostedt (Red Hat)
291102c9323SSteven Rostedt (Red Hat) if (*pos < last_index + start_index)
292102c9323SSteven Rostedt (Red Hat) return __start___tracepoint_str + (*pos - last_index);
293102c9323SSteven Rostedt (Red Hat)
294f36d1be2SQiu Peiyang start_index += last_index;
2951813dc37SSteven Rostedt return find_next_mod_format(start_index, v, fmt, pos);
2961813dc37SSteven Rostedt }
2971813dc37SSteven Rostedt
2987975a2beSSteven Rostedt static void *
t_start(struct seq_file * m,loff_t * pos)299c8961ec6SLi Zefan t_start(struct seq_file *m, loff_t *pos)
3007975a2beSSteven Rostedt {
3011813dc37SSteven Rostedt format_mod_start();
3021813dc37SSteven Rostedt return find_next(NULL, pos);
3037975a2beSSteven Rostedt }
3047975a2beSSteven Rostedt
t_next(struct seq_file * m,void * v,loff_t * pos)305c8961ec6SLi Zefan static void *t_next(struct seq_file *m, void * v, loff_t *pos)
3067975a2beSSteven Rostedt {
307c8961ec6SLi Zefan (*pos)++;
3081813dc37SSteven Rostedt return find_next(v, pos);
3097975a2beSSteven Rostedt }
3107975a2beSSteven Rostedt
t_show(struct seq_file * m,void * v)3117975a2beSSteven Rostedt static int t_show(struct seq_file *m, void *v)
3127975a2beSSteven Rostedt {
3137975a2beSSteven Rostedt const char **fmt = v;
3147975a2beSSteven Rostedt const char *str = *fmt;
3157975a2beSSteven Rostedt int i;
3167975a2beSSteven Rostedt
3173debb0a9SSteven Rostedt (Red Hat) if (!*fmt)
3183debb0a9SSteven Rostedt (Red Hat) return 0;
3193debb0a9SSteven Rostedt (Red Hat)
3204c739ff0SSteven Rostedt seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
3217975a2beSSteven Rostedt
3227975a2beSSteven Rostedt /*
3237975a2beSSteven Rostedt * Tabs and new lines need to be converted.
3247975a2beSSteven Rostedt */
3257975a2beSSteven Rostedt for (i = 0; str[i]; i++) {
3267975a2beSSteven Rostedt switch (str[i]) {
3277975a2beSSteven Rostedt case '\n':
3287975a2beSSteven Rostedt seq_puts(m, "\\n");
3297975a2beSSteven Rostedt break;
3307975a2beSSteven Rostedt case '\t':
3317975a2beSSteven Rostedt seq_puts(m, "\\t");
3327975a2beSSteven Rostedt break;
3337975a2beSSteven Rostedt case '\\':
3341177e436SRasmus Villemoes seq_putc(m, '\\');
3357975a2beSSteven Rostedt break;
3367975a2beSSteven Rostedt case '"':
3377975a2beSSteven Rostedt seq_puts(m, "\\\"");
3387975a2beSSteven Rostedt break;
3397975a2beSSteven Rostedt default:
3407975a2beSSteven Rostedt seq_putc(m, str[i]);
3417975a2beSSteven Rostedt }
3427975a2beSSteven Rostedt }
3437975a2beSSteven Rostedt seq_puts(m, "\"\n");
3447975a2beSSteven Rostedt
3457975a2beSSteven Rostedt return 0;
3467975a2beSSteven Rostedt }
3477975a2beSSteven Rostedt
t_stop(struct seq_file * m,void * p)3487975a2beSSteven Rostedt static void t_stop(struct seq_file *m, void *p)
3497975a2beSSteven Rostedt {
3501813dc37SSteven Rostedt format_mod_stop();
3517975a2beSSteven Rostedt }
3527975a2beSSteven Rostedt
3537975a2beSSteven Rostedt static const struct seq_operations show_format_seq_ops = {
3547975a2beSSteven Rostedt .start = t_start,
3557975a2beSSteven Rostedt .next = t_next,
3567975a2beSSteven Rostedt .show = t_show,
3577975a2beSSteven Rostedt .stop = t_stop,
3587975a2beSSteven Rostedt };
3597975a2beSSteven Rostedt
3607975a2beSSteven Rostedt static int
ftrace_formats_open(struct inode * inode,struct file * file)3617975a2beSSteven Rostedt ftrace_formats_open(struct inode *inode, struct file *file)
3627975a2beSSteven Rostedt {
36317911ff3SSteven Rostedt (VMware) int ret;
36417911ff3SSteven Rostedt (VMware)
36517911ff3SSteven Rostedt (VMware) ret = security_locked_down(LOCKDOWN_TRACEFS);
36617911ff3SSteven Rostedt (VMware) if (ret)
36717911ff3SSteven Rostedt (VMware) return ret;
36817911ff3SSteven Rostedt (VMware)
369c8961ec6SLi Zefan return seq_open(file, &show_format_seq_ops);
3707975a2beSSteven Rostedt }
3717975a2beSSteven Rostedt
3727975a2beSSteven Rostedt static const struct file_operations ftrace_formats_fops = {
3737975a2beSSteven Rostedt .open = ftrace_formats_open,
3747975a2beSSteven Rostedt .read = seq_read,
3757975a2beSSteven Rostedt .llseek = seq_lseek,
3767975a2beSSteven Rostedt .release = seq_release,
3777975a2beSSteven Rostedt };
3787975a2beSSteven Rostedt
init_trace_printk_function_export(void)3797975a2beSSteven Rostedt static __init int init_trace_printk_function_export(void)
3807975a2beSSteven Rostedt {
38122c36b18SWei Yang int ret;
3827975a2beSSteven Rostedt
38322c36b18SWei Yang ret = tracing_init_dentry();
38422c36b18SWei Yang if (ret)
3857975a2beSSteven Rostedt return 0;
3867975a2beSSteven Rostedt
387*4e4f6e33SSteven Rostedt (VMware) trace_create_file("printk_formats", TRACE_MODE_READ, NULL,
3887975a2beSSteven Rostedt NULL, &ftrace_formats_fops);
3897975a2beSSteven Rostedt
3907975a2beSSteven Rostedt return 0;
3917975a2beSSteven Rostedt }
3927975a2beSSteven Rostedt
3937975a2beSSteven Rostedt fs_initcall(init_trace_printk_function_export);
3947975a2beSSteven Rostedt
init_trace_printk(void)395769b0441SFrederic Weisbecker static __init int init_trace_printk(void)
396769b0441SFrederic Weisbecker {
397769b0441SFrederic Weisbecker return register_module_notifier(&module_trace_bprintk_format_nb);
398769b0441SFrederic Weisbecker }
399769b0441SFrederic Weisbecker
400769b0441SFrederic Weisbecker early_initcall(init_trace_printk);
401