xref: /openbmc/linux/kernel/trace/trace_printk.c (revision 4e4f6e33)
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