1bcea3f96SSteven Rostedt (VMware) // SPDX-License-Identifier: GPL-2.0
2b77e38aaSSteven Rostedt /*
3b77e38aaSSteven Rostedt * event tracer
4b77e38aaSSteven Rostedt *
5b77e38aaSSteven Rostedt * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <[email protected]>
6b77e38aaSSteven Rostedt *
7981d081eSSteven Rostedt * - Added format output of fields of the trace point.
8981d081eSSteven Rostedt * This was based off of work by Tom Zanussi <[email protected]>.
9981d081eSSteven Rostedt *
10b77e38aaSSteven Rostedt */
11b77e38aaSSteven Rostedt
123448bac3SFabian Frederick #define pr_fmt(fmt) fmt
133448bac3SFabian Frederick
14e6187007SSteven Rostedt #include <linux/workqueue.h>
1517911ff3SSteven Rostedt (VMware) #include <linux/security.h>
16e6187007SSteven Rostedt #include <linux/spinlock.h>
17e6187007SSteven Rostedt #include <linux/kthread.h>
188434dc93SSteven Rostedt (Red Hat) #include <linux/tracefs.h>
19b77e38aaSSteven Rostedt #include <linux/uaccess.h>
20b77e38aaSSteven Rostedt #include <linux/module.h>
21b77e38aaSSteven Rostedt #include <linux/ctype.h>
2249090107SSteven Rostedt (Red Hat) #include <linux/sort.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
24e6187007SSteven Rostedt #include <linux/delay.h>
25b77e38aaSSteven Rostedt
263fdaf80fSSteven Rostedt (Red Hat) #include <trace/events/sched.h>
2704ae87a5SPeter Zijlstra #include <trace/syscall.h>
283fdaf80fSSteven Rostedt (Red Hat)
29020e5f85SLi Zefan #include <asm/setup.h>
30020e5f85SLi Zefan
3191729ef9SSteven Rostedt #include "trace_output.h"
32b77e38aaSSteven Rostedt
334e5292eaSSteven Rostedt #undef TRACE_SYSTEM
34b628b3e6SSteven Rostedt #define TRACE_SYSTEM "TRACE_SYSTEM"
35b628b3e6SSteven Rostedt
3620c8928aSLi Zefan DEFINE_MUTEX(event_mutex);
3711a241a3SSteven Rostedt
38a59fd602SSteven Rostedt LIST_HEAD(ftrace_events);
399f616680SDaniel Wagner static LIST_HEAD(ftrace_generic_fields);
40b3a8c6fdSzhangwei(Jovi) static LIST_HEAD(ftrace_common_fields);
41a838deabSMasami Hiramatsu static bool eventdir_initialized;
42a59fd602SSteven Rostedt
43795301d3SSteven Rostedt (Google) static LIST_HEAD(module_strings);
44795301d3SSteven Rostedt (Google)
45795301d3SSteven Rostedt (Google) struct module_string {
46795301d3SSteven Rostedt (Google) struct list_head next;
47795301d3SSteven Rostedt (Google) struct module *module;
48795301d3SSteven Rostedt (Google) char *str;
49795301d3SSteven Rostedt (Google) };
50795301d3SSteven Rostedt (Google)
51d1a29143SSteven Rostedt #define GFP_TRACE (GFP_KERNEL | __GFP_ZERO)
52d1a29143SSteven Rostedt
53d1a29143SSteven Rostedt static struct kmem_cache *field_cachep;
54d1a29143SSteven Rostedt static struct kmem_cache *file_cachep;
55d1a29143SSteven Rostedt
system_refcount(struct event_subsystem * system)566e94a780SSteven Rostedt static inline int system_refcount(struct event_subsystem *system)
576e94a780SSteven Rostedt {
5879ac6ef5SRasmus Villemoes return system->ref_count;
596e94a780SSteven Rostedt }
606e94a780SSteven Rostedt
system_refcount_inc(struct event_subsystem * system)616e94a780SSteven Rostedt static int system_refcount_inc(struct event_subsystem *system)
626e94a780SSteven Rostedt {
6379ac6ef5SRasmus Villemoes return system->ref_count++;
646e94a780SSteven Rostedt }
656e94a780SSteven Rostedt
system_refcount_dec(struct event_subsystem * system)666e94a780SSteven Rostedt static int system_refcount_dec(struct event_subsystem *system)
676e94a780SSteven Rostedt {
6879ac6ef5SRasmus Villemoes return --system->ref_count;
696e94a780SSteven Rostedt }
706e94a780SSteven Rostedt
71ae63b31eSSteven Rostedt /* Double loops, do not use break, only goto's work */
72ae63b31eSSteven Rostedt #define do_for_each_event_file(tr, file) \
73ae63b31eSSteven Rostedt list_for_each_entry(tr, &ftrace_trace_arrays, list) { \
74ae63b31eSSteven Rostedt list_for_each_entry(file, &tr->events, list)
75ae63b31eSSteven Rostedt
76ae63b31eSSteven Rostedt #define do_for_each_event_file_safe(tr, file) \
77ae63b31eSSteven Rostedt list_for_each_entry(tr, &ftrace_trace_arrays, list) { \
787f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *___n; \
79ae63b31eSSteven Rostedt list_for_each_entry_safe(file, ___n, &tr->events, list)
80ae63b31eSSteven Rostedt
81ae63b31eSSteven Rostedt #define while_for_each_event_file() \
82ae63b31eSSteven Rostedt }
83ae63b31eSSteven Rostedt
84b3a8c6fdSzhangwei(Jovi) static struct ftrace_event_field *
__find_event_field(struct list_head * head,const char * name)85afd2627fSSteven Rostedt __find_event_field(struct list_head *head, const char *name)
86b3a8c6fdSzhangwei(Jovi) {
87b3a8c6fdSzhangwei(Jovi) struct ftrace_event_field *field;
88b3a8c6fdSzhangwei(Jovi)
89b3a8c6fdSzhangwei(Jovi) list_for_each_entry(field, head, link) {
90b3a8c6fdSzhangwei(Jovi) if (!strcmp(field->name, name))
91b3a8c6fdSzhangwei(Jovi) return field;
92b3a8c6fdSzhangwei(Jovi) }
93b3a8c6fdSzhangwei(Jovi)
94b3a8c6fdSzhangwei(Jovi) return NULL;
95b3a8c6fdSzhangwei(Jovi) }
96b3a8c6fdSzhangwei(Jovi)
97b3a8c6fdSzhangwei(Jovi) struct ftrace_event_field *
trace_find_event_field(struct trace_event_call * call,char * name)982425bcb9SSteven Rostedt (Red Hat) trace_find_event_field(struct trace_event_call *call, char *name)
99b3a8c6fdSzhangwei(Jovi) {
100b3a8c6fdSzhangwei(Jovi) struct ftrace_event_field *field;
101b3a8c6fdSzhangwei(Jovi) struct list_head *head;
102b3a8c6fdSzhangwei(Jovi)
103e57cbaf0SSteven Rostedt (Red Hat) head = trace_get_fields(call);
104e57cbaf0SSteven Rostedt (Red Hat) field = __find_event_field(head, name);
105e57cbaf0SSteven Rostedt (Red Hat) if (field)
106e57cbaf0SSteven Rostedt (Red Hat) return field;
107e57cbaf0SSteven Rostedt (Red Hat)
1089f616680SDaniel Wagner field = __find_event_field(&ftrace_generic_fields, name);
1099f616680SDaniel Wagner if (field)
1109f616680SDaniel Wagner return field;
1119f616680SDaniel Wagner
112e57cbaf0SSteven Rostedt (Red Hat) return __find_event_field(&ftrace_common_fields, name);
113b3a8c6fdSzhangwei(Jovi) }
114b3a8c6fdSzhangwei(Jovi)
__trace_define_field(struct list_head * head,const char * type,const char * name,int offset,int size,int is_signed,int filter_type,int len,int need_test)1158728fe50SLi Zefan static int __trace_define_field(struct list_head *head, const char *type,
1168728fe50SLi Zefan const char *name, int offset, int size,
117afd2627fSSteven Rostedt int is_signed, int filter_type, int len,
118afd2627fSSteven Rostedt int need_test)
119cf027f64STom Zanussi {
120cf027f64STom Zanussi struct ftrace_event_field *field;
121cf027f64STom Zanussi
122d1a29143SSteven Rostedt field = kmem_cache_alloc(field_cachep, GFP_TRACE);
123cf027f64STom Zanussi if (!field)
124aaf6ac0fSNamhyung Kim return -ENOMEM;
125fe9f57f2SIngo Molnar
12692edca07SSteven Rostedt field->name = name;
12792edca07SSteven Rostedt field->type = type;
128fe9f57f2SIngo Molnar
12943b51eadSLi Zefan if (filter_type == FILTER_OTHER)
130aa38e9fcSLi Zefan field->filter_type = filter_assign_type(type);
13143b51eadSLi Zefan else
13243b51eadSLi Zefan field->filter_type = filter_type;
13343b51eadSLi Zefan
134cf027f64STom Zanussi field->offset = offset;
135cf027f64STom Zanussi field->size = size;
136a118e4d1STom Zanussi field->is_signed = is_signed;
137afd2627fSSteven Rostedt field->needs_test = need_test;
138b6c7abd1SYafang Shao field->len = len;
139aa38e9fcSLi Zefan
1402e33af02SSteven Rostedt list_add(&field->link, head);
141cf027f64STom Zanussi
142cf027f64STom Zanussi return 0;
143cf027f64STom Zanussi }
1448728fe50SLi Zefan
trace_define_field(struct trace_event_call * call,const char * type,const char * name,int offset,int size,int is_signed,int filter_type)1452425bcb9SSteven Rostedt (Red Hat) int trace_define_field(struct trace_event_call *call, const char *type,
1468728fe50SLi Zefan const char *name, int offset, int size, int is_signed,
1478728fe50SLi Zefan int filter_type)
1488728fe50SLi Zefan {
1498728fe50SLi Zefan struct list_head *head;
1508728fe50SLi Zefan
1518728fe50SLi Zefan if (WARN_ON(!call->class))
1528728fe50SLi Zefan return 0;
1538728fe50SLi Zefan
1548728fe50SLi Zefan head = trace_get_fields(call);
1558728fe50SLi Zefan return __trace_define_field(head, type, name, offset, size,
156afd2627fSSteven Rostedt is_signed, filter_type, 0, 0);
1578728fe50SLi Zefan }
15817c873ecSSteven Rostedt EXPORT_SYMBOL_GPL(trace_define_field);
159cf027f64STom Zanussi
trace_define_field_ext(struct trace_event_call * call,const char * type,const char * name,int offset,int size,int is_signed,int filter_type,int len,int need_test)16070b5339cSSteven Rostedt (Google) static int trace_define_field_ext(struct trace_event_call *call, const char *type,
161b6c7abd1SYafang Shao const char *name, int offset, int size, int is_signed,
162afd2627fSSteven Rostedt int filter_type, int len, int need_test)
163b6c7abd1SYafang Shao {
164b6c7abd1SYafang Shao struct list_head *head;
165b6c7abd1SYafang Shao
166b6c7abd1SYafang Shao if (WARN_ON(!call->class))
167b6c7abd1SYafang Shao return 0;
168b6c7abd1SYafang Shao
169b6c7abd1SYafang Shao head = trace_get_fields(call);
170b6c7abd1SYafang Shao return __trace_define_field(head, type, name, offset, size,
171afd2627fSSteven Rostedt is_signed, filter_type, len, need_test);
172b6c7abd1SYafang Shao }
173b6c7abd1SYafang Shao
1749f616680SDaniel Wagner #define __generic_field(type, item, filter_type) \
1759f616680SDaniel Wagner ret = __trace_define_field(&ftrace_generic_fields, #type, \
1769f616680SDaniel Wagner #item, 0, 0, is_signed_type(type), \
177afd2627fSSteven Rostedt filter_type, 0, 0); \
1789f616680SDaniel Wagner if (ret) \
1799f616680SDaniel Wagner return ret;
1809f616680SDaniel Wagner
181e647d6b3SLi Zefan #define __common_field(type, item) \
1828728fe50SLi Zefan ret = __trace_define_field(&ftrace_common_fields, #type, \
1838728fe50SLi Zefan "common_" #item, \
184e647d6b3SLi Zefan offsetof(typeof(ent), item), \
185e647d6b3SLi Zefan sizeof(ent.item), \
186afd2627fSSteven Rostedt is_signed_type(type), FILTER_OTHER, \
187afd2627fSSteven Rostedt 0, 0); \
188e647d6b3SLi Zefan if (ret) \
189e647d6b3SLi Zefan return ret;
190e647d6b3SLi Zefan
trace_define_generic_fields(void)1919f616680SDaniel Wagner static int trace_define_generic_fields(void)
1929f616680SDaniel Wagner {
1939f616680SDaniel Wagner int ret;
1949f616680SDaniel Wagner
195e57cbaf0SSteven Rostedt (Red Hat) __generic_field(int, CPU, FILTER_CPU);
196e57cbaf0SSteven Rostedt (Red Hat) __generic_field(int, cpu, FILTER_CPU);
197b2380577SSteven Rostedt (Google) __generic_field(int, common_cpu, FILTER_CPU);
198e57cbaf0SSteven Rostedt (Red Hat) __generic_field(char *, COMM, FILTER_COMM);
199e57cbaf0SSteven Rostedt (Red Hat) __generic_field(char *, comm, FILTER_COMM);
2004b512860SSteven Rostedt (Google) __generic_field(char *, stacktrace, FILTER_STACKTRACE);
2014b512860SSteven Rostedt (Google) __generic_field(char *, STACKTRACE, FILTER_STACKTRACE);
2029f616680SDaniel Wagner
2039f616680SDaniel Wagner return ret;
2049f616680SDaniel Wagner }
2059f616680SDaniel Wagner
trace_define_common_fields(void)2068728fe50SLi Zefan static int trace_define_common_fields(void)
207e647d6b3SLi Zefan {
208e647d6b3SLi Zefan int ret;
209e647d6b3SLi Zefan struct trace_entry ent;
210e647d6b3SLi Zefan
211e647d6b3SLi Zefan __common_field(unsigned short, type);
212e647d6b3SLi Zefan __common_field(unsigned char, flags);
21354357f0cSThomas Gleixner /* Holds both preempt_count and migrate_disable */
214e647d6b3SLi Zefan __common_field(unsigned char, preempt_count);
215e647d6b3SLi Zefan __common_field(int, pid);
216e647d6b3SLi Zefan
217e647d6b3SLi Zefan return ret;
218e647d6b3SLi Zefan }
219e647d6b3SLi Zefan
trace_destroy_fields(struct trace_event_call * call)2202425bcb9SSteven Rostedt (Red Hat) static void trace_destroy_fields(struct trace_event_call *call)
2212df75e41SLi Zefan {
2222df75e41SLi Zefan struct ftrace_event_field *field, *next;
2232e33af02SSteven Rostedt struct list_head *head;
2242df75e41SLi Zefan
2252e33af02SSteven Rostedt head = trace_get_fields(call);
2262e33af02SSteven Rostedt list_for_each_entry_safe(field, next, head, link) {
2272df75e41SLi Zefan list_del(&field->link);
228d1a29143SSteven Rostedt kmem_cache_free(field_cachep, field);
2292df75e41SLi Zefan }
2302df75e41SLi Zefan }
2312df75e41SLi Zefan
23232bbe007SAlexei Starovoitov /*
23332bbe007SAlexei Starovoitov * run-time version of trace_event_get_offsets_<call>() that returns the last
23432bbe007SAlexei Starovoitov * accessible offset of trace fields excluding __dynamic_array bytes
23532bbe007SAlexei Starovoitov */
trace_event_get_offsets(struct trace_event_call * call)23632bbe007SAlexei Starovoitov int trace_event_get_offsets(struct trace_event_call *call)
23732bbe007SAlexei Starovoitov {
23832bbe007SAlexei Starovoitov struct ftrace_event_field *tail;
23932bbe007SAlexei Starovoitov struct list_head *head;
24032bbe007SAlexei Starovoitov
24132bbe007SAlexei Starovoitov head = trace_get_fields(call);
24232bbe007SAlexei Starovoitov /*
24332bbe007SAlexei Starovoitov * head->next points to the last field with the largest offset,
24432bbe007SAlexei Starovoitov * since it was added last by trace_define_field()
24532bbe007SAlexei Starovoitov */
24632bbe007SAlexei Starovoitov tail = list_first_entry(head, struct ftrace_event_field, link);
24732bbe007SAlexei Starovoitov return tail->offset + tail->size;
24832bbe007SAlexei Starovoitov }
24932bbe007SAlexei Starovoitov
25065a25d9fSSteven Rostedt
find_event_field(const char * fmt,struct trace_event_call * call)25165a25d9fSSteven Rostedt static struct trace_event_fields *find_event_field(const char *fmt,
25265a25d9fSSteven Rostedt struct trace_event_call *call)
2535013f454SSteven Rostedt (VMware) {
2545013f454SSteven Rostedt (VMware) struct trace_event_fields *field = call->class->fields_array;
2555013f454SSteven Rostedt (VMware) const char *p = fmt;
2565013f454SSteven Rostedt (VMware) int len;
2575013f454SSteven Rostedt (VMware)
2585013f454SSteven Rostedt (VMware) if (!(len = str_has_prefix(fmt, "REC->")))
25965a25d9fSSteven Rostedt return NULL;
2605013f454SSteven Rostedt (VMware) fmt += len;
2615013f454SSteven Rostedt (VMware) for (p = fmt; *p; p++) {
2625013f454SSteven Rostedt (VMware) if (!isalnum(*p) && *p != '_')
2635013f454SSteven Rostedt (VMware) break;
2645013f454SSteven Rostedt (VMware) }
2655013f454SSteven Rostedt (VMware) len = p - fmt;
2665013f454SSteven Rostedt (VMware)
2675013f454SSteven Rostedt (VMware) for (; field->type; field++) {
268a6629626SSteven Rostedt if (strncmp(field->name, fmt, len) || field->name[len])
2695013f454SSteven Rostedt (VMware) continue;
27065a25d9fSSteven Rostedt
27165a25d9fSSteven Rostedt return field;
2725013f454SSteven Rostedt (VMware) }
27365a25d9fSSteven Rostedt return NULL;
27465a25d9fSSteven Rostedt }
27565a25d9fSSteven Rostedt
27665a25d9fSSteven Rostedt /*
27765a25d9fSSteven Rostedt * Check if the referenced field is an array and return true,
27865a25d9fSSteven Rostedt * as arrays are OK to dereference.
27965a25d9fSSteven Rostedt */
test_field(const char * fmt,struct trace_event_call * call)28065a25d9fSSteven Rostedt static bool test_field(const char *fmt, struct trace_event_call *call)
28165a25d9fSSteven Rostedt {
28265a25d9fSSteven Rostedt struct trace_event_fields *field;
28365a25d9fSSteven Rostedt
28465a25d9fSSteven Rostedt field = find_event_field(fmt, call);
28565a25d9fSSteven Rostedt if (!field)
2865013f454SSteven Rostedt (VMware) return false;
28765a25d9fSSteven Rostedt
28865a25d9fSSteven Rostedt /* This is an array and is OK to dereference. */
28965a25d9fSSteven Rostedt return strchr(field->type, '[') != NULL;
2905013f454SSteven Rostedt (VMware) }
2915013f454SSteven Rostedt (VMware)
29291711048SSteven Rostedt /* Look for a string within an argument */
find_print_string(const char * arg,const char * str,const char * end)29391711048SSteven Rostedt static bool find_print_string(const char *arg, const char *str, const char *end)
29491711048SSteven Rostedt {
29591711048SSteven Rostedt const char *r;
29691711048SSteven Rostedt
29791711048SSteven Rostedt r = strstr(arg, str);
29891711048SSteven Rostedt return r && r < end;
29991711048SSteven Rostedt }
30091711048SSteven Rostedt
301a6629626SSteven Rostedt /* Return true if the argument pointer is safe */
process_pointer(const char * fmt,int len,struct trace_event_call * call)302a6629626SSteven Rostedt static bool process_pointer(const char *fmt, int len, struct trace_event_call *call)
303a6629626SSteven Rostedt {
304a6629626SSteven Rostedt const char *r, *e, *a;
305a6629626SSteven Rostedt
306a6629626SSteven Rostedt e = fmt + len;
307a6629626SSteven Rostedt
308a6629626SSteven Rostedt /* Find the REC-> in the argument */
309a6629626SSteven Rostedt r = strstr(fmt, "REC->");
310a6629626SSteven Rostedt if (r && r < e) {
311a6629626SSteven Rostedt /*
312a6629626SSteven Rostedt * Addresses of events on the buffer, or an array on the buffer is
313a6629626SSteven Rostedt * OK to dereference. There's ways to fool this, but
314a6629626SSteven Rostedt * this is to catch common mistakes, not malicious code.
315a6629626SSteven Rostedt */
316a6629626SSteven Rostedt a = strchr(fmt, '&');
317a6629626SSteven Rostedt if ((a && (a < r)) || test_field(r, call))
318a6629626SSteven Rostedt return true;
31991711048SSteven Rostedt } else if (find_print_string(fmt, "__get_dynamic_array(", e)) {
320a6629626SSteven Rostedt return true;
32191711048SSteven Rostedt } else if (find_print_string(fmt, "__get_rel_dynamic_array(", e)) {
32291711048SSteven Rostedt return true;
32391711048SSteven Rostedt } else if (find_print_string(fmt, "__get_dynamic_array_len(", e)) {
32491711048SSteven Rostedt return true;
32591711048SSteven Rostedt } else if (find_print_string(fmt, "__get_rel_dynamic_array_len(", e)) {
32691711048SSteven Rostedt return true;
32791711048SSteven Rostedt } else if (find_print_string(fmt, "__get_sockaddr(", e)) {
32891711048SSteven Rostedt return true;
32991711048SSteven Rostedt } else if (find_print_string(fmt, "__get_rel_sockaddr(", e)) {
330a6629626SSteven Rostedt return true;
331a6629626SSteven Rostedt }
332a6629626SSteven Rostedt return false;
333a6629626SSteven Rostedt }
334a6629626SSteven Rostedt
33565a25d9fSSteven Rostedt /* Return true if the string is safe */
process_string(const char * fmt,int len,struct trace_event_call * call)33665a25d9fSSteven Rostedt static bool process_string(const char *fmt, int len, struct trace_event_call *call)
33765a25d9fSSteven Rostedt {
338afd2627fSSteven Rostedt struct trace_event_fields *field;
33965a25d9fSSteven Rostedt const char *r, *e, *s;
34065a25d9fSSteven Rostedt
34165a25d9fSSteven Rostedt e = fmt + len;
34265a25d9fSSteven Rostedt
34365a25d9fSSteven Rostedt /*
34465a25d9fSSteven Rostedt * There are several helper functions that return strings.
34565a25d9fSSteven Rostedt * If the argument contains a function, then assume its field is valid.
34665a25d9fSSteven Rostedt * It is considered that the argument has a function if it has:
34765a25d9fSSteven Rostedt * alphanumeric or '_' before a parenthesis.
34865a25d9fSSteven Rostedt */
34965a25d9fSSteven Rostedt s = fmt;
35065a25d9fSSteven Rostedt do {
35165a25d9fSSteven Rostedt r = strstr(s, "(");
35265a25d9fSSteven Rostedt if (!r || r >= e)
35365a25d9fSSteven Rostedt break;
35465a25d9fSSteven Rostedt for (int i = 1; r - i >= s; i++) {
35565a25d9fSSteven Rostedt char ch = *(r - i);
35665a25d9fSSteven Rostedt if (isspace(ch))
35765a25d9fSSteven Rostedt continue;
35865a25d9fSSteven Rostedt if (isalnum(ch) || ch == '_')
35965a25d9fSSteven Rostedt return true;
36065a25d9fSSteven Rostedt /* Anything else, this isn't a function */
36165a25d9fSSteven Rostedt break;
36265a25d9fSSteven Rostedt }
36365a25d9fSSteven Rostedt /* A function could be wrapped in parethesis, try the next one */
36465a25d9fSSteven Rostedt s = r + 1;
36565a25d9fSSteven Rostedt } while (s < e);
36665a25d9fSSteven Rostedt
36765a25d9fSSteven Rostedt /*
368afc67176SSteven Rostedt * Check for arrays. If the argument has: foo[REC->val]
369afc67176SSteven Rostedt * then it is very likely that foo is an array of strings
370afc67176SSteven Rostedt * that are safe to use.
371afc67176SSteven Rostedt */
372afc67176SSteven Rostedt r = strstr(s, "[");
373afc67176SSteven Rostedt if (r && r < e) {
374afc67176SSteven Rostedt r = strstr(r, "REC->");
375afc67176SSteven Rostedt if (r && r < e)
376afc67176SSteven Rostedt return true;
377afc67176SSteven Rostedt }
378afc67176SSteven Rostedt
379afc67176SSteven Rostedt /*
38065a25d9fSSteven Rostedt * If there's any strings in the argument consider this arg OK as it
38165a25d9fSSteven Rostedt * could be: REC->field ? "foo" : "bar" and we don't want to get into
38265a25d9fSSteven Rostedt * verifying that logic here.
38365a25d9fSSteven Rostedt */
38465a25d9fSSteven Rostedt if (find_print_string(fmt, "\"", e))
38565a25d9fSSteven Rostedt return true;
38665a25d9fSSteven Rostedt
38765a25d9fSSteven Rostedt /* Dereferenced strings are also valid like any other pointer */
38865a25d9fSSteven Rostedt if (process_pointer(fmt, len, call))
38965a25d9fSSteven Rostedt return true;
39065a25d9fSSteven Rostedt
391afd2627fSSteven Rostedt /* Make sure the field is found */
392afd2627fSSteven Rostedt field = find_event_field(fmt, call);
393afd2627fSSteven Rostedt if (!field)
394afd2627fSSteven Rostedt return false;
395afd2627fSSteven Rostedt
396afd2627fSSteven Rostedt /* Test this field's string before printing the event */
397afd2627fSSteven Rostedt call->flags |= TRACE_EVENT_FL_TEST_STR;
398afd2627fSSteven Rostedt field->needs_test = 1;
399afd2627fSSteven Rostedt
400afd2627fSSteven Rostedt return true;
40165a25d9fSSteven Rostedt }
40265a25d9fSSteven Rostedt
4035013f454SSteven Rostedt (VMware) /*
4045013f454SSteven Rostedt (VMware) * Examine the print fmt of the event looking for unsafe dereference
4055013f454SSteven Rostedt (VMware) * pointers using %p* that could be recorded in the trace event and
4065013f454SSteven Rostedt (VMware) * much later referenced after the pointer was freed. Dereferencing
4075013f454SSteven Rostedt (VMware) * pointers are OK, if it is dereferenced into the event itself.
4085013f454SSteven Rostedt (VMware) */
test_event_printk(struct trace_event_call * call)4095013f454SSteven Rostedt (VMware) static void test_event_printk(struct trace_event_call *call)
4105013f454SSteven Rostedt (VMware) {
4115013f454SSteven Rostedt (VMware) u64 dereference_flags = 0;
41265a25d9fSSteven Rostedt u64 string_flags = 0;
4135013f454SSteven Rostedt (VMware) bool first = true;
414a6629626SSteven Rostedt const char *fmt;
4155013f454SSteven Rostedt (VMware) int parens = 0;
4165013f454SSteven Rostedt (VMware) char in_quote = 0;
4175013f454SSteven Rostedt (VMware) int start_arg = 0;
4185013f454SSteven Rostedt (VMware) int arg = 0;
419a6629626SSteven Rostedt int i, e;
4205013f454SSteven Rostedt (VMware)
4215013f454SSteven Rostedt (VMware) fmt = call->print_fmt;
4225013f454SSteven Rostedt (VMware)
4235013f454SSteven Rostedt (VMware) if (!fmt)
4245013f454SSteven Rostedt (VMware) return;
4255013f454SSteven Rostedt (VMware)
4265013f454SSteven Rostedt (VMware) for (i = 0; fmt[i]; i++) {
4275013f454SSteven Rostedt (VMware) switch (fmt[i]) {
4285013f454SSteven Rostedt (VMware) case '\\':
4295013f454SSteven Rostedt (VMware) i++;
4305013f454SSteven Rostedt (VMware) if (!fmt[i])
4315013f454SSteven Rostedt (VMware) return;
4325013f454SSteven Rostedt (VMware) continue;
4335013f454SSteven Rostedt (VMware) case '"':
4345013f454SSteven Rostedt (VMware) case '\'':
4355013f454SSteven Rostedt (VMware) /*
4365013f454SSteven Rostedt (VMware) * The print fmt starts with a string that
4375013f454SSteven Rostedt (VMware) * is processed first to find %p* usage,
4385013f454SSteven Rostedt (VMware) * then after the first string, the print fmt
4395013f454SSteven Rostedt (VMware) * contains arguments that are used to check
4405013f454SSteven Rostedt (VMware) * if the dereferenced %p* usage is safe.
4415013f454SSteven Rostedt (VMware) */
4425013f454SSteven Rostedt (VMware) if (first) {
4435013f454SSteven Rostedt (VMware) if (fmt[i] == '\'')
4445013f454SSteven Rostedt (VMware) continue;
4455013f454SSteven Rostedt (VMware) if (in_quote) {
4465013f454SSteven Rostedt (VMware) arg = 0;
4475013f454SSteven Rostedt (VMware) first = false;
4485013f454SSteven Rostedt (VMware) /*
4495013f454SSteven Rostedt (VMware) * If there was no %p* uses
4505013f454SSteven Rostedt (VMware) * the fmt is OK.
4515013f454SSteven Rostedt (VMware) */
4525013f454SSteven Rostedt (VMware) if (!dereference_flags)
4535013f454SSteven Rostedt (VMware) return;
4545013f454SSteven Rostedt (VMware) }
4555013f454SSteven Rostedt (VMware) }
4565013f454SSteven Rostedt (VMware) if (in_quote) {
4575013f454SSteven Rostedt (VMware) if (in_quote == fmt[i])
4585013f454SSteven Rostedt (VMware) in_quote = 0;
4595013f454SSteven Rostedt (VMware) } else {
4605013f454SSteven Rostedt (VMware) in_quote = fmt[i];
4615013f454SSteven Rostedt (VMware) }
4625013f454SSteven Rostedt (VMware) continue;
4635013f454SSteven Rostedt (VMware) case '%':
4645013f454SSteven Rostedt (VMware) if (!first || !in_quote)
4655013f454SSteven Rostedt (VMware) continue;
4665013f454SSteven Rostedt (VMware) i++;
4675013f454SSteven Rostedt (VMware) if (!fmt[i])
4685013f454SSteven Rostedt (VMware) return;
4695013f454SSteven Rostedt (VMware) switch (fmt[i]) {
4705013f454SSteven Rostedt (VMware) case '%':
4715013f454SSteven Rostedt (VMware) continue;
4725013f454SSteven Rostedt (VMware) case 'p':
473*ea8d7647SSteven Rostedt do_pointer:
4745013f454SSteven Rostedt (VMware) /* Find dereferencing fields */
4755013f454SSteven Rostedt (VMware) switch (fmt[i + 1]) {
4765013f454SSteven Rostedt (VMware) case 'B': case 'R': case 'r':
4775013f454SSteven Rostedt (VMware) case 'b': case 'M': case 'm':
4785013f454SSteven Rostedt (VMware) case 'I': case 'i': case 'E':
4795013f454SSteven Rostedt (VMware) case 'U': case 'V': case 'N':
4805013f454SSteven Rostedt (VMware) case 'a': case 'd': case 'D':
4815013f454SSteven Rostedt (VMware) case 'g': case 't': case 'C':
4825013f454SSteven Rostedt (VMware) case 'O': case 'f':
4835013f454SSteven Rostedt (VMware) if (WARN_ONCE(arg == 63,
4845013f454SSteven Rostedt (VMware) "Too many args for event: %s",
4855013f454SSteven Rostedt (VMware) trace_event_name(call)))
4865013f454SSteven Rostedt (VMware) return;
4875013f454SSteven Rostedt (VMware) dereference_flags |= 1ULL << arg;
4885013f454SSteven Rostedt (VMware) }
4895013f454SSteven Rostedt (VMware) break;
4905013f454SSteven Rostedt (VMware) default:
4915013f454SSteven Rostedt (VMware) {
4925013f454SSteven Rostedt (VMware) bool star = false;
4935013f454SSteven Rostedt (VMware) int j;
4945013f454SSteven Rostedt (VMware)
4955013f454SSteven Rostedt (VMware) /* Increment arg if %*s exists. */
4965013f454SSteven Rostedt (VMware) for (j = 0; fmt[i + j]; j++) {
4975013f454SSteven Rostedt (VMware) if (isdigit(fmt[i + j]) ||
4985013f454SSteven Rostedt (VMware) fmt[i + j] == '.')
4995013f454SSteven Rostedt (VMware) continue;
5005013f454SSteven Rostedt (VMware) if (fmt[i + j] == '*') {
5015013f454SSteven Rostedt (VMware) star = true;
502*ea8d7647SSteven Rostedt /* Handle %*pbl case */
503*ea8d7647SSteven Rostedt if (!j && fmt[i + 1] == 'p') {
504*ea8d7647SSteven Rostedt arg++;
505*ea8d7647SSteven Rostedt i++;
506*ea8d7647SSteven Rostedt goto do_pointer;
507*ea8d7647SSteven Rostedt }
5085013f454SSteven Rostedt (VMware) continue;
5095013f454SSteven Rostedt (VMware) }
51065a25d9fSSteven Rostedt if ((fmt[i + j] == 's')) {
51165a25d9fSSteven Rostedt if (star)
5125013f454SSteven Rostedt (VMware) arg++;
51365a25d9fSSteven Rostedt if (WARN_ONCE(arg == 63,
51465a25d9fSSteven Rostedt "Too many args for event: %s",
51565a25d9fSSteven Rostedt trace_event_name(call)))
51665a25d9fSSteven Rostedt return;
51765a25d9fSSteven Rostedt dereference_flags |= 1ULL << arg;
51865a25d9fSSteven Rostedt string_flags |= 1ULL << arg;
51965a25d9fSSteven Rostedt }
5205013f454SSteven Rostedt (VMware) break;
5215013f454SSteven Rostedt (VMware) }
5225013f454SSteven Rostedt (VMware) break;
5235013f454SSteven Rostedt (VMware) } /* default */
5245013f454SSteven Rostedt (VMware)
5255013f454SSteven Rostedt (VMware) } /* switch */
5265013f454SSteven Rostedt (VMware) arg++;
5275013f454SSteven Rostedt (VMware) continue;
5285013f454SSteven Rostedt (VMware) case '(':
5295013f454SSteven Rostedt (VMware) if (in_quote)
5305013f454SSteven Rostedt (VMware) continue;
5315013f454SSteven Rostedt (VMware) parens++;
5325013f454SSteven Rostedt (VMware) continue;
5335013f454SSteven Rostedt (VMware) case ')':
5345013f454SSteven Rostedt (VMware) if (in_quote)
5355013f454SSteven Rostedt (VMware) continue;
5365013f454SSteven Rostedt (VMware) parens--;
5375013f454SSteven Rostedt (VMware) if (WARN_ONCE(parens < 0,
5385013f454SSteven Rostedt (VMware) "Paren mismatch for event: %s\narg='%s'\n%*s",
5395013f454SSteven Rostedt (VMware) trace_event_name(call),
5405013f454SSteven Rostedt (VMware) fmt + start_arg,
5415013f454SSteven Rostedt (VMware) (i - start_arg) + 5, "^"))
5425013f454SSteven Rostedt (VMware) return;
5435013f454SSteven Rostedt (VMware) continue;
5445013f454SSteven Rostedt (VMware) case ',':
5455013f454SSteven Rostedt (VMware) if (in_quote || parens)
5465013f454SSteven Rostedt (VMware) continue;
547a6629626SSteven Rostedt e = i;
5485013f454SSteven Rostedt (VMware) i++;
5495013f454SSteven Rostedt (VMware) while (isspace(fmt[i]))
5505013f454SSteven Rostedt (VMware) i++;
5515013f454SSteven Rostedt (VMware)
5525013f454SSteven Rostedt (VMware) /*
553a6629626SSteven Rostedt * If start_arg is zero, then this is the start of the
554a6629626SSteven Rostedt * first argument. The processing of the argument happens
555a6629626SSteven Rostedt * when the end of the argument is found, as it needs to
556a6629626SSteven Rostedt * handle paranthesis and such.
5575013f454SSteven Rostedt (VMware) */
558a6629626SSteven Rostedt if (!start_arg) {
559a6629626SSteven Rostedt start_arg = i;
560a6629626SSteven Rostedt /* Balance out the i++ in the for loop */
561a6629626SSteven Rostedt i--;
562a6629626SSteven Rostedt continue;
563a6629626SSteven Rostedt }
564a6629626SSteven Rostedt
565a6629626SSteven Rostedt if (dereference_flags & (1ULL << arg)) {
56665a25d9fSSteven Rostedt if (string_flags & (1ULL << arg)) {
56765a25d9fSSteven Rostedt if (process_string(fmt + start_arg, e - start_arg, call))
56865a25d9fSSteven Rostedt dereference_flags &= ~(1ULL << arg);
56965a25d9fSSteven Rostedt } else if (process_pointer(fmt + start_arg, e - start_arg, call))
570499f1216SSteven Rostedt (Google) dereference_flags &= ~(1ULL << arg);
5715013f454SSteven Rostedt (VMware) }
572499f1216SSteven Rostedt (Google)
573a6629626SSteven Rostedt start_arg = i;
5745013f454SSteven Rostedt (VMware) arg++;
575a6629626SSteven Rostedt /* Balance out the i++ in the for loop */
576a6629626SSteven Rostedt i--;
5775013f454SSteven Rostedt (VMware) }
5785013f454SSteven Rostedt (VMware) }
5795013f454SSteven Rostedt (VMware)
580a6629626SSteven Rostedt if (dereference_flags & (1ULL << arg)) {
58165a25d9fSSteven Rostedt if (string_flags & (1ULL << arg)) {
58265a25d9fSSteven Rostedt if (process_string(fmt + start_arg, i - start_arg, call))
58365a25d9fSSteven Rostedt dereference_flags &= ~(1ULL << arg);
58465a25d9fSSteven Rostedt } else if (process_pointer(fmt + start_arg, i - start_arg, call))
585a6629626SSteven Rostedt dereference_flags &= ~(1ULL << arg);
586a6629626SSteven Rostedt }
587a6629626SSteven Rostedt
5885013f454SSteven Rostedt (VMware) /*
5895013f454SSteven Rostedt (VMware) * If you triggered the below warning, the trace event reported
5905013f454SSteven Rostedt (VMware) * uses an unsafe dereference pointer %p*. As the data stored
5915013f454SSteven Rostedt (VMware) * at the trace event time may no longer exist when the trace
5925013f454SSteven Rostedt (VMware) * event is printed, dereferencing to the original source is
5935013f454SSteven Rostedt (VMware) * unsafe. The source of the dereference must be copied into the
5945013f454SSteven Rostedt (VMware) * event itself, and the dereference must access the copy instead.
5955013f454SSteven Rostedt (VMware) */
5965013f454SSteven Rostedt (VMware) if (WARN_ON_ONCE(dereference_flags)) {
5975013f454SSteven Rostedt (VMware) arg = 1;
5985013f454SSteven Rostedt (VMware) while (!(dereference_flags & 1)) {
5995013f454SSteven Rostedt (VMware) dereference_flags >>= 1;
6005013f454SSteven Rostedt (VMware) arg++;
6015013f454SSteven Rostedt (VMware) }
6025013f454SSteven Rostedt (VMware) pr_warn("event %s has unsafe dereference of argument %d\n",
6035013f454SSteven Rostedt (VMware) trace_event_name(call), arg);
6045013f454SSteven Rostedt (VMware) pr_warn("print_fmt: %s\n", fmt);
6055013f454SSteven Rostedt (VMware) }
6065013f454SSteven Rostedt (VMware) }
6075013f454SSteven Rostedt (VMware)
trace_event_raw_init(struct trace_event_call * call)6082425bcb9SSteven Rostedt (Red Hat) int trace_event_raw_init(struct trace_event_call *call)
60987d9b4e1SLi Zefan {
61087d9b4e1SLi Zefan int id;
61187d9b4e1SLi Zefan
6129023c930SSteven Rostedt (Red Hat) id = register_trace_event(&call->event);
61387d9b4e1SLi Zefan if (!id)
61487d9b4e1SLi Zefan return -ENODEV;
61587d9b4e1SLi Zefan
6165013f454SSteven Rostedt (VMware) test_event_printk(call);
6175013f454SSteven Rostedt (VMware)
61887d9b4e1SLi Zefan return 0;
61987d9b4e1SLi Zefan }
62087d9b4e1SLi Zefan EXPORT_SYMBOL_GPL(trace_event_raw_init);
62187d9b4e1SLi Zefan
trace_event_ignore_this_pid(struct trace_event_file * trace_file)6223fdaf80fSSteven Rostedt (Red Hat) bool trace_event_ignore_this_pid(struct trace_event_file *trace_file)
6233fdaf80fSSteven Rostedt (Red Hat) {
6243fdaf80fSSteven Rostedt (Red Hat) struct trace_array *tr = trace_file->tr;
6253fdaf80fSSteven Rostedt (Red Hat) struct trace_array_cpu *data;
62627683626SSteven Rostedt (VMware) struct trace_pid_list *no_pid_list;
6273fdaf80fSSteven Rostedt (Red Hat) struct trace_pid_list *pid_list;
6283fdaf80fSSteven Rostedt (Red Hat)
629da25a672SJoel Fernandes (Google) pid_list = rcu_dereference_raw(tr->filtered_pids);
63027683626SSteven Rostedt (VMware) no_pid_list = rcu_dereference_raw(tr->filtered_no_pids);
63127683626SSteven Rostedt (VMware)
63227683626SSteven Rostedt (VMware) if (!pid_list && !no_pid_list)
6333fdaf80fSSteven Rostedt (Red Hat) return false;
6343fdaf80fSSteven Rostedt (Red Hat)
6351c5eb448SSteven Rostedt (VMware) data = this_cpu_ptr(tr->array_buffer.data);
6363fdaf80fSSteven Rostedt (Red Hat)
6373fdaf80fSSteven Rostedt (Red Hat) return data->ignore_pid;
6383fdaf80fSSteven Rostedt (Red Hat) }
6393fdaf80fSSteven Rostedt (Red Hat) EXPORT_SYMBOL_GPL(trace_event_ignore_this_pid);
6403fdaf80fSSteven Rostedt (Red Hat)
trace_event_buffer_reserve(struct trace_event_buffer * fbuffer,struct trace_event_file * trace_file,unsigned long len)6413f795dcfSSteven Rostedt (Red Hat) void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer,
6427f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *trace_file,
6433fd40d1eSSteven Rostedt unsigned long len)
6443fd40d1eSSteven Rostedt {
6452425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *event_call = trace_file->event_call;
6463fd40d1eSSteven Rostedt
6473fdaf80fSSteven Rostedt (Red Hat) if ((trace_file->flags & EVENT_FILE_FL_PID_FILTER) &&
6483fdaf80fSSteven Rostedt (Red Hat) trace_event_ignore_this_pid(trace_file))
6493fdaf80fSSteven Rostedt (Red Hat) return NULL;
6503fdaf80fSSteven Rostedt (Red Hat)
651e947841cSSteven Rostedt (Red Hat) /*
65230c93704SThomas Gleixner * If CONFIG_PREEMPTION is enabled, then the tracepoint itself disables
653e947841cSSteven Rostedt (Red Hat) * preemption (adding one to the preempt_count). Since we are
654e947841cSSteven Rostedt (Red Hat) * interested in the preempt_count at the time the tracepoint was
655e947841cSSteven Rostedt (Red Hat) * hit, we need to subtract one to offset the increment.
656e947841cSSteven Rostedt (Red Hat) */
65736590c50SSebastian Andrzej Siewior fbuffer->trace_ctx = tracing_gen_ctx_dec();
6587f1d2f82SSteven Rostedt (Red Hat) fbuffer->trace_file = trace_file;
6593fd40d1eSSteven Rostedt
6603fd40d1eSSteven Rostedt fbuffer->event =
6617f1d2f82SSteven Rostedt (Red Hat) trace_event_buffer_lock_reserve(&fbuffer->buffer, trace_file,
6623fd40d1eSSteven Rostedt event_call->event.type, len,
66336590c50SSebastian Andrzej Siewior fbuffer->trace_ctx);
6643fd40d1eSSteven Rostedt if (!fbuffer->event)
6653fd40d1eSSteven Rostedt return NULL;
6663fd40d1eSSteven Rostedt
6678cfcf155SMasami Hiramatsu fbuffer->regs = NULL;
6683fd40d1eSSteven Rostedt fbuffer->entry = ring_buffer_event_data(fbuffer->event);
6693fd40d1eSSteven Rostedt return fbuffer->entry;
6703fd40d1eSSteven Rostedt }
6713f795dcfSSteven Rostedt (Red Hat) EXPORT_SYMBOL_GPL(trace_event_buffer_reserve);
6723fd40d1eSSteven Rostedt
trace_event_reg(struct trace_event_call * call,enum trace_reg type,void * data)6732425bcb9SSteven Rostedt (Red Hat) int trace_event_reg(struct trace_event_call *call,
674ceec0b6fSJiri Olsa enum trace_reg type, void *data)
675a1d0ce82SSteven Rostedt {
6767f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file = data;
677ae63b31eSSteven Rostedt
678de7b2973SMathieu Desnoyers WARN_ON(!(call->flags & TRACE_EVENT_FL_TRACEPOINT));
679a1d0ce82SSteven Rostedt switch (type) {
680a1d0ce82SSteven Rostedt case TRACE_REG_REGISTER:
681de7b2973SMathieu Desnoyers return tracepoint_probe_register(call->tp,
682a1d0ce82SSteven Rostedt call->class->probe,
683ae63b31eSSteven Rostedt file);
684a1d0ce82SSteven Rostedt case TRACE_REG_UNREGISTER:
685de7b2973SMathieu Desnoyers tracepoint_probe_unregister(call->tp,
686a1d0ce82SSteven Rostedt call->class->probe,
687ae63b31eSSteven Rostedt file);
688a1d0ce82SSteven Rostedt return 0;
689a1d0ce82SSteven Rostedt
690a1d0ce82SSteven Rostedt #ifdef CONFIG_PERF_EVENTS
691a1d0ce82SSteven Rostedt case TRACE_REG_PERF_REGISTER:
692de7b2973SMathieu Desnoyers return tracepoint_probe_register(call->tp,
693a1d0ce82SSteven Rostedt call->class->perf_probe,
694a1d0ce82SSteven Rostedt call);
695a1d0ce82SSteven Rostedt case TRACE_REG_PERF_UNREGISTER:
696de7b2973SMathieu Desnoyers tracepoint_probe_unregister(call->tp,
697a1d0ce82SSteven Rostedt call->class->perf_probe,
698a1d0ce82SSteven Rostedt call);
699a1d0ce82SSteven Rostedt return 0;
700ceec0b6fSJiri Olsa case TRACE_REG_PERF_OPEN:
701ceec0b6fSJiri Olsa case TRACE_REG_PERF_CLOSE:
702489c75c3SJiri Olsa case TRACE_REG_PERF_ADD:
703489c75c3SJiri Olsa case TRACE_REG_PERF_DEL:
704ceec0b6fSJiri Olsa return 0;
705a1d0ce82SSteven Rostedt #endif
706a1d0ce82SSteven Rostedt }
707a1d0ce82SSteven Rostedt return 0;
708a1d0ce82SSteven Rostedt }
7099023c930SSteven Rostedt (Red Hat) EXPORT_SYMBOL_GPL(trace_event_reg);
710a1d0ce82SSteven Rostedt
trace_event_enable_cmd_record(bool enable)711e870e9a1SLi Zefan void trace_event_enable_cmd_record(bool enable)
712e870e9a1SLi Zefan {
7137f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
714ae63b31eSSteven Rostedt struct trace_array *tr;
715e870e9a1SLi Zefan
7163a53acf1SPrateek Sood lockdep_assert_held(&event_mutex);
7173a53acf1SPrateek Sood
718ae63b31eSSteven Rostedt do_for_each_event_file(tr, file) {
719ae63b31eSSteven Rostedt
7205d6ad960SSteven Rostedt (Red Hat) if (!(file->flags & EVENT_FILE_FL_ENABLED))
721e870e9a1SLi Zefan continue;
722e870e9a1SLi Zefan
723e870e9a1SLi Zefan if (enable) {
724e870e9a1SLi Zefan tracing_start_cmdline_record();
7255d6ad960SSteven Rostedt (Red Hat) set_bit(EVENT_FILE_FL_RECORDED_CMD_BIT, &file->flags);
726e870e9a1SLi Zefan } else {
727e870e9a1SLi Zefan tracing_stop_cmdline_record();
7285d6ad960SSteven Rostedt (Red Hat) clear_bit(EVENT_FILE_FL_RECORDED_CMD_BIT, &file->flags);
729e870e9a1SLi Zefan }
730ae63b31eSSteven Rostedt } while_for_each_event_file();
731e870e9a1SLi Zefan }
732e870e9a1SLi Zefan
trace_event_enable_tgid_record(bool enable)733d914ba37SJoel Fernandes void trace_event_enable_tgid_record(bool enable)
734d914ba37SJoel Fernandes {
735d914ba37SJoel Fernandes struct trace_event_file *file;
736d914ba37SJoel Fernandes struct trace_array *tr;
737d914ba37SJoel Fernandes
7383a53acf1SPrateek Sood lockdep_assert_held(&event_mutex);
7393a53acf1SPrateek Sood
740d914ba37SJoel Fernandes do_for_each_event_file(tr, file) {
741d914ba37SJoel Fernandes if (!(file->flags & EVENT_FILE_FL_ENABLED))
742d914ba37SJoel Fernandes continue;
743d914ba37SJoel Fernandes
744d914ba37SJoel Fernandes if (enable) {
745d914ba37SJoel Fernandes tracing_start_tgid_record();
746d914ba37SJoel Fernandes set_bit(EVENT_FILE_FL_RECORDED_TGID_BIT, &file->flags);
747d914ba37SJoel Fernandes } else {
748d914ba37SJoel Fernandes tracing_stop_tgid_record();
749d914ba37SJoel Fernandes clear_bit(EVENT_FILE_FL_RECORDED_TGID_BIT,
750d914ba37SJoel Fernandes &file->flags);
751d914ba37SJoel Fernandes }
752d914ba37SJoel Fernandes } while_for_each_event_file();
753d914ba37SJoel Fernandes }
754d914ba37SJoel Fernandes
__ftrace_event_enable_disable(struct trace_event_file * file,int enable,int soft_disable)7557f1d2f82SSteven Rostedt (Red Hat) static int __ftrace_event_enable_disable(struct trace_event_file *file,
756417944c4SSteven Rostedt (Red Hat) int enable, int soft_disable)
757fd994989SSteven Rostedt {
7582425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call = file->event_call;
759983f938aSSteven Rostedt (Red Hat) struct trace_array *tr = file->tr;
7603b8e4273SLi Zefan int ret = 0;
761417944c4SSteven Rostedt (Red Hat) int disable;
7623b8e4273SLi Zefan
763fd994989SSteven Rostedt switch (enable) {
764fd994989SSteven Rostedt case 0:
765417944c4SSteven Rostedt (Red Hat) /*
7661cf4c073SMasami Hiramatsu * When soft_disable is set and enable is cleared, the sm_ref
7671cf4c073SMasami Hiramatsu * reference counter is decremented. If it reaches 0, we want
768417944c4SSteven Rostedt (Red Hat) * to clear the SOFT_DISABLED flag but leave the event in the
769417944c4SSteven Rostedt (Red Hat) * state that it was. That is, if the event was enabled and
770417944c4SSteven Rostedt (Red Hat) * SOFT_DISABLED isn't set, then do nothing. But if SOFT_DISABLED
771417944c4SSteven Rostedt (Red Hat) * is set we do not want the event to be enabled before we
772417944c4SSteven Rostedt (Red Hat) * clear the bit.
773417944c4SSteven Rostedt (Red Hat) *
774417944c4SSteven Rostedt (Red Hat) * When soft_disable is not set but the SOFT_MODE flag is,
775417944c4SSteven Rostedt (Red Hat) * we do nothing. Do not disable the tracepoint, otherwise
776417944c4SSteven Rostedt (Red Hat) * "soft enable"s (clearing the SOFT_DISABLED bit) wont work.
777417944c4SSteven Rostedt (Red Hat) */
778417944c4SSteven Rostedt (Red Hat) if (soft_disable) {
7791cf4c073SMasami Hiramatsu if (atomic_dec_return(&file->sm_ref) > 0)
7801cf4c073SMasami Hiramatsu break;
7815d6ad960SSteven Rostedt (Red Hat) disable = file->flags & EVENT_FILE_FL_SOFT_DISABLED;
7825d6ad960SSteven Rostedt (Red Hat) clear_bit(EVENT_FILE_FL_SOFT_MODE_BIT, &file->flags);
783dea49978SZheng Yejian /* Disable use of trace_buffered_event */
784dea49978SZheng Yejian trace_buffered_event_disable();
785417944c4SSteven Rostedt (Red Hat) } else
7865d6ad960SSteven Rostedt (Red Hat) disable = !(file->flags & EVENT_FILE_FL_SOFT_MODE);
787417944c4SSteven Rostedt (Red Hat)
7885d6ad960SSteven Rostedt (Red Hat) if (disable && (file->flags & EVENT_FILE_FL_ENABLED)) {
7895d6ad960SSteven Rostedt (Red Hat) clear_bit(EVENT_FILE_FL_ENABLED_BIT, &file->flags);
7905d6ad960SSteven Rostedt (Red Hat) if (file->flags & EVENT_FILE_FL_RECORDED_CMD) {
791b11c53e1SZhaolei tracing_stop_cmdline_record();
7925d6ad960SSteven Rostedt (Red Hat) clear_bit(EVENT_FILE_FL_RECORDED_CMD_BIT, &file->flags);
793e870e9a1SLi Zefan }
794d914ba37SJoel Fernandes
795d914ba37SJoel Fernandes if (file->flags & EVENT_FILE_FL_RECORDED_TGID) {
796d914ba37SJoel Fernandes tracing_stop_tgid_record();
7977685ab6cSChunyu Hu clear_bit(EVENT_FILE_FL_RECORDED_TGID_BIT, &file->flags);
798d914ba37SJoel Fernandes }
799d914ba37SJoel Fernandes
8000c588ac0SGabriele Paoloni ret = call->class->reg(call, TRACE_REG_UNREGISTER, file);
8010c588ac0SGabriele Paoloni
8020c588ac0SGabriele Paoloni WARN_ON_ONCE(ret);
803fd994989SSteven Rostedt }
8043baa5e4cSTom Zanussi /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT, else clear it */
8055d6ad960SSteven Rostedt (Red Hat) if (file->flags & EVENT_FILE_FL_SOFT_MODE)
8065d6ad960SSteven Rostedt (Red Hat) set_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags);
8073baa5e4cSTom Zanussi else
8085d6ad960SSteven Rostedt (Red Hat) clear_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags);
809fd994989SSteven Rostedt break;
810fd994989SSteven Rostedt case 1:
811417944c4SSteven Rostedt (Red Hat) /*
812417944c4SSteven Rostedt (Red Hat) * When soft_disable is set and enable is set, we want to
813417944c4SSteven Rostedt (Red Hat) * register the tracepoint for the event, but leave the event
814417944c4SSteven Rostedt (Red Hat) * as is. That means, if the event was already enabled, we do
815417944c4SSteven Rostedt (Red Hat) * nothing (but set SOFT_MODE). If the event is disabled, we
816417944c4SSteven Rostedt (Red Hat) * set SOFT_DISABLED before enabling the event tracepoint, so
817417944c4SSteven Rostedt (Red Hat) * it still seems to be disabled.
818417944c4SSteven Rostedt (Red Hat) */
819417944c4SSteven Rostedt (Red Hat) if (!soft_disable)
8205d6ad960SSteven Rostedt (Red Hat) clear_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags);
8211cf4c073SMasami Hiramatsu else {
8221cf4c073SMasami Hiramatsu if (atomic_inc_return(&file->sm_ref) > 1)
8231cf4c073SMasami Hiramatsu break;
8245d6ad960SSteven Rostedt (Red Hat) set_bit(EVENT_FILE_FL_SOFT_MODE_BIT, &file->flags);
825dea49978SZheng Yejian /* Enable use of trace_buffered_event */
826dea49978SZheng Yejian trace_buffered_event_enable();
8271cf4c073SMasami Hiramatsu }
828417944c4SSteven Rostedt (Red Hat)
8295d6ad960SSteven Rostedt (Red Hat) if (!(file->flags & EVENT_FILE_FL_ENABLED)) {
830d914ba37SJoel Fernandes bool cmd = false, tgid = false;
831417944c4SSteven Rostedt (Red Hat)
832417944c4SSteven Rostedt (Red Hat) /* Keep the event disabled, when going to SOFT_MODE. */
833417944c4SSteven Rostedt (Red Hat) if (soft_disable)
8345d6ad960SSteven Rostedt (Red Hat) set_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags);
835417944c4SSteven Rostedt (Red Hat)
836983f938aSSteven Rostedt (Red Hat) if (tr->trace_flags & TRACE_ITER_RECORD_CMD) {
837d914ba37SJoel Fernandes cmd = true;
838b11c53e1SZhaolei tracing_start_cmdline_record();
8395d6ad960SSteven Rostedt (Red Hat) set_bit(EVENT_FILE_FL_RECORDED_CMD_BIT, &file->flags);
840e870e9a1SLi Zefan }
841d914ba37SJoel Fernandes
842d914ba37SJoel Fernandes if (tr->trace_flags & TRACE_ITER_RECORD_TGID) {
843d914ba37SJoel Fernandes tgid = true;
844d914ba37SJoel Fernandes tracing_start_tgid_record();
845d914ba37SJoel Fernandes set_bit(EVENT_FILE_FL_RECORDED_TGID_BIT, &file->flags);
846d914ba37SJoel Fernandes }
847d914ba37SJoel Fernandes
848ae63b31eSSteven Rostedt ret = call->class->reg(call, TRACE_REG_REGISTER, file);
8493b8e4273SLi Zefan if (ret) {
850d914ba37SJoel Fernandes if (cmd)
8513b8e4273SLi Zefan tracing_stop_cmdline_record();
852d914ba37SJoel Fernandes if (tgid)
853d914ba37SJoel Fernandes tracing_stop_tgid_record();
8543b8e4273SLi Zefan pr_info("event trace: Could not enable event "
855687fcc4aSSteven Rostedt (Red Hat) "%s\n", trace_event_name(call));
8563b8e4273SLi Zefan break;
8573b8e4273SLi Zefan }
8585d6ad960SSteven Rostedt (Red Hat) set_bit(EVENT_FILE_FL_ENABLED_BIT, &file->flags);
859575380daSSteven Rostedt (Red Hat)
860575380daSSteven Rostedt (Red Hat) /* WAS_ENABLED gets set but never cleared. */
861065e63f9SSteven Rostedt (VMware) set_bit(EVENT_FILE_FL_WAS_ENABLED_BIT, &file->flags);
862fd994989SSteven Rostedt }
863fd994989SSteven Rostedt break;
864fd994989SSteven Rostedt }
8653b8e4273SLi Zefan
8663b8e4273SLi Zefan return ret;
867fd994989SSteven Rostedt }
868fd994989SSteven Rostedt
trace_event_enable_disable(struct trace_event_file * file,int enable,int soft_disable)8697f1d2f82SSteven Rostedt (Red Hat) int trace_event_enable_disable(struct trace_event_file *file,
87085f2b082STom Zanussi int enable, int soft_disable)
87185f2b082STom Zanussi {
87285f2b082STom Zanussi return __ftrace_event_enable_disable(file, enable, soft_disable);
87385f2b082STom Zanussi }
87485f2b082STom Zanussi
ftrace_event_enable_disable(struct trace_event_file * file,int enable)8757f1d2f82SSteven Rostedt (Red Hat) static int ftrace_event_enable_disable(struct trace_event_file *file,
876417944c4SSteven Rostedt (Red Hat) int enable)
877417944c4SSteven Rostedt (Red Hat) {
878417944c4SSteven Rostedt (Red Hat) return __ftrace_event_enable_disable(file, enable, 0);
879417944c4SSteven Rostedt (Red Hat) }
880417944c4SSteven Rostedt (Red Hat)
881a925df6fSSteven Rostedt #ifdef CONFIG_MODULES
882b355247dSSteven Rostedt struct event_mod_load {
883b355247dSSteven Rostedt struct list_head list;
884b355247dSSteven Rostedt char *module;
885b355247dSSteven Rostedt char *match;
886b355247dSSteven Rostedt char *system;
887b355247dSSteven Rostedt char *event;
888b355247dSSteven Rostedt };
889b355247dSSteven Rostedt
free_event_mod(struct event_mod_load * event_mod)890b355247dSSteven Rostedt static void free_event_mod(struct event_mod_load *event_mod)
891b355247dSSteven Rostedt {
892b355247dSSteven Rostedt list_del(&event_mod->list);
893b355247dSSteven Rostedt kfree(event_mod->module);
894b355247dSSteven Rostedt kfree(event_mod->match);
895b355247dSSteven Rostedt kfree(event_mod->system);
896b355247dSSteven Rostedt kfree(event_mod->event);
897b355247dSSteven Rostedt kfree(event_mod);
898b355247dSSteven Rostedt }
899b355247dSSteven Rostedt
clear_mod_events(struct trace_array * tr)900b355247dSSteven Rostedt static void clear_mod_events(struct trace_array *tr)
901b355247dSSteven Rostedt {
902b355247dSSteven Rostedt struct event_mod_load *event_mod, *n;
903b355247dSSteven Rostedt
904b355247dSSteven Rostedt list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
905b355247dSSteven Rostedt free_event_mod(event_mod);
906b355247dSSteven Rostedt }
907b355247dSSteven Rostedt }
908b355247dSSteven Rostedt
remove_cache_mod(struct trace_array * tr,const char * mod,const char * match,const char * system,const char * event)909b355247dSSteven Rostedt static int remove_cache_mod(struct trace_array *tr, const char *mod,
910b355247dSSteven Rostedt const char *match, const char *system, const char *event)
911b355247dSSteven Rostedt {
912b355247dSSteven Rostedt struct event_mod_load *event_mod, *n;
913b355247dSSteven Rostedt int ret = -EINVAL;
914b355247dSSteven Rostedt
915b355247dSSteven Rostedt list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
916b355247dSSteven Rostedt if (strcmp(event_mod->module, mod) != 0)
917b355247dSSteven Rostedt continue;
918b355247dSSteven Rostedt
919b355247dSSteven Rostedt if (match && strcmp(event_mod->match, match) != 0)
920b355247dSSteven Rostedt continue;
921b355247dSSteven Rostedt
922b355247dSSteven Rostedt if (system &&
923b355247dSSteven Rostedt (!event_mod->system || strcmp(event_mod->system, system) != 0))
924b355247dSSteven Rostedt continue;
925b355247dSSteven Rostedt
926b355247dSSteven Rostedt if (event &&
927b355247dSSteven Rostedt (!event_mod->event || strcmp(event_mod->event, event) != 0))
928b355247dSSteven Rostedt continue;
929b355247dSSteven Rostedt
930b355247dSSteven Rostedt free_event_mod(event_mod);
931b355247dSSteven Rostedt ret = 0;
932b355247dSSteven Rostedt }
933b355247dSSteven Rostedt
934b355247dSSteven Rostedt return ret;
935b355247dSSteven Rostedt }
936b355247dSSteven Rostedt
cache_mod(struct trace_array * tr,const char * mod,int set,const char * match,const char * system,const char * event)937b355247dSSteven Rostedt static int cache_mod(struct trace_array *tr, const char *mod, int set,
938b355247dSSteven Rostedt const char *match, const char *system, const char *event)
939b355247dSSteven Rostedt {
940b355247dSSteven Rostedt struct event_mod_load *event_mod;
941b355247dSSteven Rostedt
942b355247dSSteven Rostedt /* If the module exists, then this just failed to find an event */
943b355247dSSteven Rostedt if (module_exists(mod))
944b355247dSSteven Rostedt return -EINVAL;
945b355247dSSteven Rostedt
946b355247dSSteven Rostedt /* See if this is to remove a cached filter */
947b355247dSSteven Rostedt if (!set)
948b355247dSSteven Rostedt return remove_cache_mod(tr, mod, match, system, event);
949b355247dSSteven Rostedt
950b355247dSSteven Rostedt event_mod = kzalloc(sizeof(*event_mod), GFP_KERNEL);
951b355247dSSteven Rostedt if (!event_mod)
952b355247dSSteven Rostedt return -ENOMEM;
953b355247dSSteven Rostedt
954b355247dSSteven Rostedt INIT_LIST_HEAD(&event_mod->list);
955b355247dSSteven Rostedt event_mod->module = kstrdup(mod, GFP_KERNEL);
956b355247dSSteven Rostedt if (!event_mod->module)
957b355247dSSteven Rostedt goto out_free;
958b355247dSSteven Rostedt
959b355247dSSteven Rostedt if (match) {
960b355247dSSteven Rostedt event_mod->match = kstrdup(match, GFP_KERNEL);
961b355247dSSteven Rostedt if (!event_mod->match)
962b355247dSSteven Rostedt goto out_free;
963b355247dSSteven Rostedt }
964b355247dSSteven Rostedt
965b355247dSSteven Rostedt if (system) {
966b355247dSSteven Rostedt event_mod->system = kstrdup(system, GFP_KERNEL);
967b355247dSSteven Rostedt if (!event_mod->system)
968b355247dSSteven Rostedt goto out_free;
969b355247dSSteven Rostedt }
970b355247dSSteven Rostedt
971b355247dSSteven Rostedt if (event) {
972b355247dSSteven Rostedt event_mod->event = kstrdup(event, GFP_KERNEL);
973b355247dSSteven Rostedt if (!event_mod->event)
974b355247dSSteven Rostedt goto out_free;
975b355247dSSteven Rostedt }
976b355247dSSteven Rostedt
977b355247dSSteven Rostedt list_add(&event_mod->list, &tr->mod_events);
978b355247dSSteven Rostedt
979b355247dSSteven Rostedt return 0;
980b355247dSSteven Rostedt
981b355247dSSteven Rostedt out_free:
982b355247dSSteven Rostedt free_event_mod(event_mod);
983b355247dSSteven Rostedt
984b355247dSSteven Rostedt return -ENOMEM;
985b355247dSSteven Rostedt }
986b355247dSSteven Rostedt #else /* CONFIG_MODULES */
clear_mod_events(struct trace_array * tr)987b355247dSSteven Rostedt static inline void clear_mod_events(struct trace_array *tr) { }
cache_mod(struct trace_array * tr,const char * mod,int set,const char * match,const char * system,const char * event)988b355247dSSteven Rostedt static int cache_mod(struct trace_array *tr, const char *mod, int set,
989b355247dSSteven Rostedt const char *match, const char *system, const char *event)
990b355247dSSteven Rostedt {
991b355247dSSteven Rostedt return -EINVAL;
992b355247dSSteven Rostedt }
993b355247dSSteven Rostedt #endif
994b355247dSSteven Rostedt
ftrace_clear_events(struct trace_array * tr)995ae63b31eSSteven Rostedt static void ftrace_clear_events(struct trace_array *tr)
9960e907c99SZhaolei {
9977f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
9980e907c99SZhaolei
9990e907c99SZhaolei mutex_lock(&event_mutex);
1000ae63b31eSSteven Rostedt list_for_each_entry(file, &tr->events, list) {
1001ae63b31eSSteven Rostedt ftrace_event_enable_disable(file, 0);
10020e907c99SZhaolei }
1003b355247dSSteven Rostedt clear_mod_events(tr);
10040e907c99SZhaolei mutex_unlock(&event_mutex);
10050e907c99SZhaolei }
10060e907c99SZhaolei
1007c37775d5SSteven Rostedt static void
event_filter_pid_sched_process_exit(void * data,struct task_struct * task)1008c37775d5SSteven Rostedt event_filter_pid_sched_process_exit(void *data, struct task_struct *task)
1009c37775d5SSteven Rostedt {
1010c37775d5SSteven Rostedt struct trace_pid_list *pid_list;
1011c37775d5SSteven Rostedt struct trace_array *tr = data;
1012c37775d5SSteven Rostedt
1013da25a672SJoel Fernandes (Google) pid_list = rcu_dereference_raw(tr->filtered_pids);
10144e267db1SSteven Rostedt trace_filter_add_remove_task(pid_list, NULL, task);
101527683626SSteven Rostedt (VMware)
101627683626SSteven Rostedt (VMware) pid_list = rcu_dereference_raw(tr->filtered_no_pids);
101727683626SSteven Rostedt (VMware) trace_filter_add_remove_task(pid_list, NULL, task);
1018c37775d5SSteven Rostedt }
1019c37775d5SSteven Rostedt
1020c37775d5SSteven Rostedt static void
event_filter_pid_sched_process_fork(void * data,struct task_struct * self,struct task_struct * task)1021c37775d5SSteven Rostedt event_filter_pid_sched_process_fork(void *data,
1022c37775d5SSteven Rostedt struct task_struct *self,
1023c37775d5SSteven Rostedt struct task_struct *task)
1024c37775d5SSteven Rostedt {
1025c37775d5SSteven Rostedt struct trace_pid_list *pid_list;
1026c37775d5SSteven Rostedt struct trace_array *tr = data;
1027c37775d5SSteven Rostedt
1028c37775d5SSteven Rostedt pid_list = rcu_dereference_sched(tr->filtered_pids);
10294e267db1SSteven Rostedt trace_filter_add_remove_task(pid_list, self, task);
103027683626SSteven Rostedt (VMware)
103127683626SSteven Rostedt (VMware) pid_list = rcu_dereference_sched(tr->filtered_no_pids);
103227683626SSteven Rostedt (VMware) trace_filter_add_remove_task(pid_list, self, task);
1033c37775d5SSteven Rostedt }
1034c37775d5SSteven Rostedt
trace_event_follow_fork(struct trace_array * tr,bool enable)1035c37775d5SSteven Rostedt void trace_event_follow_fork(struct trace_array *tr, bool enable)
1036c37775d5SSteven Rostedt {
1037c37775d5SSteven Rostedt if (enable) {
1038c37775d5SSteven Rostedt register_trace_prio_sched_process_fork(event_filter_pid_sched_process_fork,
1039c37775d5SSteven Rostedt tr, INT_MIN);
1040afcab636SSteven Rostedt (VMware) register_trace_prio_sched_process_free(event_filter_pid_sched_process_exit,
1041c37775d5SSteven Rostedt tr, INT_MAX);
1042c37775d5SSteven Rostedt } else {
1043c37775d5SSteven Rostedt unregister_trace_sched_process_fork(event_filter_pid_sched_process_fork,
1044c37775d5SSteven Rostedt tr);
1045afcab636SSteven Rostedt (VMware) unregister_trace_sched_process_free(event_filter_pid_sched_process_exit,
1046c37775d5SSteven Rostedt tr);
1047c37775d5SSteven Rostedt }
10483fdaf80fSSteven Rostedt (Red Hat) }
10493fdaf80fSSteven Rostedt (Red Hat)
10503fdaf80fSSteven Rostedt (Red Hat) static void
event_filter_pid_sched_switch_probe_pre(void * data,bool preempt,struct task_struct * prev,struct task_struct * next,unsigned int prev_state)105122402cd0SLinus Torvalds event_filter_pid_sched_switch_probe_pre(void *data, bool preempt,
1052fa2c3254SValentin Schneider struct task_struct *prev,
10539c2136beSDelyan Kratunov struct task_struct *next,
10549c2136beSDelyan Kratunov unsigned int prev_state)
10553fdaf80fSSteven Rostedt (Red Hat) {
10563fdaf80fSSteven Rostedt (Red Hat) struct trace_array *tr = data;
105727683626SSteven Rostedt (VMware) struct trace_pid_list *no_pid_list;
10583fdaf80fSSteven Rostedt (Red Hat) struct trace_pid_list *pid_list;
105927683626SSteven Rostedt (VMware) bool ret;
10603fdaf80fSSteven Rostedt (Red Hat)
10613fdaf80fSSteven Rostedt (Red Hat) pid_list = rcu_dereference_sched(tr->filtered_pids);
106227683626SSteven Rostedt (VMware) no_pid_list = rcu_dereference_sched(tr->filtered_no_pids);
10633fdaf80fSSteven Rostedt (Red Hat)
106427683626SSteven Rostedt (VMware) /*
106527683626SSteven Rostedt (VMware) * Sched switch is funny, as we only want to ignore it
106627683626SSteven Rostedt (VMware) * in the notrace case if both prev and next should be ignored.
106727683626SSteven Rostedt (VMware) */
106827683626SSteven Rostedt (VMware) ret = trace_ignore_this_task(NULL, no_pid_list, prev) &&
106927683626SSteven Rostedt (VMware) trace_ignore_this_task(NULL, no_pid_list, next);
107027683626SSteven Rostedt (VMware)
107127683626SSteven Rostedt (VMware) this_cpu_write(tr->array_buffer.data->ignore_pid, ret ||
107227683626SSteven Rostedt (VMware) (trace_ignore_this_task(pid_list, NULL, prev) &&
107327683626SSteven Rostedt (VMware) trace_ignore_this_task(pid_list, NULL, next)));
10743fdaf80fSSteven Rostedt (Red Hat) }
10753fdaf80fSSteven Rostedt (Red Hat)
10763fdaf80fSSteven Rostedt (Red Hat) static void
event_filter_pid_sched_switch_probe_post(void * data,bool preempt,struct task_struct * prev,struct task_struct * next,unsigned int prev_state)107722402cd0SLinus Torvalds event_filter_pid_sched_switch_probe_post(void *data, bool preempt,
1078fa2c3254SValentin Schneider struct task_struct *prev,
10799c2136beSDelyan Kratunov struct task_struct *next,
10809c2136beSDelyan Kratunov unsigned int prev_state)
10813fdaf80fSSteven Rostedt (Red Hat) {
10823fdaf80fSSteven Rostedt (Red Hat) struct trace_array *tr = data;
108327683626SSteven Rostedt (VMware) struct trace_pid_list *no_pid_list;
10843fdaf80fSSteven Rostedt (Red Hat) struct trace_pid_list *pid_list;
10853fdaf80fSSteven Rostedt (Red Hat)
10863fdaf80fSSteven Rostedt (Red Hat) pid_list = rcu_dereference_sched(tr->filtered_pids);
108727683626SSteven Rostedt (VMware) no_pid_list = rcu_dereference_sched(tr->filtered_no_pids);
10883fdaf80fSSteven Rostedt (Red Hat)
10891c5eb448SSteven Rostedt (VMware) this_cpu_write(tr->array_buffer.data->ignore_pid,
109027683626SSteven Rostedt (VMware) trace_ignore_this_task(pid_list, no_pid_list, next));
10913fdaf80fSSteven Rostedt (Red Hat) }
10923fdaf80fSSteven Rostedt (Red Hat)
10933fdaf80fSSteven Rostedt (Red Hat) static void
event_filter_pid_sched_wakeup_probe_pre(void * data,struct task_struct * task)10943fdaf80fSSteven Rostedt (Red Hat) event_filter_pid_sched_wakeup_probe_pre(void *data, struct task_struct *task)
10953fdaf80fSSteven Rostedt (Red Hat) {
10963fdaf80fSSteven Rostedt (Red Hat) struct trace_array *tr = data;
109727683626SSteven Rostedt (VMware) struct trace_pid_list *no_pid_list;
10983fdaf80fSSteven Rostedt (Red Hat) struct trace_pid_list *pid_list;
10993fdaf80fSSteven Rostedt (Red Hat)
11003fdaf80fSSteven Rostedt (Red Hat) /* Nothing to do if we are already tracing */
11011c5eb448SSteven Rostedt (VMware) if (!this_cpu_read(tr->array_buffer.data->ignore_pid))
11023fdaf80fSSteven Rostedt (Red Hat) return;
11033fdaf80fSSteven Rostedt (Red Hat)
11043fdaf80fSSteven Rostedt (Red Hat) pid_list = rcu_dereference_sched(tr->filtered_pids);
110527683626SSteven Rostedt (VMware) no_pid_list = rcu_dereference_sched(tr->filtered_no_pids);
11063fdaf80fSSteven Rostedt (Red Hat)
11071c5eb448SSteven Rostedt (VMware) this_cpu_write(tr->array_buffer.data->ignore_pid,
110827683626SSteven Rostedt (VMware) trace_ignore_this_task(pid_list, no_pid_list, task));
11093fdaf80fSSteven Rostedt (Red Hat) }
11103fdaf80fSSteven Rostedt (Red Hat)
11113fdaf80fSSteven Rostedt (Red Hat) static void
event_filter_pid_sched_wakeup_probe_post(void * data,struct task_struct * task)11123fdaf80fSSteven Rostedt (Red Hat) event_filter_pid_sched_wakeup_probe_post(void *data, struct task_struct *task)
11133fdaf80fSSteven Rostedt (Red Hat) {
11143fdaf80fSSteven Rostedt (Red Hat) struct trace_array *tr = data;
111527683626SSteven Rostedt (VMware) struct trace_pid_list *no_pid_list;
11163fdaf80fSSteven Rostedt (Red Hat) struct trace_pid_list *pid_list;
11173fdaf80fSSteven Rostedt (Red Hat)
11183fdaf80fSSteven Rostedt (Red Hat) /* Nothing to do if we are not tracing */
11191c5eb448SSteven Rostedt (VMware) if (this_cpu_read(tr->array_buffer.data->ignore_pid))
11203fdaf80fSSteven Rostedt (Red Hat) return;
11213fdaf80fSSteven Rostedt (Red Hat)
11223fdaf80fSSteven Rostedt (Red Hat) pid_list = rcu_dereference_sched(tr->filtered_pids);
112327683626SSteven Rostedt (VMware) no_pid_list = rcu_dereference_sched(tr->filtered_no_pids);
11243fdaf80fSSteven Rostedt (Red Hat)
11253fdaf80fSSteven Rostedt (Red Hat) /* Set tracing if current is enabled */
11261c5eb448SSteven Rostedt (VMware) this_cpu_write(tr->array_buffer.data->ignore_pid,
112727683626SSteven Rostedt (VMware) trace_ignore_this_task(pid_list, no_pid_list, current));
11283fdaf80fSSteven Rostedt (Red Hat) }
11293fdaf80fSSteven Rostedt (Red Hat)
unregister_pid_events(struct trace_array * tr)113027683626SSteven Rostedt (VMware) static void unregister_pid_events(struct trace_array *tr)
113149090107SSteven Rostedt (Red Hat) {
11323fdaf80fSSteven Rostedt (Red Hat) unregister_trace_sched_switch(event_filter_pid_sched_switch_probe_pre, tr);
11333fdaf80fSSteven Rostedt (Red Hat) unregister_trace_sched_switch(event_filter_pid_sched_switch_probe_post, tr);
11343fdaf80fSSteven Rostedt (Red Hat)
11353fdaf80fSSteven Rostedt (Red Hat) unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre, tr);
11363fdaf80fSSteven Rostedt (Red Hat) unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_post, tr);
11373fdaf80fSSteven Rostedt (Red Hat)
11380f72e37eSSteven Rostedt (Red Hat) unregister_trace_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_pre, tr);
11390f72e37eSSteven Rostedt (Red Hat) unregister_trace_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_post, tr);
11400f72e37eSSteven Rostedt (Red Hat)
11410f72e37eSSteven Rostedt (Red Hat) unregister_trace_sched_waking(event_filter_pid_sched_wakeup_probe_pre, tr);
11420f72e37eSSteven Rostedt (Red Hat) unregister_trace_sched_waking(event_filter_pid_sched_wakeup_probe_post, tr);
114327683626SSteven Rostedt (VMware) }
114427683626SSteven Rostedt (VMware)
__ftrace_clear_event_pids(struct trace_array * tr,int type)114527683626SSteven Rostedt (VMware) static void __ftrace_clear_event_pids(struct trace_array *tr, int type)
114627683626SSteven Rostedt (VMware) {
114727683626SSteven Rostedt (VMware) struct trace_pid_list *pid_list;
114827683626SSteven Rostedt (VMware) struct trace_pid_list *no_pid_list;
114927683626SSteven Rostedt (VMware) struct trace_event_file *file;
115027683626SSteven Rostedt (VMware) int cpu;
115127683626SSteven Rostedt (VMware)
115227683626SSteven Rostedt (VMware) pid_list = rcu_dereference_protected(tr->filtered_pids,
115327683626SSteven Rostedt (VMware) lockdep_is_held(&event_mutex));
115427683626SSteven Rostedt (VMware) no_pid_list = rcu_dereference_protected(tr->filtered_no_pids,
115527683626SSteven Rostedt (VMware) lockdep_is_held(&event_mutex));
115627683626SSteven Rostedt (VMware)
115727683626SSteven Rostedt (VMware) /* Make sure there's something to do */
115827683626SSteven Rostedt (VMware) if (!pid_type_enabled(type, pid_list, no_pid_list))
115927683626SSteven Rostedt (VMware) return;
116027683626SSteven Rostedt (VMware)
116127683626SSteven Rostedt (VMware) if (!still_need_pid_events(type, pid_list, no_pid_list)) {
116227683626SSteven Rostedt (VMware) unregister_pid_events(tr);
11630f72e37eSSteven Rostedt (Red Hat)
11643fdaf80fSSteven Rostedt (Red Hat) list_for_each_entry(file, &tr->events, list) {
11653fdaf80fSSteven Rostedt (Red Hat) clear_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags);
11663fdaf80fSSteven Rostedt (Red Hat) }
11673fdaf80fSSteven Rostedt (Red Hat)
11683fdaf80fSSteven Rostedt (Red Hat) for_each_possible_cpu(cpu)
11691c5eb448SSteven Rostedt (VMware) per_cpu_ptr(tr->array_buffer.data, cpu)->ignore_pid = false;
117027683626SSteven Rostedt (VMware) }
11713fdaf80fSSteven Rostedt (Red Hat)
117227683626SSteven Rostedt (VMware) if (type & TRACE_PIDS)
117349090107SSteven Rostedt (Red Hat) rcu_assign_pointer(tr->filtered_pids, NULL);
117449090107SSteven Rostedt (Red Hat)
117527683626SSteven Rostedt (VMware) if (type & TRACE_NO_PIDS)
117627683626SSteven Rostedt (VMware) rcu_assign_pointer(tr->filtered_no_pids, NULL);
117727683626SSteven Rostedt (VMware)
117849090107SSteven Rostedt (Red Hat) /* Wait till all users are no longer using pid filtering */
1179e0a568dcSSteven Rostedt (VMware) tracepoint_synchronize_unregister();
118049090107SSteven Rostedt (Red Hat)
118127683626SSteven Rostedt (VMware) if ((type & TRACE_PIDS) && pid_list)
11826954e415SSteven Rostedt (VMware) trace_pid_list_free(pid_list);
118327683626SSteven Rostedt (VMware)
118427683626SSteven Rostedt (VMware) if ((type & TRACE_NO_PIDS) && no_pid_list)
11856954e415SSteven Rostedt (VMware) trace_pid_list_free(no_pid_list);
118649090107SSteven Rostedt (Red Hat) }
118749090107SSteven Rostedt (Red Hat)
ftrace_clear_event_pids(struct trace_array * tr,int type)118827683626SSteven Rostedt (VMware) static void ftrace_clear_event_pids(struct trace_array *tr, int type)
118949090107SSteven Rostedt (Red Hat) {
119049090107SSteven Rostedt (Red Hat) mutex_lock(&event_mutex);
119127683626SSteven Rostedt (VMware) __ftrace_clear_event_pids(tr, type);
119249090107SSteven Rostedt (Red Hat) mutex_unlock(&event_mutex);
119349090107SSteven Rostedt (Red Hat) }
119449090107SSteven Rostedt (Red Hat)
__put_system(struct event_subsystem * system)1195e9dbfae5SSteven Rostedt static void __put_system(struct event_subsystem *system)
1196e9dbfae5SSteven Rostedt {
1197e9dbfae5SSteven Rostedt struct event_filter *filter = system->filter;
1198e9dbfae5SSteven Rostedt
11996e94a780SSteven Rostedt WARN_ON_ONCE(system_refcount(system) == 0);
12006e94a780SSteven Rostedt if (system_refcount_dec(system))
1201e9dbfae5SSteven Rostedt return;
1202e9dbfae5SSteven Rostedt
1203ae63b31eSSteven Rostedt list_del(&system->list);
1204ae63b31eSSteven Rostedt
1205e9dbfae5SSteven Rostedt if (filter) {
1206e9dbfae5SSteven Rostedt kfree(filter->filter_string);
1207e9dbfae5SSteven Rostedt kfree(filter);
1208e9dbfae5SSteven Rostedt }
120979ac6ef5SRasmus Villemoes kfree_const(system->name);
1210e9dbfae5SSteven Rostedt kfree(system);
1211e9dbfae5SSteven Rostedt }
1212e9dbfae5SSteven Rostedt
__get_system(struct event_subsystem * system)1213e9dbfae5SSteven Rostedt static void __get_system(struct event_subsystem *system)
1214e9dbfae5SSteven Rostedt {
12156e94a780SSteven Rostedt WARN_ON_ONCE(system_refcount(system) == 0);
12166e94a780SSteven Rostedt system_refcount_inc(system);
1217e9dbfae5SSteven Rostedt }
1218e9dbfae5SSteven Rostedt
__get_system_dir(struct trace_subsystem_dir * dir)12197967b3e0SSteven Rostedt (Red Hat) static void __get_system_dir(struct trace_subsystem_dir *dir)
1220ae63b31eSSteven Rostedt {
1221ae63b31eSSteven Rostedt WARN_ON_ONCE(dir->ref_count == 0);
1222ae63b31eSSteven Rostedt dir->ref_count++;
1223ae63b31eSSteven Rostedt __get_system(dir->subsystem);
1224ae63b31eSSteven Rostedt }
1225ae63b31eSSteven Rostedt
__put_system_dir(struct trace_subsystem_dir * dir)12267967b3e0SSteven Rostedt (Red Hat) static void __put_system_dir(struct trace_subsystem_dir *dir)
1227ae63b31eSSteven Rostedt {
1228ae63b31eSSteven Rostedt WARN_ON_ONCE(dir->ref_count == 0);
1229ae63b31eSSteven Rostedt /* If the subsystem is about to be freed, the dir must be too */
12306e94a780SSteven Rostedt WARN_ON_ONCE(system_refcount(dir->subsystem) == 1 && dir->ref_count != 1);
1231ae63b31eSSteven Rostedt
1232ae63b31eSSteven Rostedt __put_system(dir->subsystem);
1233ae63b31eSSteven Rostedt if (!--dir->ref_count)
1234ae63b31eSSteven Rostedt kfree(dir);
1235ae63b31eSSteven Rostedt }
1236ae63b31eSSteven Rostedt
put_system(struct trace_subsystem_dir * dir)12377967b3e0SSteven Rostedt (Red Hat) static void put_system(struct trace_subsystem_dir *dir)
1238e9dbfae5SSteven Rostedt {
1239e9dbfae5SSteven Rostedt mutex_lock(&event_mutex);
1240ae63b31eSSteven Rostedt __put_system_dir(dir);
1241e9dbfae5SSteven Rostedt mutex_unlock(&event_mutex);
1242e9dbfae5SSteven Rostedt }
1243e9dbfae5SSteven Rostedt
remove_subsystem(struct trace_subsystem_dir * dir)12447967b3e0SSteven Rostedt (Red Hat) static void remove_subsystem(struct trace_subsystem_dir *dir)
1245f6a84bdcSOleg Nesterov {
1246f6a84bdcSOleg Nesterov if (!dir)
1247f6a84bdcSOleg Nesterov return;
1248f6a84bdcSOleg Nesterov
1249f6a84bdcSOleg Nesterov if (!--dir->nr_events) {
12505790b1fbSSteven Rostedt (Google) eventfs_remove_dir(dir->ei);
1251f6a84bdcSOleg Nesterov list_del(&dir->list);
1252f6a84bdcSOleg Nesterov __put_system_dir(dir);
1253f6a84bdcSOleg Nesterov }
1254f6a84bdcSOleg Nesterov }
1255f6a84bdcSOleg Nesterov
event_file_get(struct trace_event_file * file)1256bb32500fSSteven Rostedt (Google) void event_file_get(struct trace_event_file *file)
1257bb32500fSSteven Rostedt (Google) {
12586e2fdcefSSteven Rostedt refcount_inc(&file->ref);
1259bb32500fSSteven Rostedt (Google) }
1260bb32500fSSteven Rostedt (Google)
event_file_put(struct trace_event_file * file)1261bb32500fSSteven Rostedt (Google) void event_file_put(struct trace_event_file *file)
1262bb32500fSSteven Rostedt (Google) {
12636e2fdcefSSteven Rostedt if (WARN_ON_ONCE(!refcount_read(&file->ref))) {
1264bb32500fSSteven Rostedt (Google) if (file->flags & EVENT_FILE_FL_FREED)
1265bb32500fSSteven Rostedt (Google) kmem_cache_free(file_cachep, file);
1266bb32500fSSteven Rostedt (Google) return;
1267bb32500fSSteven Rostedt (Google) }
1268bb32500fSSteven Rostedt (Google)
12696e2fdcefSSteven Rostedt if (refcount_dec_and_test(&file->ref)) {
1270bb32500fSSteven Rostedt (Google) /* Count should only go to zero when it is freed */
1271bb32500fSSteven Rostedt (Google) if (WARN_ON_ONCE(!(file->flags & EVENT_FILE_FL_FREED)))
1272bb32500fSSteven Rostedt (Google) return;
1273bb32500fSSteven Rostedt (Google) kmem_cache_free(file_cachep, file);
1274bb32500fSSteven Rostedt (Google) }
1275bb32500fSSteven Rostedt (Google) }
1276bb32500fSSteven Rostedt (Google)
remove_event_file_dir(struct trace_event_file * file)12777f1d2f82SSteven Rostedt (Red Hat) static void remove_event_file_dir(struct trace_event_file *file)
1278f6a84bdcSOleg Nesterov {
12795790b1fbSSteven Rostedt (Google) eventfs_remove_dir(file->ei);
1280f6a84bdcSOleg Nesterov list_del(&file->list);
1281f6a84bdcSOleg Nesterov remove_subsystem(file->system);
12822448e349SOleg Nesterov free_event_filter(file->filter);
1283bb32500fSSteven Rostedt (Google) file->flags |= EVENT_FILE_FL_FREED;
1284bb32500fSSteven Rostedt (Google) event_file_put(file);
1285f6a84bdcSOleg Nesterov }
1286f6a84bdcSOleg Nesterov
12878f31bfe5SLi Zefan /*
12888f31bfe5SLi Zefan * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events.
12898f31bfe5SLi Zefan */
12902a6c24afSSteven Rostedt (Red Hat) static int
__ftrace_set_clr_event_nolock(struct trace_array * tr,const char * match,const char * sub,const char * event,int set,const char * mod)12912a6c24afSSteven Rostedt (Red Hat) __ftrace_set_clr_event_nolock(struct trace_array *tr, const char *match,
12924c86bc53SSteven Rostedt const char *sub, const char *event, int set,
12934c86bc53SSteven Rostedt const char *mod)
1294b77e38aaSSteven Rostedt {
12957f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
12962425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call;
12974c86bc53SSteven Rostedt char *module __free(kfree) = NULL;
1298de7b2973SMathieu Desnoyers const char *name;
129929f93943SSteven Rostedt int ret = -EINVAL;
1300989a0a3dSSteven Rostedt (Red Hat) int eret = 0;
1301b77e38aaSSteven Rostedt
13024c86bc53SSteven Rostedt if (mod) {
13034c86bc53SSteven Rostedt char *p;
13044c86bc53SSteven Rostedt
13054c86bc53SSteven Rostedt module = kstrdup(mod, GFP_KERNEL);
13064c86bc53SSteven Rostedt if (!module)
13074c86bc53SSteven Rostedt return -ENOMEM;
13084c86bc53SSteven Rostedt
13094c86bc53SSteven Rostedt /* Replace all '-' with '_' as that's what modules do */
13104c86bc53SSteven Rostedt for (p = strchr(module, '-'); p; p = strchr(p + 1, '-'))
13114c86bc53SSteven Rostedt *p = '_';
13124c86bc53SSteven Rostedt }
13134c86bc53SSteven Rostedt
1314ae63b31eSSteven Rostedt list_for_each_entry(file, &tr->events, list) {
1315ae63b31eSSteven Rostedt
1316ae63b31eSSteven Rostedt call = file->event_call;
13174c86bc53SSteven Rostedt
13184c86bc53SSteven Rostedt /* If a module is specified, skip events that are not that module */
13194c86bc53SSteven Rostedt if (module && (!call->module || strcmp(module_name(call->module), module)))
13204c86bc53SSteven Rostedt continue;
13214c86bc53SSteven Rostedt
1322687fcc4aSSteven Rostedt (Red Hat) name = trace_event_name(call);
1323b77e38aaSSteven Rostedt
1324de7b2973SMathieu Desnoyers if (!name || !call->class || !call->class->reg)
1325b77e38aaSSteven Rostedt continue;
13261473e441SSteven Rostedt
13279b63776fSSteven Rostedt if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
13289b63776fSSteven Rostedt continue;
13299b63776fSSteven Rostedt
1330b628b3e6SSteven Rostedt if (match &&
1331de7b2973SMathieu Desnoyers strcmp(match, name) != 0 &&
13328f082018SSteven Rostedt strcmp(match, call->class->system) != 0)
1333b628b3e6SSteven Rostedt continue;
1334b628b3e6SSteven Rostedt
13358f082018SSteven Rostedt if (sub && strcmp(sub, call->class->system) != 0)
1336b628b3e6SSteven Rostedt continue;
1337b628b3e6SSteven Rostedt
1338de7b2973SMathieu Desnoyers if (event && strcmp(event, name) != 0)
13391473e441SSteven Rostedt continue;
1340b77e38aaSSteven Rostedt
1341989a0a3dSSteven Rostedt (Red Hat) ret = ftrace_event_enable_disable(file, set);
1342fd994989SSteven Rostedt
1343989a0a3dSSteven Rostedt (Red Hat) /*
1344989a0a3dSSteven Rostedt (Red Hat) * Save the first error and return that. Some events
1345989a0a3dSSteven Rostedt (Red Hat) * may still have been enabled, but let the user
1346989a0a3dSSteven Rostedt (Red Hat) * know that something went wrong.
1347989a0a3dSSteven Rostedt (Red Hat) */
1348989a0a3dSSteven Rostedt (Red Hat) if (ret && !eret)
1349989a0a3dSSteven Rostedt (Red Hat) eret = ret;
1350989a0a3dSSteven Rostedt (Red Hat)
1351989a0a3dSSteven Rostedt (Red Hat) ret = eret;
1352b77e38aaSSteven Rostedt }
13532a6c24afSSteven Rostedt (Red Hat)
1354b355247dSSteven Rostedt /*
1355b355247dSSteven Rostedt * If this is a module setting and nothing was found,
1356b355247dSSteven Rostedt * check if the module was loaded. If it wasn't cache it.
1357b355247dSSteven Rostedt */
1358b355247dSSteven Rostedt if (module && ret == -EINVAL && !eret)
1359b355247dSSteven Rostedt ret = cache_mod(tr, module, set, match, sub, event);
1360b355247dSSteven Rostedt
13612a6c24afSSteven Rostedt (Red Hat) return ret;
13622a6c24afSSteven Rostedt (Red Hat) }
13632a6c24afSSteven Rostedt (Red Hat)
__ftrace_set_clr_event(struct trace_array * tr,const char * match,const char * sub,const char * event,int set,const char * mod)13642a6c24afSSteven Rostedt (Red Hat) static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
13654c86bc53SSteven Rostedt const char *sub, const char *event, int set,
13664c86bc53SSteven Rostedt const char *mod)
13672a6c24afSSteven Rostedt (Red Hat) {
13682a6c24afSSteven Rostedt (Red Hat) int ret;
13692a6c24afSSteven Rostedt (Red Hat)
13702a6c24afSSteven Rostedt (Red Hat) mutex_lock(&event_mutex);
13714c86bc53SSteven Rostedt ret = __ftrace_set_clr_event_nolock(tr, match, sub, event, set, mod);
137211a241a3SSteven Rostedt mutex_unlock(&event_mutex);
137311a241a3SSteven Rostedt
1374b628b3e6SSteven Rostedt return ret;
1375b77e38aaSSteven Rostedt }
1376b77e38aaSSteven Rostedt
ftrace_set_clr_event(struct trace_array * tr,char * buf,int set)1377595a438cSDenis Efremov int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set)
13788f31bfe5SLi Zefan {
13794c86bc53SSteven Rostedt char *event = NULL, *sub = NULL, *match, *mod;
138084fce9dbSJoonsoo Kim int ret;
13818f31bfe5SLi Zefan
1382953ae45aSDivya Indi if (!tr)
1383953ae45aSDivya Indi return -ENOENT;
13844c86bc53SSteven Rostedt
13854c86bc53SSteven Rostedt /* Modules events can be appened with :mod:<module> */
13864c86bc53SSteven Rostedt mod = strstr(buf, ":mod:");
13874c86bc53SSteven Rostedt if (mod) {
13884c86bc53SSteven Rostedt *mod = '\0';
13894c86bc53SSteven Rostedt /* move to the module name */
13904c86bc53SSteven Rostedt mod += 5;
13914c86bc53SSteven Rostedt }
13924c86bc53SSteven Rostedt
13938f31bfe5SLi Zefan /*
13948f31bfe5SLi Zefan * The buf format can be <subsystem>:<event-name>
13958f31bfe5SLi Zefan * *:<event-name> means any event by that name.
13968f31bfe5SLi Zefan * :<event-name> is the same.
13978f31bfe5SLi Zefan *
13988f31bfe5SLi Zefan * <subsystem>:* means all events in that subsystem
13998f31bfe5SLi Zefan * <subsystem>: means the same.
14008f31bfe5SLi Zefan *
14018f31bfe5SLi Zefan * <name> (no ':') means all events in a subsystem with
14028f31bfe5SLi Zefan * the name <name> or any event that matches <name>
14038f31bfe5SLi Zefan */
14048f31bfe5SLi Zefan
14058f31bfe5SLi Zefan match = strsep(&buf, ":");
14068f31bfe5SLi Zefan if (buf) {
14078f31bfe5SLi Zefan sub = match;
14088f31bfe5SLi Zefan event = buf;
14098f31bfe5SLi Zefan match = NULL;
14108f31bfe5SLi Zefan
14118f31bfe5SLi Zefan if (!strlen(sub) || strcmp(sub, "*") == 0)
14128f31bfe5SLi Zefan sub = NULL;
14138f31bfe5SLi Zefan if (!strlen(event) || strcmp(event, "*") == 0)
14148f31bfe5SLi Zefan event = NULL;
14154c86bc53SSteven Rostedt } else if (mod) {
14164c86bc53SSteven Rostedt /* Allow wildcard for no length or star */
14174c86bc53SSteven Rostedt if (!strlen(match) || strcmp(match, "*") == 0)
14184c86bc53SSteven Rostedt match = NULL;
14198f31bfe5SLi Zefan }
14208f31bfe5SLi Zefan
14214c86bc53SSteven Rostedt ret = __ftrace_set_clr_event(tr, match, sub, event, set, mod);
142284fce9dbSJoonsoo Kim
142384fce9dbSJoonsoo Kim /* Put back the colon to allow this to be called again */
142484fce9dbSJoonsoo Kim if (buf)
142584fce9dbSJoonsoo Kim *(buf - 1) = ':';
142684fce9dbSJoonsoo Kim
142784fce9dbSJoonsoo Kim return ret;
14288f31bfe5SLi Zefan }
14298f31bfe5SLi Zefan
14304671c794SSteven Rostedt /**
14314671c794SSteven Rostedt * trace_set_clr_event - enable or disable an event
14324671c794SSteven Rostedt * @system: system name to match (NULL for any system)
14334671c794SSteven Rostedt * @event: event name to match (NULL for all events, within system)
14344671c794SSteven Rostedt * @set: 1 to enable, 0 to disable
14354671c794SSteven Rostedt *
14364671c794SSteven Rostedt * This is a way for other parts of the kernel to enable or disable
14374671c794SSteven Rostedt * event recording.
14384671c794SSteven Rostedt *
14394671c794SSteven Rostedt * Returns 0 on success, -EINVAL if the parameters do not match any
14404671c794SSteven Rostedt * registered events.
14414671c794SSteven Rostedt */
trace_set_clr_event(const char * system,const char * event,int set)14424671c794SSteven Rostedt int trace_set_clr_event(const char *system, const char *event, int set)
14434671c794SSteven Rostedt {
1444ae63b31eSSteven Rostedt struct trace_array *tr = top_trace_array();
1445ae63b31eSSteven Rostedt
1446dc81e5e3SYoshihiro YUNOMAE if (!tr)
1447dc81e5e3SYoshihiro YUNOMAE return -ENODEV;
1448dc81e5e3SYoshihiro YUNOMAE
14494c86bc53SSteven Rostedt return __ftrace_set_clr_event(tr, NULL, system, event, set, NULL);
14504671c794SSteven Rostedt }
145156355b83SYuanhan Liu EXPORT_SYMBOL_GPL(trace_set_clr_event);
14524671c794SSteven Rostedt
145328879787SDivya Indi /**
145428879787SDivya Indi * trace_array_set_clr_event - enable or disable an event for a trace array.
145528879787SDivya Indi * @tr: concerned trace array.
145628879787SDivya Indi * @system: system name to match (NULL for any system)
145728879787SDivya Indi * @event: event name to match (NULL for all events, within system)
145828879787SDivya Indi * @enable: true to enable, false to disable
145928879787SDivya Indi *
146028879787SDivya Indi * This is a way for other parts of the kernel to enable or disable
146128879787SDivya Indi * event recording.
146228879787SDivya Indi *
146328879787SDivya Indi * Returns 0 on success, -EINVAL if the parameters do not match any
146428879787SDivya Indi * registered events.
146528879787SDivya Indi */
trace_array_set_clr_event(struct trace_array * tr,const char * system,const char * event,bool enable)146628879787SDivya Indi int trace_array_set_clr_event(struct trace_array *tr, const char *system,
146728879787SDivya Indi const char *event, bool enable)
146828879787SDivya Indi {
146928879787SDivya Indi int set;
147028879787SDivya Indi
147128879787SDivya Indi if (!tr)
147228879787SDivya Indi return -ENOENT;
147328879787SDivya Indi
147428879787SDivya Indi set = (enable == true) ? 1 : 0;
14754c86bc53SSteven Rostedt return __ftrace_set_clr_event(tr, NULL, system, event, set, NULL);
147628879787SDivya Indi }
147728879787SDivya Indi EXPORT_SYMBOL_GPL(trace_array_set_clr_event);
147828879787SDivya Indi
1479b77e38aaSSteven Rostedt /* 128 should be much more than enough */
1480b77e38aaSSteven Rostedt #define EVENT_BUF_SIZE 127
1481b77e38aaSSteven Rostedt
1482b77e38aaSSteven Rostedt static ssize_t
ftrace_event_write(struct file * file,const char __user * ubuf,size_t cnt,loff_t * ppos)1483b77e38aaSSteven Rostedt ftrace_event_write(struct file *file, const char __user *ubuf,
1484b77e38aaSSteven Rostedt size_t cnt, loff_t *ppos)
1485b77e38aaSSteven Rostedt {
148648966364S[email protected] struct trace_parser parser;
1487ae63b31eSSteven Rostedt struct seq_file *m = file->private_data;
1488ae63b31eSSteven Rostedt struct trace_array *tr = m->private;
14894ba7978eSLi Zefan ssize_t read, ret;
1490b77e38aaSSteven Rostedt
14914ba7978eSLi Zefan if (!cnt)
1492b77e38aaSSteven Rostedt return 0;
1493b77e38aaSSteven Rostedt
1494a1f157c7SZheng Yejian ret = tracing_update_buffers(tr);
14951852fcceSSteven Rostedt if (ret < 0)
14961852fcceSSteven Rostedt return ret;
14971852fcceSSteven Rostedt
149848966364S[email protected] if (trace_parser_get_init(&parser, EVENT_BUF_SIZE + 1))
1499b77e38aaSSteven Rostedt return -ENOMEM;
1500b77e38aaSSteven Rostedt
150148966364S[email protected] read = trace_get_user(&parser, ubuf, cnt, ppos);
1502b77e38aaSSteven Rostedt
15034ba7978eSLi Zefan if (read >= 0 && trace_parser_loaded((&parser))) {
150448966364S[email protected] int set = 1;
150548966364S[email protected]
150648966364S[email protected] if (*parser.buffer == '!')
1507b77e38aaSSteven Rostedt set = 0;
1508b77e38aaSSteven Rostedt
1509ae63b31eSSteven Rostedt ret = ftrace_set_clr_event(tr, parser.buffer + !set, set);
1510b77e38aaSSteven Rostedt if (ret)
151148966364S[email protected] goto out_put;
1512b77e38aaSSteven Rostedt }
1513b77e38aaSSteven Rostedt
1514b77e38aaSSteven Rostedt ret = read;
1515b77e38aaSSteven Rostedt
151648966364S[email protected] out_put:
151748966364S[email protected] trace_parser_put(&parser);
1518b77e38aaSSteven Rostedt
1519b77e38aaSSteven Rostedt return ret;
1520b77e38aaSSteven Rostedt }
1521b77e38aaSSteven Rostedt
1522b77e38aaSSteven Rostedt static void *
t_next(struct seq_file * m,void * v,loff_t * pos)1523b77e38aaSSteven Rostedt t_next(struct seq_file *m, void *v, loff_t *pos)
1524b77e38aaSSteven Rostedt {
15257f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file = v;
15262425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call;
1527ae63b31eSSteven Rostedt struct trace_array *tr = m->private;
1528b77e38aaSSteven Rostedt
1529b77e38aaSSteven Rostedt (*pos)++;
1530b77e38aaSSteven Rostedt
1531ae63b31eSSteven Rostedt list_for_each_entry_continue(file, &tr->events, list) {
1532ae63b31eSSteven Rostedt call = file->event_call;
153340e26815SSteven Rostedt /*
153440e26815SSteven Rostedt * The ftrace subsystem is for showing formats only.
153540e26815SSteven Rostedt * They can not be enabled or disabled via the event files.
153640e26815SSteven Rostedt */
1537d045437aSSteven Rostedt (Red Hat) if (call->class && call->class->reg &&
1538d045437aSSteven Rostedt (Red Hat) !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
1539ae63b31eSSteven Rostedt return file;
154040e26815SSteven Rostedt }
154140e26815SSteven Rostedt
154230bd39cdSLi Zefan return NULL;
1543b77e38aaSSteven Rostedt }
1544b77e38aaSSteven Rostedt
t_start(struct seq_file * m,loff_t * pos)1545b77e38aaSSteven Rostedt static void *t_start(struct seq_file *m, loff_t *pos)
1546b77e38aaSSteven Rostedt {
15477f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
1548ae63b31eSSteven Rostedt struct trace_array *tr = m->private;
1549e1c7e2a6SLi Zefan loff_t l;
1550e1c7e2a6SLi Zefan
155120c8928aSLi Zefan mutex_lock(&event_mutex);
1552e1c7e2a6SLi Zefan
15537f1d2f82SSteven Rostedt (Red Hat) file = list_entry(&tr->events, struct trace_event_file, list);
1554e1c7e2a6SLi Zefan for (l = 0; l <= *pos; ) {
1555ae63b31eSSteven Rostedt file = t_next(m, file, &l);
1556ae63b31eSSteven Rostedt if (!file)
1557e1c7e2a6SLi Zefan break;
1558e1c7e2a6SLi Zefan }
1559ae63b31eSSteven Rostedt return file;
1560b77e38aaSSteven Rostedt }
1561b77e38aaSSteven Rostedt
1562b355247dSSteven Rostedt enum set_event_iter_type {
1563b355247dSSteven Rostedt SET_EVENT_FILE,
1564b355247dSSteven Rostedt SET_EVENT_MOD,
1565b355247dSSteven Rostedt };
1566b355247dSSteven Rostedt
1567b355247dSSteven Rostedt struct set_event_iter {
1568b355247dSSteven Rostedt enum set_event_iter_type type;
1569b355247dSSteven Rostedt union {
1570b355247dSSteven Rostedt struct trace_event_file *file;
1571b355247dSSteven Rostedt struct event_mod_load *event_mod;
1572b355247dSSteven Rostedt };
1573b355247dSSteven Rostedt };
1574b355247dSSteven Rostedt
1575b77e38aaSSteven Rostedt static void *
s_next(struct seq_file * m,void * v,loff_t * pos)1576b77e38aaSSteven Rostedt s_next(struct seq_file *m, void *v, loff_t *pos)
1577b77e38aaSSteven Rostedt {
1578b355247dSSteven Rostedt struct set_event_iter *iter = v;
1579b355247dSSteven Rostedt struct trace_event_file *file;
1580ae63b31eSSteven Rostedt struct trace_array *tr = m->private;
1581b77e38aaSSteven Rostedt
1582b77e38aaSSteven Rostedt (*pos)++;
1583b77e38aaSSteven Rostedt
1584b355247dSSteven Rostedt if (iter->type == SET_EVENT_FILE) {
1585b355247dSSteven Rostedt file = iter->file;
1586ae63b31eSSteven Rostedt list_for_each_entry_continue(file, &tr->events, list) {
1587b355247dSSteven Rostedt if (file->flags & EVENT_FILE_FL_ENABLED) {
1588b355247dSSteven Rostedt iter->file = file;
1589b355247dSSteven Rostedt return iter;
1590b77e38aaSSteven Rostedt }
1591b355247dSSteven Rostedt }
1592b355247dSSteven Rostedt #ifdef CONFIG_MODULES
1593b355247dSSteven Rostedt iter->type = SET_EVENT_MOD;
1594b355247dSSteven Rostedt iter->event_mod = list_entry(&tr->mod_events, struct event_mod_load, list);
1595b355247dSSteven Rostedt #endif
1596b355247dSSteven Rostedt }
1597b355247dSSteven Rostedt
1598b355247dSSteven Rostedt #ifdef CONFIG_MODULES
1599b355247dSSteven Rostedt list_for_each_entry_continue(iter->event_mod, &tr->mod_events, list)
1600b355247dSSteven Rostedt return iter;
1601b355247dSSteven Rostedt #endif
1602b77e38aaSSteven Rostedt
16032fa6a013SAdrian Huang /*
16042fa6a013SAdrian Huang * The iter is allocated in s_start() and passed via the 'v'
16052fa6a013SAdrian Huang * parameter. To stop the iterator, NULL must be returned. But
16062fa6a013SAdrian Huang * the return value is what the 'v' parameter in s_stop() receives
16072fa6a013SAdrian Huang * and frees. Free iter here as it will no longer be used.
16082fa6a013SAdrian Huang */
16092fa6a013SAdrian Huang kfree(iter);
161030bd39cdSLi Zefan return NULL;
1611b77e38aaSSteven Rostedt }
1612b77e38aaSSteven Rostedt
s_start(struct seq_file * m,loff_t * pos)1613b77e38aaSSteven Rostedt static void *s_start(struct seq_file *m, loff_t *pos)
1614b77e38aaSSteven Rostedt {
1615ae63b31eSSteven Rostedt struct trace_array *tr = m->private;
1616b355247dSSteven Rostedt struct set_event_iter *iter;
1617e1c7e2a6SLi Zefan loff_t l;
1618e1c7e2a6SLi Zefan
1619f95ee542SSteven Rostedt iter = kzalloc(sizeof(*iter), GFP_KERNEL);
1620b355247dSSteven Rostedt if (!iter)
1621b355247dSSteven Rostedt return NULL;
1622b355247dSSteven Rostedt
162320c8928aSLi Zefan mutex_lock(&event_mutex);
1624e1c7e2a6SLi Zefan
1625b355247dSSteven Rostedt iter->type = SET_EVENT_FILE;
1626b355247dSSteven Rostedt iter->file = list_entry(&tr->events, struct trace_event_file, list);
1627b355247dSSteven Rostedt
1628e1c7e2a6SLi Zefan for (l = 0; l <= *pos; ) {
1629b355247dSSteven Rostedt iter = s_next(m, iter, &l);
1630b355247dSSteven Rostedt if (!iter)
1631e1c7e2a6SLi Zefan break;
1632e1c7e2a6SLi Zefan }
1633b355247dSSteven Rostedt return iter;
1634b77e38aaSSteven Rostedt }
1635b77e38aaSSteven Rostedt
t_show(struct seq_file * m,void * v)1636b77e38aaSSteven Rostedt static int t_show(struct seq_file *m, void *v)
1637b77e38aaSSteven Rostedt {
16387f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file = v;
16392425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call = file->event_call;
1640b77e38aaSSteven Rostedt
16418f082018SSteven Rostedt if (strcmp(call->class->system, TRACE_SYSTEM) != 0)
16428f082018SSteven Rostedt seq_printf(m, "%s:", call->class->system);
1643687fcc4aSSteven Rostedt (Red Hat) seq_printf(m, "%s\n", trace_event_name(call));
1644b77e38aaSSteven Rostedt
1645b77e38aaSSteven Rostedt return 0;
1646b77e38aaSSteven Rostedt }
1647b77e38aaSSteven Rostedt
t_stop(struct seq_file * m,void * p)1648b77e38aaSSteven Rostedt static void t_stop(struct seq_file *m, void *p)
1649b77e38aaSSteven Rostedt {
165020c8928aSLi Zefan mutex_unlock(&event_mutex);
1651b77e38aaSSteven Rostedt }
1652b77e38aaSSteven Rostedt
1653b355247dSSteven Rostedt #ifdef CONFIG_MODULES
s_show(struct seq_file * m,void * v)1654b355247dSSteven Rostedt static int s_show(struct seq_file *m, void *v)
1655b355247dSSteven Rostedt {
1656b355247dSSteven Rostedt struct set_event_iter *iter = v;
1657b355247dSSteven Rostedt const char *system;
1658b355247dSSteven Rostedt const char *event;
1659b355247dSSteven Rostedt
1660b355247dSSteven Rostedt if (iter->type == SET_EVENT_FILE)
1661b355247dSSteven Rostedt return t_show(m, iter->file);
1662b355247dSSteven Rostedt
1663b355247dSSteven Rostedt /* When match is set, system and event are not */
1664b355247dSSteven Rostedt if (iter->event_mod->match) {
16658f21943eSSteven Rostedt seq_printf(m, "%s:mod:%s\n", iter->event_mod->match,
1666b355247dSSteven Rostedt iter->event_mod->module);
1667b355247dSSteven Rostedt return 0;
1668b355247dSSteven Rostedt }
1669b355247dSSteven Rostedt
1670b355247dSSteven Rostedt system = iter->event_mod->system ? : "*";
1671b355247dSSteven Rostedt event = iter->event_mod->event ? : "*";
1672b355247dSSteven Rostedt
1673b355247dSSteven Rostedt seq_printf(m, "%s:%s:mod:%s\n", system, event, iter->event_mod->module);
1674b355247dSSteven Rostedt
1675b355247dSSteven Rostedt return 0;
1676b355247dSSteven Rostedt }
1677b355247dSSteven Rostedt #else /* CONFIG_MODULES */
s_show(struct seq_file * m,void * v)1678b355247dSSteven Rostedt static int s_show(struct seq_file *m, void *v)
1679b355247dSSteven Rostedt {
1680b355247dSSteven Rostedt struct set_event_iter *iter = v;
1681b355247dSSteven Rostedt
1682b355247dSSteven Rostedt return t_show(m, iter->file);
1683b355247dSSteven Rostedt }
1684b355247dSSteven Rostedt #endif
1685b355247dSSteven Rostedt
s_stop(struct seq_file * m,void * v)16862fa6a013SAdrian Huang static void s_stop(struct seq_file *m, void *v)
1687b355247dSSteven Rostedt {
16882fa6a013SAdrian Huang kfree(v);
1689b355247dSSteven Rostedt t_stop(m, NULL);
1690b355247dSSteven Rostedt }
1691b355247dSSteven Rostedt
1692f4d34a87SSteven Rostedt static void *
__next(struct seq_file * m,void * v,loff_t * pos,int type)169327683626SSteven Rostedt (VMware) __next(struct seq_file *m, void *v, loff_t *pos, int type)
1694f4d34a87SSteven Rostedt {
1695f4d34a87SSteven Rostedt struct trace_array *tr = m->private;
169627683626SSteven Rostedt (VMware) struct trace_pid_list *pid_list;
169727683626SSteven Rostedt (VMware)
169827683626SSteven Rostedt (VMware) if (type == TRACE_PIDS)
169927683626SSteven Rostedt (VMware) pid_list = rcu_dereference_sched(tr->filtered_pids);
170027683626SSteven Rostedt (VMware) else
170127683626SSteven Rostedt (VMware) pid_list = rcu_dereference_sched(tr->filtered_no_pids);
1702f4d34a87SSteven Rostedt
17035cc8976bSSteven Rostedt (Red Hat) return trace_pid_next(pid_list, v, pos);
1704f4d34a87SSteven Rostedt }
1705f4d34a87SSteven Rostedt
170627683626SSteven Rostedt (VMware) static void *
p_next(struct seq_file * m,void * v,loff_t * pos)170727683626SSteven Rostedt (VMware) p_next(struct seq_file *m, void *v, loff_t *pos)
170827683626SSteven Rostedt (VMware) {
170927683626SSteven Rostedt (VMware) return __next(m, v, pos, TRACE_PIDS);
171027683626SSteven Rostedt (VMware) }
171127683626SSteven Rostedt (VMware)
171227683626SSteven Rostedt (VMware) static void *
np_next(struct seq_file * m,void * v,loff_t * pos)171327683626SSteven Rostedt (VMware) np_next(struct seq_file *m, void *v, loff_t *pos)
171427683626SSteven Rostedt (VMware) {
171527683626SSteven Rostedt (VMware) return __next(m, v, pos, TRACE_NO_PIDS);
171627683626SSteven Rostedt (VMware) }
171727683626SSteven Rostedt (VMware)
__start(struct seq_file * m,loff_t * pos,int type)171827683626SSteven Rostedt (VMware) static void *__start(struct seq_file *m, loff_t *pos, int type)
1719fb662288SSteven Rostedt (Red Hat) __acquires(RCU)
172049090107SSteven Rostedt (Red Hat) {
172149090107SSteven Rostedt (Red Hat) struct trace_pid_list *pid_list;
172249090107SSteven Rostedt (Red Hat) struct trace_array *tr = m->private;
172349090107SSteven Rostedt (Red Hat)
172449090107SSteven Rostedt (Red Hat) /*
172549090107SSteven Rostedt (Red Hat) * Grab the mutex, to keep calls to p_next() having the same
172649090107SSteven Rostedt (Red Hat) * tr->filtered_pids as p_start() has.
172749090107SSteven Rostedt (Red Hat) * If we just passed the tr->filtered_pids around, then RCU would
172849090107SSteven Rostedt (Red Hat) * have been enough, but doing that makes things more complex.
172949090107SSteven Rostedt (Red Hat) */
173049090107SSteven Rostedt (Red Hat) mutex_lock(&event_mutex);
173149090107SSteven Rostedt (Red Hat) rcu_read_lock_sched();
173249090107SSteven Rostedt (Red Hat)
173327683626SSteven Rostedt (VMware) if (type == TRACE_PIDS)
173449090107SSteven Rostedt (Red Hat) pid_list = rcu_dereference_sched(tr->filtered_pids);
173527683626SSteven Rostedt (VMware) else
173627683626SSteven Rostedt (VMware) pid_list = rcu_dereference_sched(tr->filtered_no_pids);
173749090107SSteven Rostedt (Red Hat)
1738f4d34a87SSteven Rostedt if (!pid_list)
173949090107SSteven Rostedt (Red Hat) return NULL;
174049090107SSteven Rostedt (Red Hat)
17415cc8976bSSteven Rostedt (Red Hat) return trace_pid_start(pid_list, pos);
174249090107SSteven Rostedt (Red Hat) }
174349090107SSteven Rostedt (Red Hat)
p_start(struct seq_file * m,loff_t * pos)174427683626SSteven Rostedt (VMware) static void *p_start(struct seq_file *m, loff_t *pos)
174527683626SSteven Rostedt (VMware) __acquires(RCU)
174627683626SSteven Rostedt (VMware) {
174727683626SSteven Rostedt (VMware) return __start(m, pos, TRACE_PIDS);
174827683626SSteven Rostedt (VMware) }
174927683626SSteven Rostedt (VMware)
np_start(struct seq_file * m,loff_t * pos)175027683626SSteven Rostedt (VMware) static void *np_start(struct seq_file *m, loff_t *pos)
175127683626SSteven Rostedt (VMware) __acquires(RCU)
175227683626SSteven Rostedt (VMware) {
175327683626SSteven Rostedt (VMware) return __start(m, pos, TRACE_NO_PIDS);
175427683626SSteven Rostedt (VMware) }
175527683626SSteven Rostedt (VMware)
p_stop(struct seq_file * m,void * p)175649090107SSteven Rostedt (Red Hat) static void p_stop(struct seq_file *m, void *p)
1757fb662288SSteven Rostedt (Red Hat) __releases(RCU)
175849090107SSteven Rostedt (Red Hat) {
175949090107SSteven Rostedt (Red Hat) rcu_read_unlock_sched();
176049090107SSteven Rostedt (Red Hat) mutex_unlock(&event_mutex);
176149090107SSteven Rostedt (Red Hat) }
176249090107SSteven Rostedt (Red Hat)
17631473e441SSteven Rostedt static ssize_t
event_enable_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)17641473e441SSteven Rostedt event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
17651473e441SSteven Rostedt loff_t *ppos)
17661473e441SSteven Rostedt {
17677f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
1768bc6f6b08SOleg Nesterov unsigned long flags;
1769a4390596STom Zanussi char buf[4] = "0";
17701473e441SSteven Rostedt
1771bc6f6b08SOleg Nesterov mutex_lock(&event_mutex);
1772b1560408SSteven Rostedt file = event_file_file(filp);
1773bc6f6b08SOleg Nesterov if (likely(file))
1774bc6f6b08SOleg Nesterov flags = file->flags;
1775bc6f6b08SOleg Nesterov mutex_unlock(&event_mutex);
1776bc6f6b08SOleg Nesterov
1777b1560408SSteven Rostedt if (!file)
1778bc6f6b08SOleg Nesterov return -ENODEV;
1779bc6f6b08SOleg Nesterov
17805d6ad960SSteven Rostedt (Red Hat) if (flags & EVENT_FILE_FL_ENABLED &&
17815d6ad960SSteven Rostedt (Red Hat) !(flags & EVENT_FILE_FL_SOFT_DISABLED))
1782a4390596STom Zanussi strcpy(buf, "1");
1783a4390596STom Zanussi
17845d6ad960SSteven Rostedt (Red Hat) if (flags & EVENT_FILE_FL_SOFT_DISABLED ||
17855d6ad960SSteven Rostedt (Red Hat) flags & EVENT_FILE_FL_SOFT_MODE)
1786a4390596STom Zanussi strcat(buf, "*");
1787a4390596STom Zanussi
1788a4390596STom Zanussi strcat(buf, "\n");
17891473e441SSteven Rostedt
1790417944c4SSteven Rostedt (Red Hat) return simple_read_from_buffer(ubuf, cnt, ppos, buf, strlen(buf));
17911473e441SSteven Rostedt }
17921473e441SSteven Rostedt
17931473e441SSteven Rostedt static ssize_t
event_enable_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)17941473e441SSteven Rostedt event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
17951473e441SSteven Rostedt loff_t *ppos)
17961473e441SSteven Rostedt {
17977f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
17981473e441SSteven Rostedt unsigned long val;
17991473e441SSteven Rostedt int ret;
18001473e441SSteven Rostedt
180122fe9b54SPeter Huewe ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
180222fe9b54SPeter Huewe if (ret)
18031473e441SSteven Rostedt return ret;
18041473e441SSteven Rostedt
180559980d9bSSteven Rostedt guard(mutex)(&event_mutex);
180659980d9bSSteven Rostedt
18071473e441SSteven Rostedt switch (val) {
18081473e441SSteven Rostedt case 0:
18091473e441SSteven Rostedt case 1:
1810b1560408SSteven Rostedt file = event_file_file(filp);
181159980d9bSSteven Rostedt if (!file)
181259980d9bSSteven Rostedt return -ENODEV;
1813a1f157c7SZheng Yejian ret = tracing_update_buffers(file->tr);
181459980d9bSSteven Rostedt if (ret < 0)
1815a1f157c7SZheng Yejian return ret;
1816ae63b31eSSteven Rostedt ret = ftrace_event_enable_disable(file, val);
1817cad1d5bdSSteven Rostedt if (ret < 0)
1818cad1d5bdSSteven Rostedt return ret;
18191473e441SSteven Rostedt break;
18201473e441SSteven Rostedt
18211473e441SSteven Rostedt default:
18221473e441SSteven Rostedt return -EINVAL;
18231473e441SSteven Rostedt }
18241473e441SSteven Rostedt
18251473e441SSteven Rostedt *ppos += cnt;
18261473e441SSteven Rostedt
1827cad1d5bdSSteven Rostedt return cnt;
18281473e441SSteven Rostedt }
18291473e441SSteven Rostedt
18305f3719f6SSteven Rostedt /*
18315f3719f6SSteven Rostedt * Returns:
18325f3719f6SSteven Rostedt * 0 : no events exist?
18335f3719f6SSteven Rostedt * 1 : all events are disabled
18345f3719f6SSteven Rostedt * 2 : all events are enabled
18355f3719f6SSteven Rostedt * 3 : some events are enabled and some are enabled
18365f3719f6SSteven Rostedt */
trace_events_enabled(struct trace_array * tr,const char * system)18375f3719f6SSteven Rostedt int trace_events_enabled(struct trace_array *tr, const char *system)
18388ae79a13SSteven Rostedt {
18392425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call;
18407f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
1841c142b15dSLi Zefan int set = 0;
18428ae79a13SSteven Rostedt
18435f3719f6SSteven Rostedt guard(mutex)(&event_mutex);
18445f3719f6SSteven Rostedt
1845ae63b31eSSteven Rostedt list_for_each_entry(file, &tr->events, list) {
1846ae63b31eSSteven Rostedt call = file->event_call;
1847256cfdd6SSteven Rostedt (VMware) if ((call->flags & TRACE_EVENT_FL_IGNORE_ENABLE) ||
1848256cfdd6SSteven Rostedt (VMware) !trace_event_name(call) || !call->class || !call->class->reg)
18498ae79a13SSteven Rostedt continue;
18508ae79a13SSteven Rostedt
18515f3719f6SSteven Rostedt if (system && strcmp(call->class->system, system) != 0)
18528ae79a13SSteven Rostedt continue;
18538ae79a13SSteven Rostedt
18548ae79a13SSteven Rostedt /*
18558ae79a13SSteven Rostedt * We need to find out if all the events are set
18568ae79a13SSteven Rostedt * or if all events or cleared, or if we have
18578ae79a13SSteven Rostedt * a mixture.
18588ae79a13SSteven Rostedt */
18595d6ad960SSteven Rostedt (Red Hat) set |= (1 << !!(file->flags & EVENT_FILE_FL_ENABLED));
1860c142b15dSLi Zefan
18618ae79a13SSteven Rostedt /*
18628ae79a13SSteven Rostedt * If we have a mixture, no need to look further.
18638ae79a13SSteven Rostedt */
1864c142b15dSLi Zefan if (set == 3)
18658ae79a13SSteven Rostedt break;
18668ae79a13SSteven Rostedt }
18675f3719f6SSteven Rostedt
18685f3719f6SSteven Rostedt return set;
18695f3719f6SSteven Rostedt }
18705f3719f6SSteven Rostedt
18715f3719f6SSteven Rostedt static ssize_t
system_enable_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)18725f3719f6SSteven Rostedt system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
18735f3719f6SSteven Rostedt loff_t *ppos)
18745f3719f6SSteven Rostedt {
18755f3719f6SSteven Rostedt const char set_to_char[4] = { '?', '0', '1', 'X' };
18765f3719f6SSteven Rostedt struct trace_subsystem_dir *dir = filp->private_data;
18775f3719f6SSteven Rostedt struct event_subsystem *system = dir->subsystem;
18785f3719f6SSteven Rostedt struct trace_array *tr = dir->tr;
18795f3719f6SSteven Rostedt char buf[2];
18805f3719f6SSteven Rostedt int set;
18815f3719f6SSteven Rostedt int ret;
18825f3719f6SSteven Rostedt
18835f3719f6SSteven Rostedt set = trace_events_enabled(tr, system ? system->name : NULL);
18848ae79a13SSteven Rostedt
1885c142b15dSLi Zefan buf[0] = set_to_char[set];
18868ae79a13SSteven Rostedt buf[1] = '\n';
18878ae79a13SSteven Rostedt
18888ae79a13SSteven Rostedt ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, 2);
18898ae79a13SSteven Rostedt
18908ae79a13SSteven Rostedt return ret;
18918ae79a13SSteven Rostedt }
18928ae79a13SSteven Rostedt
18938ae79a13SSteven Rostedt static ssize_t
system_enable_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)18948ae79a13SSteven Rostedt system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
18958ae79a13SSteven Rostedt loff_t *ppos)
18968ae79a13SSteven Rostedt {
18977967b3e0SSteven Rostedt (Red Hat) struct trace_subsystem_dir *dir = filp->private_data;
1898ae63b31eSSteven Rostedt struct event_subsystem *system = dir->subsystem;
189940ee4dffSSteven Rostedt const char *name = NULL;
19008ae79a13SSteven Rostedt unsigned long val;
19018ae79a13SSteven Rostedt ssize_t ret;
19028ae79a13SSteven Rostedt
190322fe9b54SPeter Huewe ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
190422fe9b54SPeter Huewe if (ret)
19058ae79a13SSteven Rostedt return ret;
19068ae79a13SSteven Rostedt
1907a1f157c7SZheng Yejian ret = tracing_update_buffers(dir->tr);
19088ae79a13SSteven Rostedt if (ret < 0)
19098ae79a13SSteven Rostedt return ret;
19108ae79a13SSteven Rostedt
19118f31bfe5SLi Zefan if (val != 0 && val != 1)
19128ae79a13SSteven Rostedt return -EINVAL;
19138ae79a13SSteven Rostedt
191440ee4dffSSteven Rostedt /*
191540ee4dffSSteven Rostedt * Opening of "enable" adds a ref count to system,
191640ee4dffSSteven Rostedt * so the name is safe to use.
191740ee4dffSSteven Rostedt */
191840ee4dffSSteven Rostedt if (system)
191940ee4dffSSteven Rostedt name = system->name;
192040ee4dffSSteven Rostedt
19214c86bc53SSteven Rostedt ret = __ftrace_set_clr_event(dir->tr, NULL, name, NULL, val, NULL);
19228ae79a13SSteven Rostedt if (ret)
19238f31bfe5SLi Zefan goto out;
19248ae79a13SSteven Rostedt
19258ae79a13SSteven Rostedt ret = cnt;
19268ae79a13SSteven Rostedt
19278f31bfe5SLi Zefan out:
19288ae79a13SSteven Rostedt *ppos += cnt;
19298ae79a13SSteven Rostedt
19308ae79a13SSteven Rostedt return ret;
19318ae79a13SSteven Rostedt }
19328ae79a13SSteven Rostedt
19332a37a3dfSSteven Rostedt enum {
19342a37a3dfSSteven Rostedt FORMAT_HEADER = 1,
193586397dc3SLi Zefan FORMAT_FIELD_SEPERATOR = 2,
193686397dc3SLi Zefan FORMAT_PRINTFMT = 3,
19372a37a3dfSSteven Rostedt };
1938981d081eSSteven Rostedt
f_next(struct seq_file * m,void * v,loff_t * pos)19392a37a3dfSSteven Rostedt static void *f_next(struct seq_file *m, void *v, loff_t *pos)
1940981d081eSSteven Rostedt {
1941b1560408SSteven Rostedt struct trace_event_file *file = event_file_data(m->private);
1942b1560408SSteven Rostedt struct trace_event_call *call = file->event_call;
194386397dc3SLi Zefan struct list_head *common_head = &ftrace_common_fields;
194486397dc3SLi Zefan struct list_head *head = trace_get_fields(call);
19457710b639SOleg Nesterov struct list_head *node = v;
1946981d081eSSteven Rostedt
19472a37a3dfSSteven Rostedt (*pos)++;
194891729ef9SSteven Rostedt
19492a37a3dfSSteven Rostedt switch ((unsigned long)v) {
19502a37a3dfSSteven Rostedt case FORMAT_HEADER:
19517710b639SOleg Nesterov node = common_head;
19527710b639SOleg Nesterov break;
195386397dc3SLi Zefan
195486397dc3SLi Zefan case FORMAT_FIELD_SEPERATOR:
19557710b639SOleg Nesterov node = head;
19567710b639SOleg Nesterov break;
19572a37a3dfSSteven Rostedt
19582a37a3dfSSteven Rostedt case FORMAT_PRINTFMT:
19592a37a3dfSSteven Rostedt /* all done */
19602a37a3dfSSteven Rostedt return NULL;
19612a37a3dfSSteven Rostedt }
19622a37a3dfSSteven Rostedt
19637710b639SOleg Nesterov node = node->prev;
19647710b639SOleg Nesterov if (node == common_head)
196586397dc3SLi Zefan return (void *)FORMAT_FIELD_SEPERATOR;
19667710b639SOleg Nesterov else if (node == head)
19672a37a3dfSSteven Rostedt return (void *)FORMAT_PRINTFMT;
19687710b639SOleg Nesterov else
19697710b639SOleg Nesterov return node;
19702a37a3dfSSteven Rostedt }
19712a37a3dfSSteven Rostedt
f_show(struct seq_file * m,void * v)19722a37a3dfSSteven Rostedt static int f_show(struct seq_file *m, void *v)
19732a37a3dfSSteven Rostedt {
1974b1560408SSteven Rostedt struct trace_event_file *file = event_file_data(m->private);
1975b1560408SSteven Rostedt struct trace_event_call *call = file->event_call;
19762a37a3dfSSteven Rostedt struct ftrace_event_field *field;
19772a37a3dfSSteven Rostedt const char *array_descriptor;
19782a37a3dfSSteven Rostedt
19792a37a3dfSSteven Rostedt switch ((unsigned long)v) {
19802a37a3dfSSteven Rostedt case FORMAT_HEADER:
1981687fcc4aSSteven Rostedt (Red Hat) seq_printf(m, "name: %s\n", trace_event_name(call));
19822a37a3dfSSteven Rostedt seq_printf(m, "ID: %d\n", call->event.type);
1983fa6f0cc7SRasmus Villemoes seq_puts(m, "format:\n");
19842a37a3dfSSteven Rostedt return 0;
19852a37a3dfSSteven Rostedt
198686397dc3SLi Zefan case FORMAT_FIELD_SEPERATOR:
198786397dc3SLi Zefan seq_putc(m, '\n');
198886397dc3SLi Zefan return 0;
198986397dc3SLi Zefan
19902a37a3dfSSteven Rostedt case FORMAT_PRINTFMT:
19912a37a3dfSSteven Rostedt seq_printf(m, "\nprint fmt: %s\n",
19922a37a3dfSSteven Rostedt call->print_fmt);
19932a37a3dfSSteven Rostedt return 0;
19942a37a3dfSSteven Rostedt }
19952a37a3dfSSteven Rostedt
19967710b639SOleg Nesterov field = list_entry(v, struct ftrace_event_field, link);
19975a65e956SLai Jiangshan /*
19985a65e956SLai Jiangshan * Smartly shows the array type(except dynamic array).
19995a65e956SLai Jiangshan * Normal:
20005a65e956SLai Jiangshan * field:TYPE VAR
20015a65e956SLai Jiangshan * If TYPE := TYPE[LEN], it is shown:
20025a65e956SLai Jiangshan * field:TYPE VAR[LEN]
20035a65e956SLai Jiangshan */
20042a37a3dfSSteven Rostedt array_descriptor = strchr(field->type, '[');
20055a65e956SLai Jiangshan
2006b6b27355SSteven Rostedt (VMware) if (str_has_prefix(field->type, "__data_loc"))
20075a65e956SLai Jiangshan array_descriptor = NULL;
20085a65e956SLai Jiangshan
20092a37a3dfSSteven Rostedt if (!array_descriptor)
20102a37a3dfSSteven Rostedt seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n",
20115a65e956SLai Jiangshan field->type, field->name, field->offset,
20125a65e956SLai Jiangshan field->size, !!field->is_signed);
2013b6c7abd1SYafang Shao else if (field->len)
2014b6c7abd1SYafang Shao seq_printf(m, "\tfield:%.*s %s[%d];\toffset:%u;\tsize:%u;\tsigned:%d;\n",
20155a65e956SLai Jiangshan (int)(array_descriptor - field->type),
20165a65e956SLai Jiangshan field->type, field->name,
2017b6c7abd1SYafang Shao field->len, field->offset,
20185a65e956SLai Jiangshan field->size, !!field->is_signed);
2019b6c7abd1SYafang Shao else
2020b6c7abd1SYafang Shao seq_printf(m, "\tfield:%.*s %s[];\toffset:%u;\tsize:%u;\tsigned:%d;\n",
2021b6c7abd1SYafang Shao (int)(array_descriptor - field->type),
2022b6c7abd1SYafang Shao field->type, field->name,
2023b6c7abd1SYafang Shao field->offset, field->size, !!field->is_signed);
20245a65e956SLai Jiangshan
20258728fe50SLi Zefan return 0;
2026981d081eSSteven Rostedt }
2027981d081eSSteven Rostedt
f_start(struct seq_file * m,loff_t * pos)20287710b639SOleg Nesterov static void *f_start(struct seq_file *m, loff_t *pos)
20297710b639SOleg Nesterov {
2030b1560408SSteven Rostedt struct trace_event_file *file;
20317710b639SOleg Nesterov void *p = (void *)FORMAT_HEADER;
20327710b639SOleg Nesterov loff_t l = 0;
20337710b639SOleg Nesterov
2034c5a44a12SOleg Nesterov /* ->stop() is called even if ->start() fails */
2035c5a44a12SOleg Nesterov mutex_lock(&event_mutex);
2036b1560408SSteven Rostedt file = event_file_file(m->private);
2037b1560408SSteven Rostedt if (!file)
2038c5a44a12SOleg Nesterov return ERR_PTR(-ENODEV);
2039c5a44a12SOleg Nesterov
20407710b639SOleg Nesterov while (l < *pos && p)
20417710b639SOleg Nesterov p = f_next(m, p, &l);
20427710b639SOleg Nesterov
20437710b639SOleg Nesterov return p;
20447710b639SOleg Nesterov }
20457710b639SOleg Nesterov
f_stop(struct seq_file * m,void * p)20462a37a3dfSSteven Rostedt static void f_stop(struct seq_file *m, void *p)
20472a37a3dfSSteven Rostedt {
2048c5a44a12SOleg Nesterov mutex_unlock(&event_mutex);
2049981d081eSSteven Rostedt }
2050981d081eSSteven Rostedt
20512a37a3dfSSteven Rostedt static const struct seq_operations trace_format_seq_ops = {
20522a37a3dfSSteven Rostedt .start = f_start,
20532a37a3dfSSteven Rostedt .next = f_next,
20542a37a3dfSSteven Rostedt .stop = f_stop,
20552a37a3dfSSteven Rostedt .show = f_show,
20562a37a3dfSSteven Rostedt };
2057981d081eSSteven Rostedt
trace_format_open(struct inode * inode,struct file * file)20582a37a3dfSSteven Rostedt static int trace_format_open(struct inode *inode, struct file *file)
20592a37a3dfSSteven Rostedt {
20602a37a3dfSSteven Rostedt struct seq_file *m;
20612a37a3dfSSteven Rostedt int ret;
2062fd994989SSteven Rostedt
206317911ff3SSteven Rostedt (VMware) /* Do we want to hide event format files on tracefs lockdown? */
206417911ff3SSteven Rostedt (VMware)
20652a37a3dfSSteven Rostedt ret = seq_open(file, &trace_format_seq_ops);
20662a37a3dfSSteven Rostedt if (ret < 0)
20672a37a3dfSSteven Rostedt return ret;
20682a37a3dfSSteven Rostedt
20692a37a3dfSSteven Rostedt m = file->private_data;
2070c5a44a12SOleg Nesterov m->private = file;
20712a37a3dfSSteven Rostedt
20722a37a3dfSSteven Rostedt return 0;
2073fd994989SSteven Rostedt }
2074fd994989SSteven Rostedt
20755281ec83SArnd Bergmann #ifdef CONFIG_PERF_EVENTS
207623725aeeSPeter Zijlstra static ssize_t
event_id_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)207723725aeeSPeter Zijlstra event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
207823725aeeSPeter Zijlstra {
20791a11126bSOleg Nesterov int id = (long)event_file_data(filp);
2080cd458ba9SOleg Nesterov char buf[32];
2081cd458ba9SOleg Nesterov int len;
208223725aeeSPeter Zijlstra
20831a11126bSOleg Nesterov if (unlikely(!id))
20841a11126bSOleg Nesterov return -ENODEV;
20851a11126bSOleg Nesterov
20861a11126bSOleg Nesterov len = sprintf(buf, "%d\n", id);
20871a11126bSOleg Nesterov
2088cd458ba9SOleg Nesterov return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
208923725aeeSPeter Zijlstra }
20905281ec83SArnd Bergmann #endif
209123725aeeSPeter Zijlstra
20927ce7e424STom Zanussi static ssize_t
event_filter_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)20937ce7e424STom Zanussi event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
20947ce7e424STom Zanussi loff_t *ppos)
20957ce7e424STom Zanussi {
20967f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
20977ce7e424STom Zanussi struct trace_seq *s;
2098e2912b09SOleg Nesterov int r = -ENODEV;
20997ce7e424STom Zanussi
21007ce7e424STom Zanussi if (*ppos)
21017ce7e424STom Zanussi return 0;
21027ce7e424STom Zanussi
21037ce7e424STom Zanussi s = kmalloc(sizeof(*s), GFP_KERNEL);
2104e2912b09SOleg Nesterov
21057ce7e424STom Zanussi if (!s)
21067ce7e424STom Zanussi return -ENOMEM;
21077ce7e424STom Zanussi
21087ce7e424STom Zanussi trace_seq_init(s);
21097ce7e424STom Zanussi
2110e2912b09SOleg Nesterov mutex_lock(&event_mutex);
2111b1560408SSteven Rostedt file = event_file_file(filp);
2112b1560408SSteven Rostedt if (file)
2113f306cc82STom Zanussi print_event_filter(file, s);
2114e2912b09SOleg Nesterov mutex_unlock(&event_mutex);
2115e2912b09SOleg Nesterov
2116f306cc82STom Zanussi if (file)
21175ac48378SSteven Rostedt (Red Hat) r = simple_read_from_buffer(ubuf, cnt, ppos,
21185ac48378SSteven Rostedt (Red Hat) s->buffer, trace_seq_used(s));
21197ce7e424STom Zanussi
21207ce7e424STom Zanussi kfree(s);
21217ce7e424STom Zanussi
21227ce7e424STom Zanussi return r;
21237ce7e424STom Zanussi }
21247ce7e424STom Zanussi
21257ce7e424STom Zanussi static ssize_t
event_filter_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)21267ce7e424STom Zanussi event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
21277ce7e424STom Zanussi loff_t *ppos)
21287ce7e424STom Zanussi {
21297f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
21308b372562STom Zanussi char *buf;
2131e2912b09SOleg Nesterov int err = -ENODEV;
21327ce7e424STom Zanussi
21338b372562STom Zanussi if (cnt >= PAGE_SIZE)
21347ce7e424STom Zanussi return -EINVAL;
21357ce7e424STom Zanussi
213670f6cbb6SAl Viro buf = memdup_user_nul(ubuf, cnt);
213770f6cbb6SAl Viro if (IS_ERR(buf))
213870f6cbb6SAl Viro return PTR_ERR(buf);
21398b372562STom Zanussi
2140e2912b09SOleg Nesterov mutex_lock(&event_mutex);
2141b1560408SSteven Rostedt file = event_file_file(filp);
2142b1560408SSteven Rostedt if (file) {
2143b1560408SSteven Rostedt if (file->flags & EVENT_FILE_FL_FREED)
2144b1560408SSteven Rostedt err = -ENODEV;
2145b1560408SSteven Rostedt else
2146f306cc82STom Zanussi err = apply_event_filter(file, buf);
2147b1560408SSteven Rostedt }
2148e2912b09SOleg Nesterov mutex_unlock(&event_mutex);
2149e2912b09SOleg Nesterov
215070f6cbb6SAl Viro kfree(buf);
21518b372562STom Zanussi if (err < 0)
21527ce7e424STom Zanussi return err;
21530a19e53cSTom Zanussi
21547ce7e424STom Zanussi *ppos += cnt;
21557ce7e424STom Zanussi
21567ce7e424STom Zanussi return cnt;
21577ce7e424STom Zanussi }
21587ce7e424STom Zanussi
2159e9dbfae5SSteven Rostedt static LIST_HEAD(event_subsystems);
2160e9dbfae5SSteven Rostedt
subsystem_open(struct inode * inode,struct file * filp)2161e9dbfae5SSteven Rostedt static int subsystem_open(struct inode *inode, struct file *filp)
2162e9dbfae5SSteven Rostedt {
216399d8ae4eSJakob Koschel struct trace_subsystem_dir *dir = NULL, *iter_dir;
216499d8ae4eSJakob Koschel struct trace_array *tr = NULL, *iter_tr;
2165e9dbfae5SSteven Rostedt struct event_subsystem *system = NULL;
2166e9dbfae5SSteven Rostedt int ret;
2167e9dbfae5SSteven Rostedt
2168d6d3523cSGeyslan G. Bem if (tracing_is_disabled())
2169d6d3523cSGeyslan G. Bem return -ENODEV;
2170d6d3523cSGeyslan G. Bem
2171e9dbfae5SSteven Rostedt /* Make sure the system still exists */
2172e9dbfae5SSteven Rostedt mutex_lock(&event_mutex);
217312ecef0cSSteven Rostedt (VMware) mutex_lock(&trace_types_lock);
217499d8ae4eSJakob Koschel list_for_each_entry(iter_tr, &ftrace_trace_arrays, list) {
217599d8ae4eSJakob Koschel list_for_each_entry(iter_dir, &iter_tr->systems, list) {
217699d8ae4eSJakob Koschel if (iter_dir == inode->i_private) {
2177e9dbfae5SSteven Rostedt /* Don't open systems with no events */
217899d8ae4eSJakob Koschel tr = iter_tr;
217999d8ae4eSJakob Koschel dir = iter_dir;
2180ae63b31eSSteven Rostedt if (dir->nr_events) {
2181ae63b31eSSteven Rostedt __get_system_dir(dir);
2182ae63b31eSSteven Rostedt system = dir->subsystem;
2183e9dbfae5SSteven Rostedt }
2184ae63b31eSSteven Rostedt goto exit_loop;
2185e9dbfae5SSteven Rostedt }
2186e9dbfae5SSteven Rostedt }
2187ae63b31eSSteven Rostedt }
2188ae63b31eSSteven Rostedt exit_loop:
2189a8227415SAlexander Z Lam mutex_unlock(&trace_types_lock);
219012ecef0cSSteven Rostedt (VMware) mutex_unlock(&event_mutex);
2191e9dbfae5SSteven Rostedt
2192ae63b31eSSteven Rostedt if (!system)
2193e9dbfae5SSteven Rostedt return -ENODEV;
2194e9dbfae5SSteven Rostedt
21958e2e2fa4SSteven Rostedt (Red Hat) /* Still need to increment the ref count of the system */
21968e2e2fa4SSteven Rostedt (Red Hat) if (trace_array_get(tr) < 0) {
2197ae63b31eSSteven Rostedt put_system(dir);
21988e2e2fa4SSteven Rostedt (Red Hat) return -ENODEV;
21998e2e2fa4SSteven Rostedt (Red Hat) }
22008e2e2fa4SSteven Rostedt (Red Hat)
22018e2e2fa4SSteven Rostedt (Red Hat) ret = tracing_open_generic(inode, filp);
22028e2e2fa4SSteven Rostedt (Red Hat) if (ret < 0) {
22038e2e2fa4SSteven Rostedt (Red Hat) trace_array_put(tr);
22048e2e2fa4SSteven Rostedt (Red Hat) put_system(dir);
22058e2e2fa4SSteven Rostedt (Red Hat) }
2206ae63b31eSSteven Rostedt
2207ae63b31eSSteven Rostedt return ret;
2208ae63b31eSSteven Rostedt }
2209ae63b31eSSteven Rostedt
system_tr_open(struct inode * inode,struct file * filp)2210ae63b31eSSteven Rostedt static int system_tr_open(struct inode *inode, struct file *filp)
2211ae63b31eSSteven Rostedt {
22127967b3e0SSteven Rostedt (Red Hat) struct trace_subsystem_dir *dir;
2213ae63b31eSSteven Rostedt struct trace_array *tr = inode->i_private;
2214ae63b31eSSteven Rostedt int ret;
2215ae63b31eSSteven Rostedt
2216ae63b31eSSteven Rostedt /* Make a temporary dir that has no system but points to tr */
2217ae63b31eSSteven Rostedt dir = kzalloc(sizeof(*dir), GFP_KERNEL);
2218aa07d71fSSteven Rostedt (VMware) if (!dir)
2219ae63b31eSSteven Rostedt return -ENOMEM;
2220ae63b31eSSteven Rostedt
2221aa07d71fSSteven Rostedt (VMware) ret = tracing_open_generic_tr(inode, filp);
22228e2e2fa4SSteven Rostedt (Red Hat) if (ret < 0) {
2223ae63b31eSSteven Rostedt kfree(dir);
2224d6d3523cSGeyslan G. Bem return ret;
22258e2e2fa4SSteven Rostedt (Red Hat) }
2226aa07d71fSSteven Rostedt (VMware) dir->tr = tr;
2227ae63b31eSSteven Rostedt filp->private_data = dir;
2228e9dbfae5SSteven Rostedt
2229d6d3523cSGeyslan G. Bem return 0;
2230e9dbfae5SSteven Rostedt }
2231e9dbfae5SSteven Rostedt
subsystem_release(struct inode * inode,struct file * file)2232e9dbfae5SSteven Rostedt static int subsystem_release(struct inode *inode, struct file *file)
2233e9dbfae5SSteven Rostedt {
22347967b3e0SSteven Rostedt (Red Hat) struct trace_subsystem_dir *dir = file->private_data;
2235e9dbfae5SSteven Rostedt
22368e2e2fa4SSteven Rostedt (Red Hat) trace_array_put(dir->tr);
22378e2e2fa4SSteven Rostedt (Red Hat)
2238ae63b31eSSteven Rostedt /*
2239ae63b31eSSteven Rostedt * If dir->subsystem is NULL, then this is a temporary
2240ae63b31eSSteven Rostedt * descriptor that was made for a trace_array to enable
2241ae63b31eSSteven Rostedt * all subsystems.
2242ae63b31eSSteven Rostedt */
2243ae63b31eSSteven Rostedt if (dir->subsystem)
2244ae63b31eSSteven Rostedt put_system(dir);
2245ae63b31eSSteven Rostedt else
2246ae63b31eSSteven Rostedt kfree(dir);
2247e9dbfae5SSteven Rostedt
2248e9dbfae5SSteven Rostedt return 0;
2249e9dbfae5SSteven Rostedt }
2250e9dbfae5SSteven Rostedt
2251cfb180f3STom Zanussi static ssize_t
subsystem_filter_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)2252cfb180f3STom Zanussi subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
2253cfb180f3STom Zanussi loff_t *ppos)
2254cfb180f3STom Zanussi {
22557967b3e0SSteven Rostedt (Red Hat) struct trace_subsystem_dir *dir = filp->private_data;
2256ae63b31eSSteven Rostedt struct event_subsystem *system = dir->subsystem;
2257cfb180f3STom Zanussi struct trace_seq *s;
2258cfb180f3STom Zanussi int r;
2259cfb180f3STom Zanussi
2260cfb180f3STom Zanussi if (*ppos)
2261cfb180f3STom Zanussi return 0;
2262cfb180f3STom Zanussi
2263cfb180f3STom Zanussi s = kmalloc(sizeof(*s), GFP_KERNEL);
2264cfb180f3STom Zanussi if (!s)
2265cfb180f3STom Zanussi return -ENOMEM;
2266cfb180f3STom Zanussi
2267cfb180f3STom Zanussi trace_seq_init(s);
2268cfb180f3STom Zanussi
22698b372562STom Zanussi print_subsystem_event_filter(system, s);
22705ac48378SSteven Rostedt (Red Hat) r = simple_read_from_buffer(ubuf, cnt, ppos,
22715ac48378SSteven Rostedt (Red Hat) s->buffer, trace_seq_used(s));
2272cfb180f3STom Zanussi
2273cfb180f3STom Zanussi kfree(s);
2274cfb180f3STom Zanussi
2275cfb180f3STom Zanussi return r;
2276cfb180f3STom Zanussi }
2277cfb180f3STom Zanussi
2278cfb180f3STom Zanussi static ssize_t
subsystem_filter_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)2279cfb180f3STom Zanussi subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
2280cfb180f3STom Zanussi loff_t *ppos)
2281cfb180f3STom Zanussi {
22827967b3e0SSteven Rostedt (Red Hat) struct trace_subsystem_dir *dir = filp->private_data;
22838b372562STom Zanussi char *buf;
2284cfb180f3STom Zanussi int err;
2285cfb180f3STom Zanussi
22868b372562STom Zanussi if (cnt >= PAGE_SIZE)
2287cfb180f3STom Zanussi return -EINVAL;
2288cfb180f3STom Zanussi
228970f6cbb6SAl Viro buf = memdup_user_nul(ubuf, cnt);
229070f6cbb6SAl Viro if (IS_ERR(buf))
229170f6cbb6SAl Viro return PTR_ERR(buf);
2292cfb180f3STom Zanussi
2293ae63b31eSSteven Rostedt err = apply_subsystem_event_filter(dir, buf);
229470f6cbb6SAl Viro kfree(buf);
22958b372562STom Zanussi if (err < 0)
229644e9c8b7SLi Zefan return err;
2297cfb180f3STom Zanussi
2298cfb180f3STom Zanussi *ppos += cnt;
2299cfb180f3STom Zanussi
2300cfb180f3STom Zanussi return cnt;
2301cfb180f3STom Zanussi }
2302cfb180f3STom Zanussi
2303d1b182a8SSteven Rostedt static ssize_t
show_header_page_file(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)2304139f8400STzvetomir Stoyanov (VMware) show_header_page_file(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
2305d1b182a8SSteven Rostedt {
2306139f8400STzvetomir Stoyanov (VMware) struct trace_array *tr = filp->private_data;
2307d1b182a8SSteven Rostedt struct trace_seq *s;
2308d1b182a8SSteven Rostedt int r;
2309d1b182a8SSteven Rostedt
2310d1b182a8SSteven Rostedt if (*ppos)
2311d1b182a8SSteven Rostedt return 0;
2312d1b182a8SSteven Rostedt
2313d1b182a8SSteven Rostedt s = kmalloc(sizeof(*s), GFP_KERNEL);
2314d1b182a8SSteven Rostedt if (!s)
2315d1b182a8SSteven Rostedt return -ENOMEM;
2316d1b182a8SSteven Rostedt
2317d1b182a8SSteven Rostedt trace_seq_init(s);
2318d1b182a8SSteven Rostedt
2319139f8400STzvetomir Stoyanov (VMware) ring_buffer_print_page_header(tr->array_buffer.buffer, s);
2320139f8400STzvetomir Stoyanov (VMware) r = simple_read_from_buffer(ubuf, cnt, ppos,
2321139f8400STzvetomir Stoyanov (VMware) s->buffer, trace_seq_used(s));
2322139f8400STzvetomir Stoyanov (VMware)
2323139f8400STzvetomir Stoyanov (VMware) kfree(s);
2324139f8400STzvetomir Stoyanov (VMware)
2325139f8400STzvetomir Stoyanov (VMware) return r;
2326139f8400STzvetomir Stoyanov (VMware) }
2327139f8400STzvetomir Stoyanov (VMware)
2328139f8400STzvetomir Stoyanov (VMware) static ssize_t
show_header_event_file(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)2329139f8400STzvetomir Stoyanov (VMware) show_header_event_file(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
2330139f8400STzvetomir Stoyanov (VMware) {
2331139f8400STzvetomir Stoyanov (VMware) struct trace_seq *s;
2332139f8400STzvetomir Stoyanov (VMware) int r;
2333139f8400STzvetomir Stoyanov (VMware)
2334139f8400STzvetomir Stoyanov (VMware) if (*ppos)
2335139f8400STzvetomir Stoyanov (VMware) return 0;
2336139f8400STzvetomir Stoyanov (VMware)
2337139f8400STzvetomir Stoyanov (VMware) s = kmalloc(sizeof(*s), GFP_KERNEL);
2338139f8400STzvetomir Stoyanov (VMware) if (!s)
2339139f8400STzvetomir Stoyanov (VMware) return -ENOMEM;
2340139f8400STzvetomir Stoyanov (VMware)
2341139f8400STzvetomir Stoyanov (VMware) trace_seq_init(s);
2342139f8400STzvetomir Stoyanov (VMware)
2343139f8400STzvetomir Stoyanov (VMware) ring_buffer_print_entry_header(s);
23445ac48378SSteven Rostedt (Red Hat) r = simple_read_from_buffer(ubuf, cnt, ppos,
23455ac48378SSteven Rostedt (Red Hat) s->buffer, trace_seq_used(s));
2346d1b182a8SSteven Rostedt
2347d1b182a8SSteven Rostedt kfree(s);
2348d1b182a8SSteven Rostedt
2349d1b182a8SSteven Rostedt return r;
2350d1b182a8SSteven Rostedt }
2351d1b182a8SSteven Rostedt
ignore_task_cpu(void * data)23528ca532adSSteven Rostedt (Red Hat) static void ignore_task_cpu(void *data)
23538ca532adSSteven Rostedt (Red Hat) {
23548ca532adSSteven Rostedt (Red Hat) struct trace_array *tr = data;
23558ca532adSSteven Rostedt (Red Hat) struct trace_pid_list *pid_list;
235627683626SSteven Rostedt (VMware) struct trace_pid_list *no_pid_list;
23578ca532adSSteven Rostedt (Red Hat)
23588ca532adSSteven Rostedt (Red Hat) /*
23598ca532adSSteven Rostedt (Red Hat) * This function is called by on_each_cpu() while the
23608ca532adSSteven Rostedt (Red Hat) * event_mutex is held.
23618ca532adSSteven Rostedt (Red Hat) */
23628ca532adSSteven Rostedt (Red Hat) pid_list = rcu_dereference_protected(tr->filtered_pids,
23638ca532adSSteven Rostedt (Red Hat) mutex_is_locked(&event_mutex));
236427683626SSteven Rostedt (VMware) no_pid_list = rcu_dereference_protected(tr->filtered_no_pids,
236527683626SSteven Rostedt (VMware) mutex_is_locked(&event_mutex));
23668ca532adSSteven Rostedt (Red Hat)
23671c5eb448SSteven Rostedt (VMware) this_cpu_write(tr->array_buffer.data->ignore_pid,
236827683626SSteven Rostedt (VMware) trace_ignore_this_task(pid_list, no_pid_list, current));
23698ca532adSSteven Rostedt (Red Hat) }
23708ca532adSSteven Rostedt (Red Hat)
register_pid_events(struct trace_array * tr)237127683626SSteven Rostedt (VMware) static void register_pid_events(struct trace_array *tr)
237249090107SSteven Rostedt (Red Hat) {
23733fdaf80fSSteven Rostedt (Red Hat) /*
23743fdaf80fSSteven Rostedt (Red Hat) * Register a probe that is called before all other probes
23753fdaf80fSSteven Rostedt (Red Hat) * to set ignore_pid if next or prev do not match.
23763fdaf80fSSteven Rostedt (Red Hat) * Register a probe this is called after all other probes
23773fdaf80fSSteven Rostedt (Red Hat) * to only keep ignore_pid set if next pid matches.
23783fdaf80fSSteven Rostedt (Red Hat) */
23793fdaf80fSSteven Rostedt (Red Hat) register_trace_prio_sched_switch(event_filter_pid_sched_switch_probe_pre,
23803fdaf80fSSteven Rostedt (Red Hat) tr, INT_MAX);
23813fdaf80fSSteven Rostedt (Red Hat) register_trace_prio_sched_switch(event_filter_pid_sched_switch_probe_post,
23823fdaf80fSSteven Rostedt (Red Hat) tr, 0);
23833fdaf80fSSteven Rostedt (Red Hat)
23843fdaf80fSSteven Rostedt (Red Hat) register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre,
23853fdaf80fSSteven Rostedt (Red Hat) tr, INT_MAX);
23863fdaf80fSSteven Rostedt (Red Hat) register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_post,
23873fdaf80fSSteven Rostedt (Red Hat) tr, 0);
23880f72e37eSSteven Rostedt (Red Hat)
23890f72e37eSSteven Rostedt (Red Hat) register_trace_prio_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_pre,
23900f72e37eSSteven Rostedt (Red Hat) tr, INT_MAX);
23910f72e37eSSteven Rostedt (Red Hat) register_trace_prio_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_post,
23920f72e37eSSteven Rostedt (Red Hat) tr, 0);
23930f72e37eSSteven Rostedt (Red Hat)
23940f72e37eSSteven Rostedt (Red Hat) register_trace_prio_sched_waking(event_filter_pid_sched_wakeup_probe_pre,
23950f72e37eSSteven Rostedt (Red Hat) tr, INT_MAX);
23960f72e37eSSteven Rostedt (Red Hat) register_trace_prio_sched_waking(event_filter_pid_sched_wakeup_probe_post,
23970f72e37eSSteven Rostedt (Red Hat) tr, 0);
2398799fd44cSSteven Rostedt (Red Hat) }
23998ca532adSSteven Rostedt (Red Hat)
240027683626SSteven Rostedt (VMware) static ssize_t
event_pid_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos,int type)240127683626SSteven Rostedt (VMware) event_pid_write(struct file *filp, const char __user *ubuf,
240227683626SSteven Rostedt (VMware) size_t cnt, loff_t *ppos, int type)
240327683626SSteven Rostedt (VMware) {
240427683626SSteven Rostedt (VMware) struct seq_file *m = filp->private_data;
240527683626SSteven Rostedt (VMware) struct trace_array *tr = m->private;
240627683626SSteven Rostedt (VMware) struct trace_pid_list *filtered_pids = NULL;
240727683626SSteven Rostedt (VMware) struct trace_pid_list *other_pids = NULL;
240827683626SSteven Rostedt (VMware) struct trace_pid_list *pid_list;
240927683626SSteven Rostedt (VMware) struct trace_event_file *file;
241027683626SSteven Rostedt (VMware) ssize_t ret;
241127683626SSteven Rostedt (VMware)
241227683626SSteven Rostedt (VMware) if (!cnt)
241327683626SSteven Rostedt (VMware) return 0;
241427683626SSteven Rostedt (VMware)
2415a1f157c7SZheng Yejian ret = tracing_update_buffers(tr);
241627683626SSteven Rostedt (VMware) if (ret < 0)
241727683626SSteven Rostedt (VMware) return ret;
241827683626SSteven Rostedt (VMware)
241959980d9bSSteven Rostedt guard(mutex)(&event_mutex);
242027683626SSteven Rostedt (VMware)
242127683626SSteven Rostedt (VMware) if (type == TRACE_PIDS) {
242227683626SSteven Rostedt (VMware) filtered_pids = rcu_dereference_protected(tr->filtered_pids,
242327683626SSteven Rostedt (VMware) lockdep_is_held(&event_mutex));
242427683626SSteven Rostedt (VMware) other_pids = rcu_dereference_protected(tr->filtered_no_pids,
242527683626SSteven Rostedt (VMware) lockdep_is_held(&event_mutex));
242627683626SSteven Rostedt (VMware) } else {
242727683626SSteven Rostedt (VMware) filtered_pids = rcu_dereference_protected(tr->filtered_no_pids,
242827683626SSteven Rostedt (VMware) lockdep_is_held(&event_mutex));
242927683626SSteven Rostedt (VMware) other_pids = rcu_dereference_protected(tr->filtered_pids,
243027683626SSteven Rostedt (VMware) lockdep_is_held(&event_mutex));
243127683626SSteven Rostedt (VMware) }
243227683626SSteven Rostedt (VMware)
243327683626SSteven Rostedt (VMware) ret = trace_pid_write(filtered_pids, &pid_list, ubuf, cnt);
243427683626SSteven Rostedt (VMware) if (ret < 0)
243559980d9bSSteven Rostedt return ret;
243627683626SSteven Rostedt (VMware)
243727683626SSteven Rostedt (VMware) if (type == TRACE_PIDS)
243827683626SSteven Rostedt (VMware) rcu_assign_pointer(tr->filtered_pids, pid_list);
243927683626SSteven Rostedt (VMware) else
244027683626SSteven Rostedt (VMware) rcu_assign_pointer(tr->filtered_no_pids, pid_list);
244127683626SSteven Rostedt (VMware)
244227683626SSteven Rostedt (VMware) list_for_each_entry(file, &tr->events, list) {
244327683626SSteven Rostedt (VMware) set_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags);
244427683626SSteven Rostedt (VMware) }
244527683626SSteven Rostedt (VMware)
244627683626SSteven Rostedt (VMware) if (filtered_pids) {
244727683626SSteven Rostedt (VMware) tracepoint_synchronize_unregister();
24486954e415SSteven Rostedt (VMware) trace_pid_list_free(filtered_pids);
244927683626SSteven Rostedt (VMware) } else if (pid_list && !other_pids) {
245027683626SSteven Rostedt (VMware) register_pid_events(tr);
245127683626SSteven Rostedt (VMware) }
245227683626SSteven Rostedt (VMware)
24538ca532adSSteven Rostedt (Red Hat) /*
24548ca532adSSteven Rostedt (Red Hat) * Ignoring of pids is done at task switch. But we have to
24558ca532adSSteven Rostedt (Red Hat) * check for those tasks that are currently running.
2456799fd44cSSteven Rostedt (Red Hat) * Always do this in case a pid was appended or removed.
24578ca532adSSteven Rostedt (Red Hat) */
24588ca532adSSteven Rostedt (Red Hat) on_each_cpu(ignore_task_cpu, tr, 1);
245949090107SSteven Rostedt (Red Hat)
246076c813e2SSteven Rostedt (Red Hat) *ppos += ret;
246149090107SSteven Rostedt (Red Hat)
246249090107SSteven Rostedt (Red Hat) return ret;
246349090107SSteven Rostedt (Red Hat) }
246449090107SSteven Rostedt (Red Hat)
246527683626SSteven Rostedt (VMware) static ssize_t
ftrace_event_pid_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)246627683626SSteven Rostedt (VMware) ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
246727683626SSteven Rostedt (VMware) size_t cnt, loff_t *ppos)
246827683626SSteven Rostedt (VMware) {
246927683626SSteven Rostedt (VMware) return event_pid_write(filp, ubuf, cnt, ppos, TRACE_PIDS);
247027683626SSteven Rostedt (VMware) }
247127683626SSteven Rostedt (VMware)
247227683626SSteven Rostedt (VMware) static ssize_t
ftrace_event_npid_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)247327683626SSteven Rostedt (VMware) ftrace_event_npid_write(struct file *filp, const char __user *ubuf,
247427683626SSteven Rostedt (VMware) size_t cnt, loff_t *ppos)
247527683626SSteven Rostedt (VMware) {
247627683626SSteven Rostedt (VMware) return event_pid_write(filp, ubuf, cnt, ppos, TRACE_NO_PIDS);
247727683626SSteven Rostedt (VMware) }
247827683626SSteven Rostedt (VMware)
247915075cacSSteven Rostedt static int ftrace_event_avail_open(struct inode *inode, struct file *file);
248015075cacSSteven Rostedt static int ftrace_event_set_open(struct inode *inode, struct file *file);
248149090107SSteven Rostedt (Red Hat) static int ftrace_event_set_pid_open(struct inode *inode, struct file *file);
248227683626SSteven Rostedt (VMware) static int ftrace_event_set_npid_open(struct inode *inode, struct file *file);
2483f77d09a3SAlexander Z Lam static int ftrace_event_release(struct inode *inode, struct file *file);
248415075cacSSteven Rostedt
2485b77e38aaSSteven Rostedt static const struct seq_operations show_event_seq_ops = {
2486b77e38aaSSteven Rostedt .start = t_start,
2487b77e38aaSSteven Rostedt .next = t_next,
2488b77e38aaSSteven Rostedt .show = t_show,
2489b77e38aaSSteven Rostedt .stop = t_stop,
2490b77e38aaSSteven Rostedt };
2491b77e38aaSSteven Rostedt
2492b77e38aaSSteven Rostedt static const struct seq_operations show_set_event_seq_ops = {
2493b77e38aaSSteven Rostedt .start = s_start,
2494b77e38aaSSteven Rostedt .next = s_next,
2495b355247dSSteven Rostedt .show = s_show,
2496b355247dSSteven Rostedt .stop = s_stop,
2497b77e38aaSSteven Rostedt };
2498b77e38aaSSteven Rostedt
249949090107SSteven Rostedt (Red Hat) static const struct seq_operations show_set_pid_seq_ops = {
250049090107SSteven Rostedt (Red Hat) .start = p_start,
250149090107SSteven Rostedt (Red Hat) .next = p_next,
25025cc8976bSSteven Rostedt (Red Hat) .show = trace_pid_show,
250349090107SSteven Rostedt (Red Hat) .stop = p_stop,
250449090107SSteven Rostedt (Red Hat) };
250549090107SSteven Rostedt (Red Hat)
250627683626SSteven Rostedt (VMware) static const struct seq_operations show_set_no_pid_seq_ops = {
250727683626SSteven Rostedt (VMware) .start = np_start,
250827683626SSteven Rostedt (VMware) .next = np_next,
250927683626SSteven Rostedt (VMware) .show = trace_pid_show,
251027683626SSteven Rostedt (VMware) .stop = p_stop,
251127683626SSteven Rostedt (VMware) };
251227683626SSteven Rostedt (VMware)
25132314c4aeSSteven Rostedt static const struct file_operations ftrace_avail_fops = {
251415075cacSSteven Rostedt .open = ftrace_event_avail_open,
25152314c4aeSSteven Rostedt .read = seq_read,
25162314c4aeSSteven Rostedt .llseek = seq_lseek,
25172314c4aeSSteven Rostedt .release = seq_release,
25182314c4aeSSteven Rostedt };
25192314c4aeSSteven Rostedt
2520b77e38aaSSteven Rostedt static const struct file_operations ftrace_set_event_fops = {
252115075cacSSteven Rostedt .open = ftrace_event_set_open,
2522b77e38aaSSteven Rostedt .read = seq_read,
2523b77e38aaSSteven Rostedt .write = ftrace_event_write,
2524b77e38aaSSteven Rostedt .llseek = seq_lseek,
2525f77d09a3SAlexander Z Lam .release = ftrace_event_release,
2526b77e38aaSSteven Rostedt };
2527b77e38aaSSteven Rostedt
252849090107SSteven Rostedt (Red Hat) static const struct file_operations ftrace_set_event_pid_fops = {
252949090107SSteven Rostedt (Red Hat) .open = ftrace_event_set_pid_open,
253049090107SSteven Rostedt (Red Hat) .read = seq_read,
253149090107SSteven Rostedt (Red Hat) .write = ftrace_event_pid_write,
253249090107SSteven Rostedt (Red Hat) .llseek = seq_lseek,
253349090107SSteven Rostedt (Red Hat) .release = ftrace_event_release,
253449090107SSteven Rostedt (Red Hat) };
253549090107SSteven Rostedt (Red Hat)
253627683626SSteven Rostedt (VMware) static const struct file_operations ftrace_set_event_notrace_pid_fops = {
253727683626SSteven Rostedt (VMware) .open = ftrace_event_set_npid_open,
253827683626SSteven Rostedt (VMware) .read = seq_read,
253927683626SSteven Rostedt (VMware) .write = ftrace_event_npid_write,
254027683626SSteven Rostedt (VMware) .llseek = seq_lseek,
254127683626SSteven Rostedt (VMware) .release = ftrace_event_release,
254227683626SSteven Rostedt (VMware) };
254327683626SSteven Rostedt (VMware)
25441473e441SSteven Rostedt static const struct file_operations ftrace_enable_fops = {
2545f5ca233eSSteven Rostedt (Google) .open = tracing_open_file_tr,
25461473e441SSteven Rostedt .read = event_enable_read,
25471473e441SSteven Rostedt .write = event_enable_write,
2548f5ca233eSSteven Rostedt (Google) .release = tracing_release_file_tr,
25496038f373SArnd Bergmann .llseek = default_llseek,
25501473e441SSteven Rostedt };
25511473e441SSteven Rostedt
2552981d081eSSteven Rostedt static const struct file_operations ftrace_event_format_fops = {
25532a37a3dfSSteven Rostedt .open = trace_format_open,
25542a37a3dfSSteven Rostedt .read = seq_read,
25552a37a3dfSSteven Rostedt .llseek = seq_lseek,
25562a37a3dfSSteven Rostedt .release = seq_release,
2557981d081eSSteven Rostedt };
2558981d081eSSteven Rostedt
25595281ec83SArnd Bergmann #ifdef CONFIG_PERF_EVENTS
256023725aeeSPeter Zijlstra static const struct file_operations ftrace_event_id_fops = {
256123725aeeSPeter Zijlstra .read = event_id_read,
25626038f373SArnd Bergmann .llseek = default_llseek,
256323725aeeSPeter Zijlstra };
25645281ec83SArnd Bergmann #endif
256523725aeeSPeter Zijlstra
25667ce7e424STom Zanussi static const struct file_operations ftrace_event_filter_fops = {
2567f5ca233eSSteven Rostedt (Google) .open = tracing_open_file_tr,
25687ce7e424STom Zanussi .read = event_filter_read,
25697ce7e424STom Zanussi .write = event_filter_write,
2570f5ca233eSSteven Rostedt (Google) .release = tracing_release_file_tr,
25716038f373SArnd Bergmann .llseek = default_llseek,
25727ce7e424STom Zanussi };
25737ce7e424STom Zanussi
2574cfb180f3STom Zanussi static const struct file_operations ftrace_subsystem_filter_fops = {
2575e9dbfae5SSteven Rostedt .open = subsystem_open,
2576cfb180f3STom Zanussi .read = subsystem_filter_read,
2577cfb180f3STom Zanussi .write = subsystem_filter_write,
25786038f373SArnd Bergmann .llseek = default_llseek,
2579e9dbfae5SSteven Rostedt .release = subsystem_release,
2580cfb180f3STom Zanussi };
2581cfb180f3STom Zanussi
25828ae79a13SSteven Rostedt static const struct file_operations ftrace_system_enable_fops = {
258340ee4dffSSteven Rostedt .open = subsystem_open,
25848ae79a13SSteven Rostedt .read = system_enable_read,
25858ae79a13SSteven Rostedt .write = system_enable_write,
25866038f373SArnd Bergmann .llseek = default_llseek,
258740ee4dffSSteven Rostedt .release = subsystem_release,
25888ae79a13SSteven Rostedt };
25898ae79a13SSteven Rostedt
2590ae63b31eSSteven Rostedt static const struct file_operations ftrace_tr_enable_fops = {
2591ae63b31eSSteven Rostedt .open = system_tr_open,
2592ae63b31eSSteven Rostedt .read = system_enable_read,
2593ae63b31eSSteven Rostedt .write = system_enable_write,
2594ae63b31eSSteven Rostedt .llseek = default_llseek,
2595ae63b31eSSteven Rostedt .release = subsystem_release,
2596ae63b31eSSteven Rostedt };
2597ae63b31eSSteven Rostedt
2598139f8400STzvetomir Stoyanov (VMware) static const struct file_operations ftrace_show_header_page_fops = {
2599139f8400STzvetomir Stoyanov (VMware) .open = tracing_open_generic_tr,
2600139f8400STzvetomir Stoyanov (VMware) .read = show_header_page_file,
26016038f373SArnd Bergmann .llseek = default_llseek,
2602139f8400STzvetomir Stoyanov (VMware) .release = tracing_release_generic_tr,
2603139f8400STzvetomir Stoyanov (VMware) };
2604139f8400STzvetomir Stoyanov (VMware)
2605139f8400STzvetomir Stoyanov (VMware) static const struct file_operations ftrace_show_header_event_fops = {
2606139f8400STzvetomir Stoyanov (VMware) .open = tracing_open_generic_tr,
2607139f8400STzvetomir Stoyanov (VMware) .read = show_header_event_file,
2608139f8400STzvetomir Stoyanov (VMware) .llseek = default_llseek,
2609139f8400STzvetomir Stoyanov (VMware) .release = tracing_release_generic_tr,
2610d1b182a8SSteven Rostedt };
2611d1b182a8SSteven Rostedt
2612ae63b31eSSteven Rostedt static int
ftrace_event_open(struct inode * inode,struct file * file,const struct seq_operations * seq_ops)2613ae63b31eSSteven Rostedt ftrace_event_open(struct inode *inode, struct file *file,
2614ae63b31eSSteven Rostedt const struct seq_operations *seq_ops)
26151473e441SSteven Rostedt {
2616ae63b31eSSteven Rostedt struct seq_file *m;
2617ae63b31eSSteven Rostedt int ret;
26181473e441SSteven Rostedt
261917911ff3SSteven Rostedt (VMware) ret = security_locked_down(LOCKDOWN_TRACEFS);
262017911ff3SSteven Rostedt (VMware) if (ret)
262117911ff3SSteven Rostedt (VMware) return ret;
262217911ff3SSteven Rostedt (VMware)
2623ae63b31eSSteven Rostedt ret = seq_open(file, seq_ops);
2624ae63b31eSSteven Rostedt if (ret < 0)
2625ae63b31eSSteven Rostedt return ret;
2626ae63b31eSSteven Rostedt m = file->private_data;
2627ae63b31eSSteven Rostedt /* copy tr over to seq ops */
2628ae63b31eSSteven Rostedt m->private = inode->i_private;
26291473e441SSteven Rostedt
2630ae63b31eSSteven Rostedt return ret;
26311473e441SSteven Rostedt }
26321473e441SSteven Rostedt
ftrace_event_release(struct inode * inode,struct file * file)2633f77d09a3SAlexander Z Lam static int ftrace_event_release(struct inode *inode, struct file *file)
2634f77d09a3SAlexander Z Lam {
2635f77d09a3SAlexander Z Lam struct trace_array *tr = inode->i_private;
2636f77d09a3SAlexander Z Lam
2637f77d09a3SAlexander Z Lam trace_array_put(tr);
2638f77d09a3SAlexander Z Lam
2639f77d09a3SAlexander Z Lam return seq_release(inode, file);
2640f77d09a3SAlexander Z Lam }
2641f77d09a3SAlexander Z Lam
264215075cacSSteven Rostedt static int
ftrace_event_avail_open(struct inode * inode,struct file * file)264315075cacSSteven Rostedt ftrace_event_avail_open(struct inode *inode, struct file *file)
264415075cacSSteven Rostedt {
264515075cacSSteven Rostedt const struct seq_operations *seq_ops = &show_event_seq_ops;
264615075cacSSteven Rostedt
264717911ff3SSteven Rostedt (VMware) /* Checks for tracefs lockdown */
2648ae63b31eSSteven Rostedt return ftrace_event_open(inode, file, seq_ops);
264915075cacSSteven Rostedt }
265015075cacSSteven Rostedt
265115075cacSSteven Rostedt static int
ftrace_event_set_open(struct inode * inode,struct file * file)265215075cacSSteven Rostedt ftrace_event_set_open(struct inode *inode, struct file *file)
265315075cacSSteven Rostedt {
265415075cacSSteven Rostedt const struct seq_operations *seq_ops = &show_set_event_seq_ops;
2655ae63b31eSSteven Rostedt struct trace_array *tr = inode->i_private;
2656f77d09a3SAlexander Z Lam int ret;
2657f77d09a3SAlexander Z Lam
26588530dec6SSteven Rostedt (VMware) ret = tracing_check_open_get_tr(tr);
26598530dec6SSteven Rostedt (VMware) if (ret)
26608530dec6SSteven Rostedt (VMware) return ret;
266115075cacSSteven Rostedt
266215075cacSSteven Rostedt if ((file->f_mode & FMODE_WRITE) &&
266315075cacSSteven Rostedt (file->f_flags & O_TRUNC))
2664ae63b31eSSteven Rostedt ftrace_clear_events(tr);
266515075cacSSteven Rostedt
2666f77d09a3SAlexander Z Lam ret = ftrace_event_open(inode, file, seq_ops);
2667f77d09a3SAlexander Z Lam if (ret < 0)
2668f77d09a3SAlexander Z Lam trace_array_put(tr);
2669f77d09a3SAlexander Z Lam return ret;
267015075cacSSteven Rostedt }
267115075cacSSteven Rostedt
267249090107SSteven Rostedt (Red Hat) static int
ftrace_event_set_pid_open(struct inode * inode,struct file * file)267349090107SSteven Rostedt (Red Hat) ftrace_event_set_pid_open(struct inode *inode, struct file *file)
267449090107SSteven Rostedt (Red Hat) {
267549090107SSteven Rostedt (Red Hat) const struct seq_operations *seq_ops = &show_set_pid_seq_ops;
267649090107SSteven Rostedt (Red Hat) struct trace_array *tr = inode->i_private;
267749090107SSteven Rostedt (Red Hat) int ret;
267849090107SSteven Rostedt (Red Hat)
26798530dec6SSteven Rostedt (VMware) ret = tracing_check_open_get_tr(tr);
26808530dec6SSteven Rostedt (VMware) if (ret)
26818530dec6SSteven Rostedt (VMware) return ret;
268249090107SSteven Rostedt (Red Hat)
268349090107SSteven Rostedt (Red Hat) if ((file->f_mode & FMODE_WRITE) &&
268449090107SSteven Rostedt (Red Hat) (file->f_flags & O_TRUNC))
268527683626SSteven Rostedt (VMware) ftrace_clear_event_pids(tr, TRACE_PIDS);
268627683626SSteven Rostedt (VMware)
268727683626SSteven Rostedt (VMware) ret = ftrace_event_open(inode, file, seq_ops);
268827683626SSteven Rostedt (VMware) if (ret < 0)
268927683626SSteven Rostedt (VMware) trace_array_put(tr);
269027683626SSteven Rostedt (VMware) return ret;
269127683626SSteven Rostedt (VMware) }
269227683626SSteven Rostedt (VMware)
269327683626SSteven Rostedt (VMware) static int
ftrace_event_set_npid_open(struct inode * inode,struct file * file)269427683626SSteven Rostedt (VMware) ftrace_event_set_npid_open(struct inode *inode, struct file *file)
269527683626SSteven Rostedt (VMware) {
269627683626SSteven Rostedt (VMware) const struct seq_operations *seq_ops = &show_set_no_pid_seq_ops;
269727683626SSteven Rostedt (VMware) struct trace_array *tr = inode->i_private;
269827683626SSteven Rostedt (VMware) int ret;
269927683626SSteven Rostedt (VMware)
270027683626SSteven Rostedt (VMware) ret = tracing_check_open_get_tr(tr);
270127683626SSteven Rostedt (VMware) if (ret)
270227683626SSteven Rostedt (VMware) return ret;
270327683626SSteven Rostedt (VMware)
270427683626SSteven Rostedt (VMware) if ((file->f_mode & FMODE_WRITE) &&
270527683626SSteven Rostedt (VMware) (file->f_flags & O_TRUNC))
270627683626SSteven Rostedt (VMware) ftrace_clear_event_pids(tr, TRACE_NO_PIDS);
270749090107SSteven Rostedt (Red Hat)
270849090107SSteven Rostedt (Red Hat) ret = ftrace_event_open(inode, file, seq_ops);
270949090107SSteven Rostedt (Red Hat) if (ret < 0)
271049090107SSteven Rostedt (Red Hat) trace_array_put(tr);
271149090107SSteven Rostedt (Red Hat) return ret;
271249090107SSteven Rostedt (Red Hat) }
271349090107SSteven Rostedt (Red Hat)
2714ae63b31eSSteven Rostedt static struct event_subsystem *
create_new_subsystem(const char * name)2715ae63b31eSSteven Rostedt create_new_subsystem(const char *name)
27166ecc2d1cSSteven Rostedt {
27176ecc2d1cSSteven Rostedt struct event_subsystem *system;
27186ecc2d1cSSteven Rostedt
27196ecc2d1cSSteven Rostedt /* need to create new entry */
27206ecc2d1cSSteven Rostedt system = kmalloc(sizeof(*system), GFP_KERNEL);
2721ae63b31eSSteven Rostedt if (!system)
2722ae63b31eSSteven Rostedt return NULL;
27236ecc2d1cSSteven Rostedt
2724e9dbfae5SSteven Rostedt system->ref_count = 1;
27256e94a780SSteven Rostedt
27266e94a780SSteven Rostedt /* Only allocate if dynamic (kprobes and modules) */
272779ac6ef5SRasmus Villemoes system->name = kstrdup_const(name, GFP_KERNEL);
27286e94a780SSteven Rostedt if (!system->name)
27296e94a780SSteven Rostedt goto out_free;
27306ecc2d1cSSteven Rostedt
27318b372562STom Zanussi system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL);
2732ae63b31eSSteven Rostedt if (!system->filter)
2733ae63b31eSSteven Rostedt goto out_free;
2734ae63b31eSSteven Rostedt
2735ae63b31eSSteven Rostedt list_add(&system->list, &event_subsystems);
2736ae63b31eSSteven Rostedt
2737ae63b31eSSteven Rostedt return system;
2738ae63b31eSSteven Rostedt
2739ae63b31eSSteven Rostedt out_free:
274079ac6ef5SRasmus Villemoes kfree_const(system->name);
2741ae63b31eSSteven Rostedt kfree(system);
2742ae63b31eSSteven Rostedt return NULL;
27438b372562STom Zanussi }
27448b372562STom Zanussi
system_callback(const char * name,umode_t * mode,void ** data,const struct file_operations ** fops)27455ddd8baaSSteven Rostedt (Google) static int system_callback(const char *name, umode_t *mode, void **data,
27465790b1fbSSteven Rostedt (Google) const struct file_operations **fops)
27475790b1fbSSteven Rostedt (Google) {
27485790b1fbSSteven Rostedt (Google) if (strcmp(name, "filter") == 0)
27495790b1fbSSteven Rostedt (Google) *fops = &ftrace_subsystem_filter_fops;
27505790b1fbSSteven Rostedt (Google)
27515790b1fbSSteven Rostedt (Google) else if (strcmp(name, "enable") == 0)
27525790b1fbSSteven Rostedt (Google) *fops = &ftrace_system_enable_fops;
27535790b1fbSSteven Rostedt (Google)
27545790b1fbSSteven Rostedt (Google) else
27555790b1fbSSteven Rostedt (Google) return 0;
27565790b1fbSSteven Rostedt (Google)
27575790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_WRITE;
27585790b1fbSSteven Rostedt (Google) return 1;
27595790b1fbSSteven Rostedt (Google) }
27605790b1fbSSteven Rostedt (Google)
27615790b1fbSSteven Rostedt (Google) static struct eventfs_inode *
event_subsystem_dir(struct trace_array * tr,const char * name,struct trace_event_file * file,struct eventfs_inode * parent)2762ae63b31eSSteven Rostedt event_subsystem_dir(struct trace_array *tr, const char *name,
27635790b1fbSSteven Rostedt (Google) struct trace_event_file *file, struct eventfs_inode *parent)
2764ae63b31eSSteven Rostedt {
2765ba27d855SJakob Koschel struct event_subsystem *system, *iter;
27667967b3e0SSteven Rostedt (Red Hat) struct trace_subsystem_dir *dir;
27675790b1fbSSteven Rostedt (Google) struct eventfs_inode *ei;
27685790b1fbSSteven Rostedt (Google) int nr_entries;
27695790b1fbSSteven Rostedt (Google) static struct eventfs_entry system_entries[] = {
27705790b1fbSSteven Rostedt (Google) {
27715790b1fbSSteven Rostedt (Google) .name = "filter",
27725790b1fbSSteven Rostedt (Google) .callback = system_callback,
27735790b1fbSSteven Rostedt (Google) },
27745790b1fbSSteven Rostedt (Google) {
27755790b1fbSSteven Rostedt (Google) .name = "enable",
27765790b1fbSSteven Rostedt (Google) .callback = system_callback,
27775790b1fbSSteven Rostedt (Google) }
27785790b1fbSSteven Rostedt (Google) };
2779ae63b31eSSteven Rostedt
2780ae63b31eSSteven Rostedt /* First see if we did not already create this dir */
2781ae63b31eSSteven Rostedt list_for_each_entry(dir, &tr->systems, list) {
2782ae63b31eSSteven Rostedt system = dir->subsystem;
2783ae63b31eSSteven Rostedt if (strcmp(system->name, name) == 0) {
2784ae63b31eSSteven Rostedt dir->nr_events++;
2785ae63b31eSSteven Rostedt file->system = dir;
27865790b1fbSSteven Rostedt (Google) return dir->ei;
2787ae63b31eSSteven Rostedt }
2788ae63b31eSSteven Rostedt }
2789ae63b31eSSteven Rostedt
2790ae63b31eSSteven Rostedt /* Now see if the system itself exists. */
2791ba27d855SJakob Koschel system = NULL;
2792ba27d855SJakob Koschel list_for_each_entry(iter, &event_subsystems, list) {
2793ba27d855SJakob Koschel if (strcmp(iter->name, name) == 0) {
2794ba27d855SJakob Koschel system = iter;
2795ae63b31eSSteven Rostedt break;
2796ae63b31eSSteven Rostedt }
2797ba27d855SJakob Koschel }
2798ae63b31eSSteven Rostedt
2799ae63b31eSSteven Rostedt dir = kmalloc(sizeof(*dir), GFP_KERNEL);
2800ae63b31eSSteven Rostedt if (!dir)
2801ae63b31eSSteven Rostedt goto out_fail;
2802ae63b31eSSteven Rostedt
2803ae63b31eSSteven Rostedt if (!system) {
2804ae63b31eSSteven Rostedt system = create_new_subsystem(name);
2805ae63b31eSSteven Rostedt if (!system)
2806ae63b31eSSteven Rostedt goto out_free;
2807ae63b31eSSteven Rostedt } else
2808ae63b31eSSteven Rostedt __get_system(system);
2809ae63b31eSSteven Rostedt
28105790b1fbSSteven Rostedt (Google) /* ftrace only has directories no files */
28115790b1fbSSteven Rostedt (Google) if (strcmp(name, "ftrace") == 0)
28125790b1fbSSteven Rostedt (Google) nr_entries = 0;
28135790b1fbSSteven Rostedt (Google) else
28145790b1fbSSteven Rostedt (Google) nr_entries = ARRAY_SIZE(system_entries);
28155790b1fbSSteven Rostedt (Google)
28165790b1fbSSteven Rostedt (Google) ei = eventfs_create_dir(name, parent, system_entries, nr_entries, dir);
28175264a2f4SDan Carpenter if (IS_ERR(ei)) {
28183448bac3SFabian Frederick pr_warn("Failed to create system directory %s\n", name);
2819ae63b31eSSteven Rostedt __put_system(system);
2820ae63b31eSSteven Rostedt goto out_free;
2821ae63b31eSSteven Rostedt }
2822ae63b31eSSteven Rostedt
28235790b1fbSSteven Rostedt (Google) dir->ei = ei;
2824ae63b31eSSteven Rostedt dir->tr = tr;
2825ae63b31eSSteven Rostedt dir->ref_count = 1;
2826ae63b31eSSteven Rostedt dir->nr_events = 1;
2827ae63b31eSSteven Rostedt dir->subsystem = system;
2828ae63b31eSSteven Rostedt file->system = dir;
2829ae63b31eSSteven Rostedt
2830ae63b31eSSteven Rostedt list_add(&dir->list, &tr->systems);
2831ae63b31eSSteven Rostedt
28325790b1fbSSteven Rostedt (Google) return dir->ei;
2833ae63b31eSSteven Rostedt
2834ae63b31eSSteven Rostedt out_free:
2835ae63b31eSSteven Rostedt kfree(dir);
2836ae63b31eSSteven Rostedt out_fail:
2837ae63b31eSSteven Rostedt /* Only print this message if failed on memory allocation */
2838ae63b31eSSteven Rostedt if (!dir || !system)
28393448bac3SFabian Frederick pr_warn("No memory to create event subsystem %s\n", name);
2840ae63b31eSSteven Rostedt return NULL;
28416ecc2d1cSSteven Rostedt }
28426ecc2d1cSSteven Rostedt
28431473e441SSteven Rostedt static int
event_define_fields(struct trace_event_call * call)2844ac343da7SMasami Hiramatsu event_define_fields(struct trace_event_call *call)
2845ac343da7SMasami Hiramatsu {
2846ac343da7SMasami Hiramatsu struct list_head *head;
2847ac343da7SMasami Hiramatsu int ret = 0;
2848ac343da7SMasami Hiramatsu
2849ac343da7SMasami Hiramatsu /*
2850ac343da7SMasami Hiramatsu * Other events may have the same class. Only update
2851ac343da7SMasami Hiramatsu * the fields if they are not already defined.
2852ac343da7SMasami Hiramatsu */
2853ac343da7SMasami Hiramatsu head = trace_get_fields(call);
2854ac343da7SMasami Hiramatsu if (list_empty(head)) {
2855ac343da7SMasami Hiramatsu struct trace_event_fields *field = call->class->fields_array;
2856ac343da7SMasami Hiramatsu unsigned int offset = sizeof(struct trace_entry);
2857ac343da7SMasami Hiramatsu
2858ac343da7SMasami Hiramatsu for (; field->type; field++) {
2859ac343da7SMasami Hiramatsu if (field->type == TRACE_FUNCTION_TYPE) {
2860ac343da7SMasami Hiramatsu field->define_fields(call);
2861ac343da7SMasami Hiramatsu break;
2862ac343da7SMasami Hiramatsu }
2863ac343da7SMasami Hiramatsu
2864ac343da7SMasami Hiramatsu offset = ALIGN(offset, field->align);
2865b6c7abd1SYafang Shao ret = trace_define_field_ext(call, field->type, field->name,
2866ac343da7SMasami Hiramatsu offset, field->size,
2867b6c7abd1SYafang Shao field->is_signed, field->filter_type,
2868afd2627fSSteven Rostedt field->len, field->needs_test);
2869ac343da7SMasami Hiramatsu if (WARN_ON_ONCE(ret)) {
2870ac343da7SMasami Hiramatsu pr_err("error code is %d\n", ret);
2871ac343da7SMasami Hiramatsu break;
2872ac343da7SMasami Hiramatsu }
2873ac343da7SMasami Hiramatsu
2874ac343da7SMasami Hiramatsu offset += field->size;
2875ac343da7SMasami Hiramatsu }
2876ac343da7SMasami Hiramatsu }
2877ac343da7SMasami Hiramatsu
2878ac343da7SMasami Hiramatsu return ret;
2879ac343da7SMasami Hiramatsu }
2880ac343da7SMasami Hiramatsu
event_callback(const char * name,umode_t * mode,void ** data,const struct file_operations ** fops)28815790b1fbSSteven Rostedt (Google) static int event_callback(const char *name, umode_t *mode, void **data,
28825790b1fbSSteven Rostedt (Google) const struct file_operations **fops)
28835790b1fbSSteven Rostedt (Google) {
28845790b1fbSSteven Rostedt (Google) struct trace_event_file *file = *data;
28855790b1fbSSteven Rostedt (Google) struct trace_event_call *call = file->event_call;
28865790b1fbSSteven Rostedt (Google)
28875790b1fbSSteven Rostedt (Google) if (strcmp(name, "format") == 0) {
28885790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_READ;
28895790b1fbSSteven Rostedt (Google) *fops = &ftrace_event_format_fops;
28905790b1fbSSteven Rostedt (Google) return 1;
28915790b1fbSSteven Rostedt (Google) }
28925790b1fbSSteven Rostedt (Google)
28935790b1fbSSteven Rostedt (Google) /*
28945790b1fbSSteven Rostedt (Google) * Only event directories that can be enabled should have
28955790b1fbSSteven Rostedt (Google) * triggers or filters, with the exception of the "print"
28965790b1fbSSteven Rostedt (Google) * event that can have a "trigger" file.
28975790b1fbSSteven Rostedt (Google) */
28985790b1fbSSteven Rostedt (Google) if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) {
28995790b1fbSSteven Rostedt (Google) if (call->class->reg && strcmp(name, "enable") == 0) {
29005790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_WRITE;
29015790b1fbSSteven Rostedt (Google) *fops = &ftrace_enable_fops;
29025790b1fbSSteven Rostedt (Google) return 1;
29035790b1fbSSteven Rostedt (Google) }
29045790b1fbSSteven Rostedt (Google)
29055790b1fbSSteven Rostedt (Google) if (strcmp(name, "filter") == 0) {
29065790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_WRITE;
29075790b1fbSSteven Rostedt (Google) *fops = &ftrace_event_filter_fops;
29085790b1fbSSteven Rostedt (Google) return 1;
29095790b1fbSSteven Rostedt (Google) }
29105790b1fbSSteven Rostedt (Google) }
29115790b1fbSSteven Rostedt (Google)
29125790b1fbSSteven Rostedt (Google) if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE) ||
29135790b1fbSSteven Rostedt (Google) strcmp(trace_event_name(call), "print") == 0) {
29145790b1fbSSteven Rostedt (Google) if (strcmp(name, "trigger") == 0) {
29155790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_WRITE;
29165790b1fbSSteven Rostedt (Google) *fops = &event_trigger_fops;
29175790b1fbSSteven Rostedt (Google) return 1;
29185790b1fbSSteven Rostedt (Google) }
29195790b1fbSSteven Rostedt (Google) }
29205790b1fbSSteven Rostedt (Google)
29215790b1fbSSteven Rostedt (Google) #ifdef CONFIG_PERF_EVENTS
29225790b1fbSSteven Rostedt (Google) if (call->event.type && call->class->reg &&
29235790b1fbSSteven Rostedt (Google) strcmp(name, "id") == 0) {
29245790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_READ;
29255790b1fbSSteven Rostedt (Google) *data = (void *)(long)call->event.type;
29265790b1fbSSteven Rostedt (Google) *fops = &ftrace_event_id_fops;
29275790b1fbSSteven Rostedt (Google) return 1;
29285790b1fbSSteven Rostedt (Google) }
29295790b1fbSSteven Rostedt (Google) #endif
29305790b1fbSSteven Rostedt (Google)
29315790b1fbSSteven Rostedt (Google) #ifdef CONFIG_HIST_TRIGGERS
29325790b1fbSSteven Rostedt (Google) if (strcmp(name, "hist") == 0) {
29335790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_READ;
29345790b1fbSSteven Rostedt (Google) *fops = &event_hist_fops;
29355790b1fbSSteven Rostedt (Google) return 1;
29365790b1fbSSteven Rostedt (Google) }
29375790b1fbSSteven Rostedt (Google) #endif
29385790b1fbSSteven Rostedt (Google) #ifdef CONFIG_HIST_TRIGGERS_DEBUG
29395790b1fbSSteven Rostedt (Google) if (strcmp(name, "hist_debug") == 0) {
29405790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_READ;
29415790b1fbSSteven Rostedt (Google) *fops = &event_hist_debug_fops;
29425790b1fbSSteven Rostedt (Google) return 1;
29435790b1fbSSteven Rostedt (Google) }
29445790b1fbSSteven Rostedt (Google) #endif
29455790b1fbSSteven Rostedt (Google) #ifdef CONFIG_TRACE_EVENT_INJECT
29465790b1fbSSteven Rostedt (Google) if (call->event.type && call->class->reg &&
29475790b1fbSSteven Rostedt (Google) strcmp(name, "inject") == 0) {
29485790b1fbSSteven Rostedt (Google) *mode = 0200;
29495790b1fbSSteven Rostedt (Google) *fops = &event_inject_fops;
29505790b1fbSSteven Rostedt (Google) return 1;
29515790b1fbSSteven Rostedt (Google) }
29525790b1fbSSteven Rostedt (Google) #endif
29535790b1fbSSteven Rostedt (Google) return 0;
29545790b1fbSSteven Rostedt (Google) }
29555790b1fbSSteven Rostedt (Google)
2956b63db58eSSteven Rostedt (Google) /* The file is incremented on creation and freeing the enable file decrements it */
event_release(const char * name,void * data)2957b63db58eSSteven Rostedt (Google) static void event_release(const char *name, void *data)
2958b63db58eSSteven Rostedt (Google) {
2959b63db58eSSteven Rostedt (Google) struct trace_event_file *file = data;
2960b63db58eSSteven Rostedt (Google)
2961b63db58eSSteven Rostedt (Google) event_file_put(file);
2962b63db58eSSteven Rostedt (Google) }
2963b63db58eSSteven Rostedt (Google)
2964ac343da7SMasami Hiramatsu static int
event_create_dir(struct eventfs_inode * parent,struct trace_event_file * file)29655790b1fbSSteven Rostedt (Google) event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
29661473e441SSteven Rostedt {
29672425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call = file->event_call;
2968ae63b31eSSteven Rostedt struct trace_array *tr = file->tr;
29695790b1fbSSteven Rostedt (Google) struct eventfs_inode *e_events;
29705790b1fbSSteven Rostedt (Google) struct eventfs_inode *ei;
2971de7b2973SMathieu Desnoyers const char *name;
29725790b1fbSSteven Rostedt (Google) int nr_entries;
2973fd994989SSteven Rostedt int ret;
29745790b1fbSSteven Rostedt (Google) static struct eventfs_entry event_entries[] = {
29755790b1fbSSteven Rostedt (Google) {
29765790b1fbSSteven Rostedt (Google) .name = "enable",
29775790b1fbSSteven Rostedt (Google) .callback = event_callback,
2978b63db58eSSteven Rostedt (Google) .release = event_release,
29795790b1fbSSteven Rostedt (Google) },
29805790b1fbSSteven Rostedt (Google) {
29815790b1fbSSteven Rostedt (Google) .name = "filter",
29825790b1fbSSteven Rostedt (Google) .callback = event_callback,
29835790b1fbSSteven Rostedt (Google) },
29845790b1fbSSteven Rostedt (Google) {
29855790b1fbSSteven Rostedt (Google) .name = "trigger",
29865790b1fbSSteven Rostedt (Google) .callback = event_callback,
29875790b1fbSSteven Rostedt (Google) },
29885790b1fbSSteven Rostedt (Google) {
29895790b1fbSSteven Rostedt (Google) .name = "format",
29905790b1fbSSteven Rostedt (Google) .callback = event_callback,
29915790b1fbSSteven Rostedt (Google) },
29925790b1fbSSteven Rostedt (Google) #ifdef CONFIG_PERF_EVENTS
29935790b1fbSSteven Rostedt (Google) {
29945790b1fbSSteven Rostedt (Google) .name = "id",
29955790b1fbSSteven Rostedt (Google) .callback = event_callback,
29965790b1fbSSteven Rostedt (Google) },
29975790b1fbSSteven Rostedt (Google) #endif
29985790b1fbSSteven Rostedt (Google) #ifdef CONFIG_HIST_TRIGGERS
29995790b1fbSSteven Rostedt (Google) {
30005790b1fbSSteven Rostedt (Google) .name = "hist",
30015790b1fbSSteven Rostedt (Google) .callback = event_callback,
30025790b1fbSSteven Rostedt (Google) },
30035790b1fbSSteven Rostedt (Google) #endif
30045790b1fbSSteven Rostedt (Google) #ifdef CONFIG_HIST_TRIGGERS_DEBUG
30055790b1fbSSteven Rostedt (Google) {
30065790b1fbSSteven Rostedt (Google) .name = "hist_debug",
30075790b1fbSSteven Rostedt (Google) .callback = event_callback,
30085790b1fbSSteven Rostedt (Google) },
30095790b1fbSSteven Rostedt (Google) #endif
30105790b1fbSSteven Rostedt (Google) #ifdef CONFIG_TRACE_EVENT_INJECT
30115790b1fbSSteven Rostedt (Google) {
30125790b1fbSSteven Rostedt (Google) .name = "inject",
30135790b1fbSSteven Rostedt (Google) .callback = event_callback,
30145790b1fbSSteven Rostedt (Google) },
30155790b1fbSSteven Rostedt (Google) #endif
30165790b1fbSSteven Rostedt (Google) };
30171473e441SSteven Rostedt
30186ecc2d1cSSteven Rostedt /*
30196ecc2d1cSSteven Rostedt * If the trace point header did not define TRACE_SYSTEM
3020ee41106aSSteven Rostedt (Google) * then the system would be called "TRACE_SYSTEM". This should
3021ee41106aSSteven Rostedt (Google) * never happen.
30226ecc2d1cSSteven Rostedt */
3023ee41106aSSteven Rostedt (Google) if (WARN_ON_ONCE(strcmp(call->class->system, TRACE_SYSTEM) == 0))
3024ee41106aSSteven Rostedt (Google) return -ENODEV;
3025ee41106aSSteven Rostedt (Google)
30265790b1fbSSteven Rostedt (Google) e_events = event_subsystem_dir(tr, call->class->system, file, parent);
30275790b1fbSSteven Rostedt (Google) if (!e_events)
3028ae63b31eSSteven Rostedt return -ENOMEM;
30296ecc2d1cSSteven Rostedt
30305790b1fbSSteven Rostedt (Google) nr_entries = ARRAY_SIZE(event_entries);
30315790b1fbSSteven Rostedt (Google)
3032687fcc4aSSteven Rostedt (Red Hat) name = trace_event_name(call);
30335790b1fbSSteven Rostedt (Google) ei = eventfs_create_dir(name, e_events, event_entries, nr_entries, file);
30345790b1fbSSteven Rostedt (Google) if (IS_ERR(ei)) {
30358434dc93SSteven Rostedt (Red Hat) pr_warn("Could not create tracefs '%s' directory\n", name);
30361473e441SSteven Rostedt return -1;
30371473e441SSteven Rostedt }
30381473e441SSteven Rostedt
30395790b1fbSSteven Rostedt (Google) file->ei = ei;
304023725aeeSPeter Zijlstra
3041ac343da7SMasami Hiramatsu ret = event_define_fields(call);
3042cf027f64STom Zanussi if (ret < 0) {
3043ac343da7SMasami Hiramatsu pr_warn("Could not initialize trace point events/%s\n", name);
3044ac343da7SMasami Hiramatsu return ret;
30452e33af02SSteven Rostedt }
30467ce7e424STom Zanussi
3047b63db58eSSteven Rostedt (Google) /* Gets decremented on freeing of the "enable" file */
3048b63db58eSSteven Rostedt (Google) event_file_get(file);
3049b63db58eSSteven Rostedt (Google)
30501473e441SSteven Rostedt return 0;
30511473e441SSteven Rostedt }
30521473e441SSteven Rostedt
remove_event_from_tracers(struct trace_event_call * call)30532425bcb9SSteven Rostedt (Red Hat) static void remove_event_from_tracers(struct trace_event_call *call)
3054ae63b31eSSteven Rostedt {
30557f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
3056ae63b31eSSteven Rostedt struct trace_array *tr;
3057ae63b31eSSteven Rostedt
3058ae63b31eSSteven Rostedt do_for_each_event_file_safe(tr, file) {
3059ae63b31eSSteven Rostedt if (file->event_call != call)
3060ae63b31eSSteven Rostedt continue;
3061ae63b31eSSteven Rostedt
3062f6a84bdcSOleg Nesterov remove_event_file_dir(file);
3063ae63b31eSSteven Rostedt /*
3064ae63b31eSSteven Rostedt * The do_for_each_event_file_safe() is
3065ae63b31eSSteven Rostedt * a double loop. After finding the call for this
3066ae63b31eSSteven Rostedt * trace_array, we use break to jump to the next
3067ae63b31eSSteven Rostedt * trace_array.
3068ae63b31eSSteven Rostedt */
3069ae63b31eSSteven Rostedt break;
3070ae63b31eSSteven Rostedt } while_for_each_event_file();
3071ae63b31eSSteven Rostedt }
3072ae63b31eSSteven Rostedt
event_remove(struct trace_event_call * call)30732425bcb9SSteven Rostedt (Red Hat) static void event_remove(struct trace_event_call *call)
30748781915aSEzequiel Garcia {
3075ae63b31eSSteven Rostedt struct trace_array *tr;
30767f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
3077ae63b31eSSteven Rostedt
3078ae63b31eSSteven Rostedt do_for_each_event_file(tr, file) {
3079ae63b31eSSteven Rostedt if (file->event_call != call)
3080ae63b31eSSteven Rostedt continue;
3081065e63f9SSteven Rostedt (VMware)
3082065e63f9SSteven Rostedt (VMware) if (file->flags & EVENT_FILE_FL_WAS_ENABLED)
3083065e63f9SSteven Rostedt (VMware) tr->clear_trace = true;
3084065e63f9SSteven Rostedt (VMware)
3085ae63b31eSSteven Rostedt ftrace_event_enable_disable(file, 0);
3086ae63b31eSSteven Rostedt /*
3087ae63b31eSSteven Rostedt * The do_for_each_event_file() is
3088ae63b31eSSteven Rostedt * a double loop. After finding the call for this
3089ae63b31eSSteven Rostedt * trace_array, we use break to jump to the next
3090ae63b31eSSteven Rostedt * trace_array.
3091ae63b31eSSteven Rostedt */
3092ae63b31eSSteven Rostedt break;
3093ae63b31eSSteven Rostedt } while_for_each_event_file();
3094ae63b31eSSteven Rostedt
30958781915aSEzequiel Garcia if (call->event.funcs)
30969023c930SSteven Rostedt (Red Hat) __unregister_trace_event(&call->event);
3097ae63b31eSSteven Rostedt remove_event_from_tracers(call);
30988781915aSEzequiel Garcia list_del(&call->list);
30998781915aSEzequiel Garcia }
31008781915aSEzequiel Garcia
event_init(struct trace_event_call * call)31012425bcb9SSteven Rostedt (Red Hat) static int event_init(struct trace_event_call *call)
31028781915aSEzequiel Garcia {
31038781915aSEzequiel Garcia int ret = 0;
3104de7b2973SMathieu Desnoyers const char *name;
31058781915aSEzequiel Garcia
3106687fcc4aSSteven Rostedt (Red Hat) name = trace_event_name(call);
3107de7b2973SMathieu Desnoyers if (WARN_ON(!name))
31088781915aSEzequiel Garcia return -EINVAL;
31098781915aSEzequiel Garcia
31108781915aSEzequiel Garcia if (call->class->raw_init) {
31118781915aSEzequiel Garcia ret = call->class->raw_init(call);
31128781915aSEzequiel Garcia if (ret < 0 && ret != -ENOSYS)
31133448bac3SFabian Frederick pr_warn("Could not initialize trace events/%s\n", name);
31148781915aSEzequiel Garcia }
31158781915aSEzequiel Garcia
31168781915aSEzequiel Garcia return ret;
31178781915aSEzequiel Garcia }
31188781915aSEzequiel Garcia
311967ead0a6SLi Zefan static int
__register_event(struct trace_event_call * call,struct module * mod)31202425bcb9SSteven Rostedt (Red Hat) __register_event(struct trace_event_call *call, struct module *mod)
3121bd1a5c84SMasami Hiramatsu {
3122bd1a5c84SMasami Hiramatsu int ret;
31236d723736SSteven Rostedt
31248781915aSEzequiel Garcia ret = event_init(call);
31258781915aSEzequiel Garcia if (ret < 0)
3126bd1a5c84SMasami Hiramatsu return ret;
3127701970b3SSteven Rostedt
312888f70d75SMasami Hiramatsu list_add(&call->list, &ftrace_events);
31291d18538eSSteven Rostedt (VMware) if (call->flags & TRACE_EVENT_FL_DYNAMIC)
31301d18538eSSteven Rostedt (VMware) atomic_set(&call->refcnt, 0);
31311d18538eSSteven Rostedt (VMware) else
31321d18538eSSteven Rostedt (VMware) call->module = mod;
313388f70d75SMasami Hiramatsu
3134ae63b31eSSteven Rostedt return 0;
3135bd1a5c84SMasami Hiramatsu }
3136bd1a5c84SMasami Hiramatsu
eval_replace(char * ptr,struct trace_eval_map * map,int len)313767ec0d85SJeremy Linton static char *eval_replace(char *ptr, struct trace_eval_map *map, int len)
31380c564a53SSteven Rostedt (Red Hat) {
31390c564a53SSteven Rostedt (Red Hat) int rlen;
31400c564a53SSteven Rostedt (Red Hat) int elen;
31410c564a53SSteven Rostedt (Red Hat)
314267ec0d85SJeremy Linton /* Find the length of the eval value as a string */
314300f4b652SJeremy Linton elen = snprintf(ptr, 0, "%ld", map->eval_value);
31440c564a53SSteven Rostedt (Red Hat) /* Make sure there's enough room to replace the string with the value */
31450c564a53SSteven Rostedt (Red Hat) if (len < elen)
31460c564a53SSteven Rostedt (Red Hat) return NULL;
31470c564a53SSteven Rostedt (Red Hat)
314800f4b652SJeremy Linton snprintf(ptr, elen + 1, "%ld", map->eval_value);
31490c564a53SSteven Rostedt (Red Hat)
31500c564a53SSteven Rostedt (Red Hat) /* Get the rest of the string of ptr */
31510c564a53SSteven Rostedt (Red Hat) rlen = strlen(ptr + len);
31520c564a53SSteven Rostedt (Red Hat) memmove(ptr + elen, ptr + len, rlen);
31530c564a53SSteven Rostedt (Red Hat) /* Make sure we end the new string */
31540c564a53SSteven Rostedt (Red Hat) ptr[elen + rlen] = 0;
31550c564a53SSteven Rostedt (Red Hat)
31560c564a53SSteven Rostedt (Red Hat) return ptr + elen;
31570c564a53SSteven Rostedt (Red Hat) }
31580c564a53SSteven Rostedt (Red Hat)
update_event_printk(struct trace_event_call * call,struct trace_eval_map * map)31592425bcb9SSteven Rostedt (Red Hat) static void update_event_printk(struct trace_event_call *call,
316000f4b652SJeremy Linton struct trace_eval_map *map)
31610c564a53SSteven Rostedt (Red Hat) {
31620c564a53SSteven Rostedt (Red Hat) char *ptr;
31630c564a53SSteven Rostedt (Red Hat) int quote = 0;
316400f4b652SJeremy Linton int len = strlen(map->eval_string);
31650c564a53SSteven Rostedt (Red Hat)
31660c564a53SSteven Rostedt (Red Hat) for (ptr = call->print_fmt; *ptr; ptr++) {
31670c564a53SSteven Rostedt (Red Hat) if (*ptr == '\\') {
31680c564a53SSteven Rostedt (Red Hat) ptr++;
31690c564a53SSteven Rostedt (Red Hat) /* paranoid */
31700c564a53SSteven Rostedt (Red Hat) if (!*ptr)
31710c564a53SSteven Rostedt (Red Hat) break;
31720c564a53SSteven Rostedt (Red Hat) continue;
31730c564a53SSteven Rostedt (Red Hat) }
31740c564a53SSteven Rostedt (Red Hat) if (*ptr == '"') {
31750c564a53SSteven Rostedt (Red Hat) quote ^= 1;
31760c564a53SSteven Rostedt (Red Hat) continue;
31770c564a53SSteven Rostedt (Red Hat) }
31780c564a53SSteven Rostedt (Red Hat) if (quote)
31790c564a53SSteven Rostedt (Red Hat) continue;
31800c564a53SSteven Rostedt (Red Hat) if (isdigit(*ptr)) {
31810c564a53SSteven Rostedt (Red Hat) /* skip numbers */
31820c564a53SSteven Rostedt (Red Hat) do {
31830c564a53SSteven Rostedt (Red Hat) ptr++;
31840c564a53SSteven Rostedt (Red Hat) /* Check for alpha chars like ULL */
31850c564a53SSteven Rostedt (Red Hat) } while (isalnum(*ptr));
31863193899dSSteven Rostedt (Red Hat) if (!*ptr)
31873193899dSSteven Rostedt (Red Hat) break;
31880c564a53SSteven Rostedt (Red Hat) /*
31890c564a53SSteven Rostedt (Red Hat) * A number must have some kind of delimiter after
31900c564a53SSteven Rostedt (Red Hat) * it, and we can ignore that too.
31910c564a53SSteven Rostedt (Red Hat) */
31920c564a53SSteven Rostedt (Red Hat) continue;
31930c564a53SSteven Rostedt (Red Hat) }
31940c564a53SSteven Rostedt (Red Hat) if (isalpha(*ptr) || *ptr == '_') {
319500f4b652SJeremy Linton if (strncmp(map->eval_string, ptr, len) == 0 &&
31960c564a53SSteven Rostedt (Red Hat) !isalnum(ptr[len]) && ptr[len] != '_') {
319767ec0d85SJeremy Linton ptr = eval_replace(ptr, map, len);
319867ec0d85SJeremy Linton /* enum/sizeof string smaller than value */
31990c564a53SSteven Rostedt (Red Hat) if (WARN_ON_ONCE(!ptr))
32000c564a53SSteven Rostedt (Red Hat) return;
32010c564a53SSteven Rostedt (Red Hat) /*
320267ec0d85SJeremy Linton * No need to decrement here, as eval_replace()
32030c564a53SSteven Rostedt (Red Hat) * returns the pointer to the character passed
320467ec0d85SJeremy Linton * the eval, and two evals can not be placed
32050c564a53SSteven Rostedt (Red Hat) * back to back without something in between.
32060c564a53SSteven Rostedt (Red Hat) * We can skip that something in between.
32070c564a53SSteven Rostedt (Red Hat) */
32080c564a53SSteven Rostedt (Red Hat) continue;
32090c564a53SSteven Rostedt (Red Hat) }
32100c564a53SSteven Rostedt (Red Hat) skip_more:
32110c564a53SSteven Rostedt (Red Hat) do {
32120c564a53SSteven Rostedt (Red Hat) ptr++;
32130c564a53SSteven Rostedt (Red Hat) } while (isalnum(*ptr) || *ptr == '_');
32143193899dSSteven Rostedt (Red Hat) if (!*ptr)
32153193899dSSteven Rostedt (Red Hat) break;
32160c564a53SSteven Rostedt (Red Hat) /*
32170c564a53SSteven Rostedt (Red Hat) * If what comes after this variable is a '.' or
32180c564a53SSteven Rostedt (Red Hat) * '->' then we can continue to ignore that string.
32190c564a53SSteven Rostedt (Red Hat) */
32200c564a53SSteven Rostedt (Red Hat) if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) {
32210c564a53SSteven Rostedt (Red Hat) ptr += *ptr == '.' ? 1 : 2;
32223193899dSSteven Rostedt (Red Hat) if (!*ptr)
32233193899dSSteven Rostedt (Red Hat) break;
32240c564a53SSteven Rostedt (Red Hat) goto skip_more;
32250c564a53SSteven Rostedt (Red Hat) }
32260c564a53SSteven Rostedt (Red Hat) /*
32270c564a53SSteven Rostedt (Red Hat) * Once again, we can skip the delimiter that came
32280c564a53SSteven Rostedt (Red Hat) * after the string.
32290c564a53SSteven Rostedt (Red Hat) */
32300c564a53SSteven Rostedt (Red Hat) continue;
32310c564a53SSteven Rostedt (Red Hat) }
32320c564a53SSteven Rostedt (Red Hat) }
32330c564a53SSteven Rostedt (Red Hat) }
32340c564a53SSteven Rostedt (Red Hat)
add_str_to_module(struct module * module,char * str)3235795301d3SSteven Rostedt (Google) static void add_str_to_module(struct module *module, char *str)
3236795301d3SSteven Rostedt (Google) {
3237795301d3SSteven Rostedt (Google) struct module_string *modstr;
3238795301d3SSteven Rostedt (Google)
3239795301d3SSteven Rostedt (Google) modstr = kmalloc(sizeof(*modstr), GFP_KERNEL);
3240795301d3SSteven Rostedt (Google)
3241795301d3SSteven Rostedt (Google) /*
3242795301d3SSteven Rostedt (Google) * If we failed to allocate memory here, then we'll just
3243795301d3SSteven Rostedt (Google) * let the str memory leak when the module is removed.
3244795301d3SSteven Rostedt (Google) * If this fails to allocate, there's worse problems than
3245795301d3SSteven Rostedt (Google) * a leaked string on module removal.
3246795301d3SSteven Rostedt (Google) */
3247795301d3SSteven Rostedt (Google) if (WARN_ON_ONCE(!modstr))
3248795301d3SSteven Rostedt (Google) return;
3249795301d3SSteven Rostedt (Google)
3250795301d3SSteven Rostedt (Google) modstr->module = module;
3251795301d3SSteven Rostedt (Google) modstr->str = str;
3252795301d3SSteven Rostedt (Google)
3253795301d3SSteven Rostedt (Google) list_add(&modstr->next, &module_strings);
3254795301d3SSteven Rostedt (Google) }
3255795301d3SSteven Rostedt (Google)
update_event_fields(struct trace_event_call * call,struct trace_eval_map * map)3256b3bc8547SSteven Rostedt (Google) static void update_event_fields(struct trace_event_call *call,
3257b3bc8547SSteven Rostedt (Google) struct trace_eval_map *map)
3258b3bc8547SSteven Rostedt (Google) {
3259b3bc8547SSteven Rostedt (Google) struct ftrace_event_field *field;
3260b3bc8547SSteven Rostedt (Google) struct list_head *head;
3261b3bc8547SSteven Rostedt (Google) char *ptr;
3262795301d3SSteven Rostedt (Google) char *str;
3263b3bc8547SSteven Rostedt (Google) int len = strlen(map->eval_string);
3264b3bc8547SSteven Rostedt (Google)
3265795301d3SSteven Rostedt (Google) /* Dynamic events should never have field maps */
3266795301d3SSteven Rostedt (Google) if (WARN_ON_ONCE(call->flags & TRACE_EVENT_FL_DYNAMIC))
3267795301d3SSteven Rostedt (Google) return;
3268795301d3SSteven Rostedt (Google)
3269b3bc8547SSteven Rostedt (Google) head = trace_get_fields(call);
3270b3bc8547SSteven Rostedt (Google) list_for_each_entry(field, head, link) {
3271b3bc8547SSteven Rostedt (Google) ptr = strchr(field->type, '[');
3272b3bc8547SSteven Rostedt (Google) if (!ptr)
3273b3bc8547SSteven Rostedt (Google) continue;
3274b3bc8547SSteven Rostedt (Google) ptr++;
3275b3bc8547SSteven Rostedt (Google)
3276b3bc8547SSteven Rostedt (Google) if (!isalpha(*ptr) && *ptr != '_')
3277b3bc8547SSteven Rostedt (Google) continue;
3278b3bc8547SSteven Rostedt (Google)
3279b3bc8547SSteven Rostedt (Google) if (strncmp(map->eval_string, ptr, len) != 0)
3280b3bc8547SSteven Rostedt (Google) continue;
3281b3bc8547SSteven Rostedt (Google)
3282795301d3SSteven Rostedt (Google) str = kstrdup(field->type, GFP_KERNEL);
3283795301d3SSteven Rostedt (Google) if (WARN_ON_ONCE(!str))
3284795301d3SSteven Rostedt (Google) return;
3285795301d3SSteven Rostedt (Google) ptr = str + (ptr - field->type);
3286b3bc8547SSteven Rostedt (Google) ptr = eval_replace(ptr, map, len);
3287b3bc8547SSteven Rostedt (Google) /* enum/sizeof string smaller than value */
3288795301d3SSteven Rostedt (Google) if (WARN_ON_ONCE(!ptr)) {
3289795301d3SSteven Rostedt (Google) kfree(str);
3290795301d3SSteven Rostedt (Google) continue;
3291795301d3SSteven Rostedt (Google) }
3292795301d3SSteven Rostedt (Google)
3293795301d3SSteven Rostedt (Google) /*
3294795301d3SSteven Rostedt (Google) * If the event is part of a module, then we need to free the string
3295795301d3SSteven Rostedt (Google) * when the module is removed. Otherwise, it will stay allocated
3296795301d3SSteven Rostedt (Google) * until a reboot.
3297795301d3SSteven Rostedt (Google) */
3298795301d3SSteven Rostedt (Google) if (call->module)
3299795301d3SSteven Rostedt (Google) add_str_to_module(call->module, str);
3300795301d3SSteven Rostedt (Google)
3301795301d3SSteven Rostedt (Google) field->type = str;
3302b3bc8547SSteven Rostedt (Google) }
3303b3bc8547SSteven Rostedt (Google) }
3304b3bc8547SSteven Rostedt (Google)
trace_event_eval_update(struct trace_eval_map ** map,int len)3305f57a4143SJeremy Linton void trace_event_eval_update(struct trace_eval_map **map, int len)
33060c564a53SSteven Rostedt (Red Hat) {
33072425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call, *p;
33080c564a53SSteven Rostedt (Red Hat) const char *last_system = NULL;
33091ebe1eafSSteven Rostedt (VMware) bool first = false;
33100c564a53SSteven Rostedt (Red Hat) int last_i;
33110c564a53SSteven Rostedt (Red Hat) int i;
33120c564a53SSteven Rostedt (Red Hat)
33130c564a53SSteven Rostedt (Red Hat) down_write(&trace_event_sem);
33140c564a53SSteven Rostedt (Red Hat) list_for_each_entry_safe(call, p, &ftrace_events, list) {
33150c564a53SSteven Rostedt (Red Hat) /* events are usually grouped together with systems */
33160c564a53SSteven Rostedt (Red Hat) if (!last_system || call->class->system != last_system) {
33171ebe1eafSSteven Rostedt (VMware) first = true;
33180c564a53SSteven Rostedt (Red Hat) last_i = 0;
33190c564a53SSteven Rostedt (Red Hat) last_system = call->class->system;
33200c564a53SSteven Rostedt (Red Hat) }
33210c564a53SSteven Rostedt (Red Hat)
33221ebe1eafSSteven Rostedt (VMware) /*
3323f2cc020dSIngo Molnar * Since calls are grouped by systems, the likelihood that the
33241ebe1eafSSteven Rostedt (VMware) * next call in the iteration belongs to the same system as the
33252b5894ccSQiujun Huang * previous call is high. As an optimization, we skip searching
33261ebe1eafSSteven Rostedt (VMware) * for a map[] that matches the call's system if the last call
33271ebe1eafSSteven Rostedt (VMware) * was from the same system. That's what last_i is for. If the
33281ebe1eafSSteven Rostedt (VMware) * call has the same system as the previous call, then last_i
33291ebe1eafSSteven Rostedt (VMware) * will be the index of the first map[] that has a matching
33301ebe1eafSSteven Rostedt (VMware) * system.
33311ebe1eafSSteven Rostedt (VMware) */
33320c564a53SSteven Rostedt (Red Hat) for (i = last_i; i < len; i++) {
33330c564a53SSteven Rostedt (Red Hat) if (call->class->system == map[i]->system) {
33340c564a53SSteven Rostedt (Red Hat) /* Save the first system if need be */
33351ebe1eafSSteven Rostedt (VMware) if (first) {
33360c564a53SSteven Rostedt (Red Hat) last_i = i;
33371ebe1eafSSteven Rostedt (VMware) first = false;
33381ebe1eafSSteven Rostedt (VMware) }
33390c564a53SSteven Rostedt (Red Hat) update_event_printk(call, map[i]);
3340b3bc8547SSteven Rostedt (Google) update_event_fields(call, map[i]);
33410c564a53SSteven Rostedt (Red Hat) }
33420c564a53SSteven Rostedt (Red Hat) }
334323cce5f2SClément Léger cond_resched();
33440c564a53SSteven Rostedt (Red Hat) }
33450c564a53SSteven Rostedt (Red Hat) up_write(&trace_event_sem);
33460c564a53SSteven Rostedt (Red Hat) }
33470c564a53SSteven Rostedt (Red Hat)
event_in_systems(struct trace_event_call * call,const char * systems)3348d2356997SSteven Rostedt (Google) static bool event_in_systems(struct trace_event_call *call,
3349d2356997SSteven Rostedt (Google) const char *systems)
3350d2356997SSteven Rostedt (Google) {
3351d2356997SSteven Rostedt (Google) const char *system;
3352d2356997SSteven Rostedt (Google) const char *p;
3353d2356997SSteven Rostedt (Google)
3354d2356997SSteven Rostedt (Google) if (!systems)
3355d2356997SSteven Rostedt (Google) return true;
3356d2356997SSteven Rostedt (Google)
3357d2356997SSteven Rostedt (Google) system = call->class->system;
3358d2356997SSteven Rostedt (Google) p = strstr(systems, system);
3359d2356997SSteven Rostedt (Google) if (!p)
3360d2356997SSteven Rostedt (Google) return false;
3361d2356997SSteven Rostedt (Google)
3362d2356997SSteven Rostedt (Google) if (p != systems && !isspace(*(p - 1)) && *(p - 1) != ',')
3363d2356997SSteven Rostedt (Google) return false;
3364d2356997SSteven Rostedt (Google)
3365d2356997SSteven Rostedt (Google) p += strlen(system);
3366d2356997SSteven Rostedt (Google) return !*p || isspace(*p) || *p == ',';
3367d2356997SSteven Rostedt (Google) }
3368d2356997SSteven Rostedt (Google)
33691bd13edbSMasami Hiramatsu (Google) #ifdef CONFIG_HIST_TRIGGERS
33701bd13edbSMasami Hiramatsu (Google) /*
33711bd13edbSMasami Hiramatsu (Google) * Wake up waiter on the hist_poll_wq from irq_work because the hist trigger
33721bd13edbSMasami Hiramatsu (Google) * may happen in any context.
33731bd13edbSMasami Hiramatsu (Google) */
hist_poll_event_irq_work(struct irq_work * work)33741bd13edbSMasami Hiramatsu (Google) static void hist_poll_event_irq_work(struct irq_work *work)
33751bd13edbSMasami Hiramatsu (Google) {
33761bd13edbSMasami Hiramatsu (Google) wake_up_all(&hist_poll_wq);
33771bd13edbSMasami Hiramatsu (Google) }
33781bd13edbSMasami Hiramatsu (Google)
33791bd13edbSMasami Hiramatsu (Google) DEFINE_IRQ_WORK(hist_poll_work, hist_poll_event_irq_work);
33801bd13edbSMasami Hiramatsu (Google) DECLARE_WAIT_QUEUE_HEAD(hist_poll_wq);
33811bd13edbSMasami Hiramatsu (Google) #endif
33821bd13edbSMasami Hiramatsu (Google)
33837f1d2f82SSteven Rostedt (Red Hat) static struct trace_event_file *
trace_create_new_event(struct trace_event_call * call,struct trace_array * tr)33842425bcb9SSteven Rostedt (Red Hat) trace_create_new_event(struct trace_event_call *call,
3385da511bf3SSteven Rostedt (Red Hat) struct trace_array *tr)
3386da511bf3SSteven Rostedt (Red Hat) {
33876cb20650SSteven Rostedt (VMware) struct trace_pid_list *no_pid_list;
33886cb20650SSteven Rostedt (VMware) struct trace_pid_list *pid_list;
33897f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
33906cb20650SSteven Rostedt (VMware) unsigned int first;
3391da511bf3SSteven Rostedt (Red Hat)
3392d2356997SSteven Rostedt (Google) if (!event_in_systems(call, tr->system_names))
3393d2356997SSteven Rostedt (Google) return NULL;
3394d2356997SSteven Rostedt (Google)
3395da511bf3SSteven Rostedt (Red Hat) file = kmem_cache_alloc(file_cachep, GFP_TRACE);
3396da511bf3SSteven Rostedt (Red Hat) if (!file)
3397d2356997SSteven Rostedt (Google) return ERR_PTR(-ENOMEM);
3398da511bf3SSteven Rostedt (Red Hat)
33996cb20650SSteven Rostedt (VMware) pid_list = rcu_dereference_protected(tr->filtered_pids,
34006cb20650SSteven Rostedt (VMware) lockdep_is_held(&event_mutex));
34016cb20650SSteven Rostedt (VMware) no_pid_list = rcu_dereference_protected(tr->filtered_no_pids,
34026cb20650SSteven Rostedt (VMware) lockdep_is_held(&event_mutex));
34036cb20650SSteven Rostedt (VMware)
34046cb20650SSteven Rostedt (VMware) if (!trace_pid_list_first(pid_list, &first) ||
340527ff768fSSteven Rostedt (VMware) !trace_pid_list_first(no_pid_list, &first))
34066cb20650SSteven Rostedt (VMware) file->flags |= EVENT_FILE_FL_PID_FILTER;
34076cb20650SSteven Rostedt (VMware)
3408da511bf3SSteven Rostedt (Red Hat) file->event_call = call;
3409da511bf3SSteven Rostedt (Red Hat) file->tr = tr;
3410da511bf3SSteven Rostedt (Red Hat) atomic_set(&file->sm_ref, 0);
341185f2b082STom Zanussi atomic_set(&file->tm_ref, 0);
341285f2b082STom Zanussi INIT_LIST_HEAD(&file->triggers);
3413da511bf3SSteven Rostedt (Red Hat) list_add(&file->list, &tr->events);
34146e2fdcefSSteven Rostedt refcount_set(&file->ref, 1);
3415da511bf3SSteven Rostedt (Red Hat)
3416da511bf3SSteven Rostedt (Red Hat) return file;
3417da511bf3SSteven Rostedt (Red Hat) }
3418da511bf3SSteven Rostedt (Red Hat)
3419a01fdc89SSteven Rostedt (Google) #define MAX_BOOT_TRIGGERS 32
3420a01fdc89SSteven Rostedt (Google)
3421a01fdc89SSteven Rostedt (Google) static struct boot_triggers {
3422a01fdc89SSteven Rostedt (Google) const char *event;
3423a01fdc89SSteven Rostedt (Google) char *trigger;
3424a01fdc89SSteven Rostedt (Google) } bootup_triggers[MAX_BOOT_TRIGGERS];
3425a01fdc89SSteven Rostedt (Google)
3426a01fdc89SSteven Rostedt (Google) static char bootup_trigger_buf[COMMAND_LINE_SIZE];
3427a01fdc89SSteven Rostedt (Google) static int nr_boot_triggers;
3428a01fdc89SSteven Rostedt (Google)
setup_trace_triggers(char * str)3429a01fdc89SSteven Rostedt (Google) static __init int setup_trace_triggers(char *str)
3430a01fdc89SSteven Rostedt (Google) {
3431a01fdc89SSteven Rostedt (Google) char *trigger;
3432a01fdc89SSteven Rostedt (Google) char *buf;
3433a01fdc89SSteven Rostedt (Google) int i;
3434a01fdc89SSteven Rostedt (Google)
3435c7dce4c5SAzeem Shaikh strscpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE);
3436a1f157c7SZheng Yejian trace_set_ring_buffer_expanded(NULL);
3437a01fdc89SSteven Rostedt (Google) disable_tracing_selftest("running event triggers");
3438a01fdc89SSteven Rostedt (Google)
3439a01fdc89SSteven Rostedt (Google) buf = bootup_trigger_buf;
3440a01fdc89SSteven Rostedt (Google) for (i = 0; i < MAX_BOOT_TRIGGERS; i++) {
3441a01fdc89SSteven Rostedt (Google) trigger = strsep(&buf, ",");
3442a01fdc89SSteven Rostedt (Google) if (!trigger)
3443a01fdc89SSteven Rostedt (Google) break;
3444a01fdc89SSteven Rostedt (Google) bootup_triggers[i].event = strsep(&trigger, ".");
3445e6745a4dSSteven Rostedt (Google) bootup_triggers[i].trigger = trigger;
3446a01fdc89SSteven Rostedt (Google) if (!bootup_triggers[i].trigger)
3447a01fdc89SSteven Rostedt (Google) break;
3448a01fdc89SSteven Rostedt (Google) }
3449a01fdc89SSteven Rostedt (Google)
3450a01fdc89SSteven Rostedt (Google) nr_boot_triggers = i;
3451a01fdc89SSteven Rostedt (Google) return 1;
3452a01fdc89SSteven Rostedt (Google) }
3453a01fdc89SSteven Rostedt (Google) __setup("trace_trigger=", setup_trace_triggers);
3454a01fdc89SSteven Rostedt (Google)
3455ae63b31eSSteven Rostedt /* Add an event to a trace directory */
3456ae63b31eSSteven Rostedt static int
__trace_add_new_event(struct trace_event_call * call,struct trace_array * tr)34572425bcb9SSteven Rostedt (Red Hat) __trace_add_new_event(struct trace_event_call *call, struct trace_array *tr)
3458ae63b31eSSteven Rostedt {
34597f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
3460ae63b31eSSteven Rostedt
3461da511bf3SSteven Rostedt (Red Hat) file = trace_create_new_event(call, tr);
3462d2356997SSteven Rostedt (Google) /*
3463d2356997SSteven Rostedt (Google) * trace_create_new_event() returns ERR_PTR(-ENOMEM) if failed
3464d2356997SSteven Rostedt (Google) * allocation, or NULL if the event is not part of the tr->system_names.
3465d2356997SSteven Rostedt (Google) * When the event is not part of the tr->system_names, return zero, not
3466d2356997SSteven Rostedt (Google) * an error.
3467d2356997SSteven Rostedt (Google) */
3468ae63b31eSSteven Rostedt if (!file)
3469d2356997SSteven Rostedt (Google) return 0;
3470d2356997SSteven Rostedt (Google)
3471d2356997SSteven Rostedt (Google) if (IS_ERR(file))
3472d2356997SSteven Rostedt (Google) return PTR_ERR(file);
3473ae63b31eSSteven Rostedt
3474a838deabSMasami Hiramatsu if (eventdir_initialized)
3475620a30e9SOleg Nesterov return event_create_dir(tr->event_dir, file);
3476a838deabSMasami Hiramatsu else
3477a838deabSMasami Hiramatsu return event_define_fields(call);
3478ae63b31eSSteven Rostedt }
3479ae63b31eSSteven Rostedt
trace_early_triggers(struct trace_event_file * file,const char * name)3480a01fdc89SSteven Rostedt (Google) static void trace_early_triggers(struct trace_event_file *file, const char *name)
3481a01fdc89SSteven Rostedt (Google) {
3482a01fdc89SSteven Rostedt (Google) int ret;
3483a01fdc89SSteven Rostedt (Google) int i;
3484a01fdc89SSteven Rostedt (Google)
3485a01fdc89SSteven Rostedt (Google) for (i = 0; i < nr_boot_triggers; i++) {
3486a01fdc89SSteven Rostedt (Google) if (strcmp(name, bootup_triggers[i].event))
3487a01fdc89SSteven Rostedt (Google) continue;
3488a01fdc89SSteven Rostedt (Google) mutex_lock(&event_mutex);
3489a01fdc89SSteven Rostedt (Google) ret = trigger_process_regex(file, bootup_triggers[i].trigger);
3490a01fdc89SSteven Rostedt (Google) mutex_unlock(&event_mutex);
3491a01fdc89SSteven Rostedt (Google) if (ret)
3492a01fdc89SSteven Rostedt (Google) pr_err("Failed to register trigger '%s' on event %s\n",
3493a01fdc89SSteven Rostedt (Google) bootup_triggers[i].trigger,
3494a01fdc89SSteven Rostedt (Google) bootup_triggers[i].event);
3495a01fdc89SSteven Rostedt (Google) }
3496a01fdc89SSteven Rostedt (Google) }
3497a01fdc89SSteven Rostedt (Google)
349877248221SSteven Rostedt /*
3499f2cc020dSIngo Molnar * Just create a descriptor for early init. A descriptor is required
350077248221SSteven Rostedt * for enabling events at boot. We want to enable events before
350177248221SSteven Rostedt * the filesystem is initialized.
350277248221SSteven Rostedt */
3503ce66f613SMasami Hiramatsu static int
__trace_early_add_new_event(struct trace_event_call * call,struct trace_array * tr)35042425bcb9SSteven Rostedt (Red Hat) __trace_early_add_new_event(struct trace_event_call *call,
350577248221SSteven Rostedt struct trace_array *tr)
350677248221SSteven Rostedt {
35077f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
3508a01fdc89SSteven Rostedt (Google) int ret;
350977248221SSteven Rostedt
3510da511bf3SSteven Rostedt (Red Hat) file = trace_create_new_event(call, tr);
3511d2356997SSteven Rostedt (Google) /*
3512d2356997SSteven Rostedt (Google) * trace_create_new_event() returns ERR_PTR(-ENOMEM) if failed
3513d2356997SSteven Rostedt (Google) * allocation, or NULL if the event is not part of the tr->system_names.
3514d2356997SSteven Rostedt (Google) * When the event is not part of the tr->system_names, return zero, not
3515d2356997SSteven Rostedt (Google) * an error.
3516d2356997SSteven Rostedt (Google) */
351777248221SSteven Rostedt if (!file)
3518d2356997SSteven Rostedt (Google) return 0;
3519d2356997SSteven Rostedt (Google)
3520d2356997SSteven Rostedt (Google) if (IS_ERR(file))
3521d2356997SSteven Rostedt (Google) return PTR_ERR(file);
352277248221SSteven Rostedt
3523a01fdc89SSteven Rostedt (Google) ret = event_define_fields(call);
3524a01fdc89SSteven Rostedt (Google) if (ret)
3525a01fdc89SSteven Rostedt (Google) return ret;
3526a01fdc89SSteven Rostedt (Google)
3527a01fdc89SSteven Rostedt (Google) trace_early_triggers(file, trace_event_name(call));
3528a01fdc89SSteven Rostedt (Google)
3529a01fdc89SSteven Rostedt (Google) return 0;
353077248221SSteven Rostedt }
353177248221SSteven Rostedt
3532ae63b31eSSteven Rostedt struct ftrace_module_file_ops;
35332425bcb9SSteven Rostedt (Red Hat) static void __add_event_to_tracers(struct trace_event_call *call);
3534ae63b31eSSteven Rostedt
35357e1413edSSteven Rostedt (VMware) /* Add an additional event_call dynamically */
trace_add_event_call(struct trace_event_call * call)35367e1413edSSteven Rostedt (VMware) int trace_add_event_call(struct trace_event_call *call)
3537bd1a5c84SMasami Hiramatsu {
3538bd1a5c84SMasami Hiramatsu int ret;
3539fc800a10SMasami Hiramatsu lockdep_assert_held(&event_mutex);
3540fc800a10SMasami Hiramatsu
354159980d9bSSteven Rostedt guard(mutex)(&trace_types_lock);
3542ae63b31eSSteven Rostedt
3543ae63b31eSSteven Rostedt ret = __register_event(call, NULL);
354459980d9bSSteven Rostedt if (ret < 0)
354559980d9bSSteven Rostedt return ret;
3546ae63b31eSSteven Rostedt
354759980d9bSSteven Rostedt __add_event_to_tracers(call);
3548fc800a10SMasami Hiramatsu return ret;
3549fc800a10SMasami Hiramatsu }
35508bcd0663SSteven Rostedt (Google) EXPORT_SYMBOL_GPL(trace_add_event_call);
3551fc800a10SMasami Hiramatsu
35524fead8e4SMasami Hiramatsu /*
3553a8227415SAlexander Z Lam * Must be called under locking of trace_types_lock, event_mutex and
3554a8227415SAlexander Z Lam * trace_event_sem.
35554fead8e4SMasami Hiramatsu */
__trace_remove_event_call(struct trace_event_call * call)35562425bcb9SSteven Rostedt (Red Hat) static void __trace_remove_event_call(struct trace_event_call *call)
3557bd1a5c84SMasami Hiramatsu {
35588781915aSEzequiel Garcia event_remove(call);
3559bd1a5c84SMasami Hiramatsu trace_destroy_fields(call);
3560bd1a5c84SMasami Hiramatsu }
3561bd1a5c84SMasami Hiramatsu
probe_remove_event_call(struct trace_event_call * call)35622425bcb9SSteven Rostedt (Red Hat) static int probe_remove_event_call(struct trace_event_call *call)
3563bd1a5c84SMasami Hiramatsu {
35642816c551SOleg Nesterov struct trace_array *tr;
35657f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
35662816c551SOleg Nesterov
35672816c551SOleg Nesterov #ifdef CONFIG_PERF_EVENTS
35682816c551SOleg Nesterov if (call->perf_refcount)
35692816c551SOleg Nesterov return -EBUSY;
35702816c551SOleg Nesterov #endif
35712816c551SOleg Nesterov do_for_each_event_file(tr, file) {
35722816c551SOleg Nesterov if (file->event_call != call)
35732816c551SOleg Nesterov continue;
35742816c551SOleg Nesterov /*
35752816c551SOleg Nesterov * We can't rely on ftrace_event_enable_disable(enable => 0)
35765d6ad960SSteven Rostedt (Red Hat) * we are going to do, EVENT_FILE_FL_SOFT_MODE can suppress
35772816c551SOleg Nesterov * TRACE_REG_UNREGISTER.
35782816c551SOleg Nesterov */
35795d6ad960SSteven Rostedt (Red Hat) if (file->flags & EVENT_FILE_FL_ENABLED)
35804313e5a6SSteven Rostedt (Google) goto busy;
35814313e5a6SSteven Rostedt (Google)
35824313e5a6SSteven Rostedt (Google) if (file->flags & EVENT_FILE_FL_WAS_ENABLED)
35834313e5a6SSteven Rostedt (Google) tr->clear_trace = true;
35842ba64035SSteven Rostedt (Red Hat) /*
35852ba64035SSteven Rostedt (Red Hat) * The do_for_each_event_file_safe() is
35862ba64035SSteven Rostedt (Red Hat) * a double loop. After finding the call for this
35872ba64035SSteven Rostedt (Red Hat) * trace_array, we use break to jump to the next
35882ba64035SSteven Rostedt (Red Hat) * trace_array.
35892ba64035SSteven Rostedt (Red Hat) */
35902816c551SOleg Nesterov break;
35912816c551SOleg Nesterov } while_for_each_event_file();
35922816c551SOleg Nesterov
35932816c551SOleg Nesterov __trace_remove_event_call(call);
35942816c551SOleg Nesterov
35952816c551SOleg Nesterov return 0;
35964313e5a6SSteven Rostedt (Google) busy:
35974313e5a6SSteven Rostedt (Google) /* No need to clear the trace now */
35984313e5a6SSteven Rostedt (Google) list_for_each_entry(tr, &ftrace_trace_arrays, list) {
35994313e5a6SSteven Rostedt (Google) tr->clear_trace = false;
36004313e5a6SSteven Rostedt (Google) }
36014313e5a6SSteven Rostedt (Google) return -EBUSY;
36022816c551SOleg Nesterov }
36032816c551SOleg Nesterov
36047e1413edSSteven Rostedt (VMware) /* Remove an event_call */
trace_remove_event_call(struct trace_event_call * call)36057e1413edSSteven Rostedt (VMware) int trace_remove_event_call(struct trace_event_call *call)
3606fc800a10SMasami Hiramatsu {
3607fc800a10SMasami Hiramatsu int ret;
3608fc800a10SMasami Hiramatsu
3609fc800a10SMasami Hiramatsu lockdep_assert_held(&event_mutex);
3610fc800a10SMasami Hiramatsu
3611fc800a10SMasami Hiramatsu mutex_lock(&trace_types_lock);
3612fc800a10SMasami Hiramatsu down_write(&trace_event_sem);
3613fc800a10SMasami Hiramatsu ret = probe_remove_event_call(call);
3614fc800a10SMasami Hiramatsu up_write(&trace_event_sem);
3615fc800a10SMasami Hiramatsu mutex_unlock(&trace_types_lock);
3616fc800a10SMasami Hiramatsu
3617fc800a10SMasami Hiramatsu return ret;
3618fc800a10SMasami Hiramatsu }
36198bcd0663SSteven Rostedt (Google) EXPORT_SYMBOL_GPL(trace_remove_event_call);
3620fc800a10SMasami Hiramatsu
3621bd1a5c84SMasami Hiramatsu #define for_each_event(event, start, end) \
3622bd1a5c84SMasami Hiramatsu for (event = start; \
3623bd1a5c84SMasami Hiramatsu (unsigned long)event < (unsigned long)end; \
3624bd1a5c84SMasami Hiramatsu event++)
3625bd1a5c84SMasami Hiramatsu
3626bd1a5c84SMasami Hiramatsu #ifdef CONFIG_MODULES
update_mod_cache(struct trace_array * tr,struct module * mod)362722412b72SSteven Rostedt static void update_mod_cache(struct trace_array *tr, struct module *mod)
3628b355247dSSteven Rostedt {
3629b355247dSSteven Rostedt struct event_mod_load *event_mod, *n;
3630b355247dSSteven Rostedt
3631b355247dSSteven Rostedt list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
3632b355247dSSteven Rostedt if (strcmp(event_mod->module, mod->name) != 0)
3633b355247dSSteven Rostedt continue;
3634b355247dSSteven Rostedt
3635b355247dSSteven Rostedt __ftrace_set_clr_event_nolock(tr, event_mod->match,
3636b355247dSSteven Rostedt event_mod->system,
3637b355247dSSteven Rostedt event_mod->event, 1, mod->name);
3638b355247dSSteven Rostedt free_event_mod(event_mod);
3639b355247dSSteven Rostedt }
3640b355247dSSteven Rostedt }
3641b355247dSSteven Rostedt
update_cache_events(struct module * mod)3642b355247dSSteven Rostedt static void update_cache_events(struct module *mod)
3643b355247dSSteven Rostedt {
3644b355247dSSteven Rostedt struct trace_array *tr;
3645b355247dSSteven Rostedt
3646b355247dSSteven Rostedt list_for_each_entry(tr, &ftrace_trace_arrays, list)
364722412b72SSteven Rostedt update_mod_cache(tr, mod);
3648b355247dSSteven Rostedt }
3649bd1a5c84SMasami Hiramatsu
trace_module_add_events(struct module * mod)36506d723736SSteven Rostedt static void trace_module_add_events(struct module *mod)
36516d723736SSteven Rostedt {
36522425bcb9SSteven Rostedt (Red Hat) struct trace_event_call **call, **start, **end;
36536d723736SSteven Rostedt
365445ab2813SSteven Rostedt (Red Hat) if (!mod->num_trace_events)
365545ab2813SSteven Rostedt (Red Hat) return;
365645ab2813SSteven Rostedt (Red Hat)
365745ab2813SSteven Rostedt (Red Hat) /* Don't add infrastructure for mods without tracepoints */
365845ab2813SSteven Rostedt (Red Hat) if (trace_module_has_bad_taint(mod)) {
365945ab2813SSteven Rostedt (Red Hat) pr_err("%s: module has bad taint, not creating trace events\n",
366045ab2813SSteven Rostedt (Red Hat) mod->name);
366145ab2813SSteven Rostedt (Red Hat) return;
366245ab2813SSteven Rostedt (Red Hat) }
366345ab2813SSteven Rostedt (Red Hat)
36646d723736SSteven Rostedt start = mod->trace_events;
36656d723736SSteven Rostedt end = mod->trace_events + mod->num_trace_events;
36666d723736SSteven Rostedt
366767ead0a6SLi Zefan for_each_event(call, start, end) {
3668ae63b31eSSteven Rostedt __register_event(*call, mod);
3669779c5e37SOleg Nesterov __add_event_to_tracers(*call);
36706d723736SSteven Rostedt }
3671b355247dSSteven Rostedt
3672b355247dSSteven Rostedt update_cache_events(mod);
36736d723736SSteven Rostedt }
36746d723736SSteven Rostedt
trace_module_remove_events(struct module * mod)36756d723736SSteven Rostedt static void trace_module_remove_events(struct module *mod)
36766d723736SSteven Rostedt {
36772425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call, *p;
3678795301d3SSteven Rostedt (Google) struct module_string *modstr, *m;
36796d723736SSteven Rostedt
368052f6ad6dSzhangwei(Jovi) down_write(&trace_event_sem);
36816d723736SSteven Rostedt list_for_each_entry_safe(call, p, &ftrace_events, list) {
36821d18538eSSteven Rostedt (VMware) if ((call->flags & TRACE_EVENT_FL_DYNAMIC) || !call->module)
36831d18538eSSteven Rostedt (VMware) continue;
36841d18538eSSteven Rostedt (VMware) if (call->module == mod)
3685bd1a5c84SMasami Hiramatsu __trace_remove_event_call(call);
36866d723736SSteven Rostedt }
3687795301d3SSteven Rostedt (Google) /* Check for any strings allocade for this module */
3688795301d3SSteven Rostedt (Google) list_for_each_entry_safe(modstr, m, &module_strings, next) {
3689795301d3SSteven Rostedt (Google) if (modstr->module != mod)
3690795301d3SSteven Rostedt (Google) continue;
3691795301d3SSteven Rostedt (Google) list_del(&modstr->next);
3692795301d3SSteven Rostedt (Google) kfree(modstr->str);
3693795301d3SSteven Rostedt (Google) kfree(modstr);
3694795301d3SSteven Rostedt (Google) }
369552f6ad6dSzhangwei(Jovi) up_write(&trace_event_sem);
36969456f0faSSteven Rostedt
36979456f0faSSteven Rostedt /*
36989456f0faSSteven Rostedt * It is safest to reset the ring buffer if the module being unloaded
3699873c642fSSteven Rostedt (Red Hat) * registered any events that were used. The only worry is if
3700873c642fSSteven Rostedt (Red Hat) * a new module gets loaded, and takes on the same id as the events
3701873c642fSSteven Rostedt (Red Hat) * of this module. When printing out the buffer, traced events left
3702873c642fSSteven Rostedt (Red Hat) * over from this module may be passed to the new module events and
3703873c642fSSteven Rostedt (Red Hat) * unexpected results may occur.
37049456f0faSSteven Rostedt */
3705e18eb878SSteven Rostedt (Google) tracing_reset_all_online_cpus_unlocked();
37066d723736SSteven Rostedt }
37076d723736SSteven Rostedt
trace_module_notify(struct notifier_block * self,unsigned long val,void * data)370861f919a1SSteven Rostedt static int trace_module_notify(struct notifier_block *self,
37096d723736SSteven Rostedt unsigned long val, void *data)
37106d723736SSteven Rostedt {
37116d723736SSteven Rostedt struct module *mod = data;
37126d723736SSteven Rostedt
37136d723736SSteven Rostedt mutex_lock(&event_mutex);
371412ecef0cSSteven Rostedt (VMware) mutex_lock(&trace_types_lock);
37156d723736SSteven Rostedt switch (val) {
37166d723736SSteven Rostedt case MODULE_STATE_COMING:
37176d723736SSteven Rostedt trace_module_add_events(mod);
37186d723736SSteven Rostedt break;
37196d723736SSteven Rostedt case MODULE_STATE_GOING:
37206d723736SSteven Rostedt trace_module_remove_events(mod);
37216d723736SSteven Rostedt break;
37226d723736SSteven Rostedt }
3723a8227415SAlexander Z Lam mutex_unlock(&trace_types_lock);
372412ecef0cSSteven Rostedt (VMware) mutex_unlock(&event_mutex);
37256d723736SSteven Rostedt
37260340a6b7SPeter Zijlstra return NOTIFY_OK;
37276d723736SSteven Rostedt }
3728315326c1SSteven Rostedt (Red Hat)
3729836d481eSOleg Nesterov static struct notifier_block trace_module_nb = {
3730836d481eSOleg Nesterov .notifier_call = trace_module_notify,
37313673b8e4SSteven Rostedt (Red Hat) .priority = 1, /* higher than trace.c module notify */
3732836d481eSOleg Nesterov };
373361f919a1SSteven Rostedt #endif /* CONFIG_MODULES */
37346d723736SSteven Rostedt
3735ae63b31eSSteven Rostedt /* Create a new event directory structure for a trace directory. */
3736ae63b31eSSteven Rostedt static void
__trace_add_event_dirs(struct trace_array * tr)3737ae63b31eSSteven Rostedt __trace_add_event_dirs(struct trace_array *tr)
3738ae63b31eSSteven Rostedt {
37392425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call;
3740ae63b31eSSteven Rostedt int ret;
3741ae63b31eSSteven Rostedt
3742ae63b31eSSteven Rostedt list_for_each_entry(call, &ftrace_events, list) {
3743620a30e9SOleg Nesterov ret = __trace_add_new_event(call, tr);
3744ae63b31eSSteven Rostedt if (ret < 0)
37453448bac3SFabian Frederick pr_warn("Could not create directory for event %s\n",
3746687fcc4aSSteven Rostedt (Red Hat) trace_event_name(call));
3747ae63b31eSSteven Rostedt }
3748ae63b31eSSteven Rostedt }
3749ae63b31eSSteven Rostedt
37503c96529cSSteven Rostedt (VMware) /* Returns any file that matches the system and event */
37517f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *
__find_event_file(struct trace_array * tr,const char * system,const char * event)37523c96529cSSteven Rostedt (VMware) __find_event_file(struct trace_array *tr, const char *system, const char *event)
37533cd715deSSteven Rostedt (Red Hat) {
37547f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
37552425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call;
3756de7b2973SMathieu Desnoyers const char *name;
37573cd715deSSteven Rostedt (Red Hat)
37583cd715deSSteven Rostedt (Red Hat) list_for_each_entry(file, &tr->events, list) {
37593cd715deSSteven Rostedt (Red Hat)
37603cd715deSSteven Rostedt (Red Hat) call = file->event_call;
3761687fcc4aSSteven Rostedt (Red Hat) name = trace_event_name(call);
37623cd715deSSteven Rostedt (Red Hat)
37633c96529cSSteven Rostedt (VMware) if (!name || !call->class)
37643cd715deSSteven Rostedt (Red Hat) continue;
37653cd715deSSteven Rostedt (Red Hat)
3766de7b2973SMathieu Desnoyers if (strcmp(event, name) == 0 &&
37673cd715deSSteven Rostedt (Red Hat) strcmp(system, call->class->system) == 0)
37683cd715deSSteven Rostedt (Red Hat) return file;
37693cd715deSSteven Rostedt (Red Hat) }
37703cd715deSSteven Rostedt (Red Hat) return NULL;
37713cd715deSSteven Rostedt (Red Hat) }
37723cd715deSSteven Rostedt (Red Hat)
37733c96529cSSteven Rostedt (VMware) /* Returns valid trace event files that match system and event */
37743c96529cSSteven Rostedt (VMware) struct trace_event_file *
find_event_file(struct trace_array * tr,const char * system,const char * event)37753c96529cSSteven Rostedt (VMware) find_event_file(struct trace_array *tr, const char *system, const char *event)
37763c96529cSSteven Rostedt (VMware) {
37773c96529cSSteven Rostedt (VMware) struct trace_event_file *file;
37783c96529cSSteven Rostedt (VMware)
37793c96529cSSteven Rostedt (VMware) file = __find_event_file(tr, system, event);
37803c96529cSSteven Rostedt (VMware) if (!file || !file->event_call->class->reg ||
37813c96529cSSteven Rostedt (VMware) file->event_call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
37823c96529cSSteven Rostedt (VMware) return NULL;
37833c96529cSSteven Rostedt (VMware)
37843c96529cSSteven Rostedt (VMware) return file;
37853c96529cSSteven Rostedt (VMware) }
37863c96529cSSteven Rostedt (VMware)
3787e3e2a2ccSTom Zanussi /**
3788e3e2a2ccSTom Zanussi * trace_get_event_file - Find and return a trace event file
3789e3e2a2ccSTom Zanussi * @instance: The name of the trace instance containing the event
3790e3e2a2ccSTom Zanussi * @system: The name of the system containing the event
3791e3e2a2ccSTom Zanussi * @event: The name of the event
3792e3e2a2ccSTom Zanussi *
3793e3e2a2ccSTom Zanussi * Return a trace event file given the trace instance name, trace
3794e3e2a2ccSTom Zanussi * system, and trace event name. If the instance name is NULL, it
3795e3e2a2ccSTom Zanussi * refers to the top-level trace array.
3796e3e2a2ccSTom Zanussi *
3797e3e2a2ccSTom Zanussi * This function will look it up and return it if found, after calling
3798e3e2a2ccSTom Zanussi * trace_array_get() to prevent the instance from going away, and
3799e3e2a2ccSTom Zanussi * increment the event's module refcount to prevent it from being
3800e3e2a2ccSTom Zanussi * removed.
3801e3e2a2ccSTom Zanussi *
3802e3e2a2ccSTom Zanussi * To release the file, call trace_put_event_file(), which will call
3803e3e2a2ccSTom Zanussi * trace_array_put() and decrement the event's module refcount.
3804e3e2a2ccSTom Zanussi *
3805e3e2a2ccSTom Zanussi * Return: The trace event on success, ERR_PTR otherwise.
3806e3e2a2ccSTom Zanussi */
trace_get_event_file(const char * instance,const char * system,const char * event)3807e3e2a2ccSTom Zanussi struct trace_event_file *trace_get_event_file(const char *instance,
3808e3e2a2ccSTom Zanussi const char *system,
3809e3e2a2ccSTom Zanussi const char *event)
3810e3e2a2ccSTom Zanussi {
3811e3e2a2ccSTom Zanussi struct trace_array *tr = top_trace_array();
3812e3e2a2ccSTom Zanussi struct trace_event_file *file = NULL;
3813e3e2a2ccSTom Zanussi int ret = -EINVAL;
3814e3e2a2ccSTom Zanussi
3815e3e2a2ccSTom Zanussi if (instance) {
3816e3e2a2ccSTom Zanussi tr = trace_array_find_get(instance);
3817e3e2a2ccSTom Zanussi if (!tr)
3818e3e2a2ccSTom Zanussi return ERR_PTR(-ENOENT);
3819e3e2a2ccSTom Zanussi } else {
3820e3e2a2ccSTom Zanussi ret = trace_array_get(tr);
3821e3e2a2ccSTom Zanussi if (ret)
3822e3e2a2ccSTom Zanussi return ERR_PTR(ret);
3823e3e2a2ccSTom Zanussi }
3824e3e2a2ccSTom Zanussi
382559980d9bSSteven Rostedt guard(mutex)(&event_mutex);
3826e3e2a2ccSTom Zanussi
3827e3e2a2ccSTom Zanussi file = find_event_file(tr, system, event);
3828e3e2a2ccSTom Zanussi if (!file) {
3829e3e2a2ccSTom Zanussi trace_array_put(tr);
383059980d9bSSteven Rostedt return ERR_PTR(-EINVAL);
3831e3e2a2ccSTom Zanussi }
3832e3e2a2ccSTom Zanussi
3833e3e2a2ccSTom Zanussi /* Don't let event modules unload while in use */
38341d18538eSSteven Rostedt (VMware) ret = trace_event_try_get_ref(file->event_call);
3835e3e2a2ccSTom Zanussi if (!ret) {
3836e3e2a2ccSTom Zanussi trace_array_put(tr);
383759980d9bSSteven Rostedt return ERR_PTR(-EBUSY);
3838e3e2a2ccSTom Zanussi }
3839e3e2a2ccSTom Zanussi
3840e3e2a2ccSTom Zanussi return file;
3841e3e2a2ccSTom Zanussi }
3842e3e2a2ccSTom Zanussi EXPORT_SYMBOL_GPL(trace_get_event_file);
3843e3e2a2ccSTom Zanussi
3844e3e2a2ccSTom Zanussi /**
3845e3e2a2ccSTom Zanussi * trace_put_event_file - Release a file from trace_get_event_file()
3846e3e2a2ccSTom Zanussi * @file: The trace event file
3847e3e2a2ccSTom Zanussi *
3848e3e2a2ccSTom Zanussi * If a file was retrieved using trace_get_event_file(), this should
3849e3e2a2ccSTom Zanussi * be called when it's no longer needed. It will cancel the previous
3850e3e2a2ccSTom Zanussi * trace_array_get() called by that function, and decrement the
3851e3e2a2ccSTom Zanussi * event's module refcount.
3852e3e2a2ccSTom Zanussi */
trace_put_event_file(struct trace_event_file * file)3853e3e2a2ccSTom Zanussi void trace_put_event_file(struct trace_event_file *file)
3854e3e2a2ccSTom Zanussi {
3855e3e2a2ccSTom Zanussi mutex_lock(&event_mutex);
38561d18538eSSteven Rostedt (VMware) trace_event_put_ref(file->event_call);
3857e3e2a2ccSTom Zanussi mutex_unlock(&event_mutex);
3858e3e2a2ccSTom Zanussi
3859e3e2a2ccSTom Zanussi trace_array_put(file->tr);
3860e3e2a2ccSTom Zanussi }
3861e3e2a2ccSTom Zanussi EXPORT_SYMBOL_GPL(trace_put_event_file);
3862e3e2a2ccSTom Zanussi
38632875a08bSSteven Rostedt (Red Hat) #ifdef CONFIG_DYNAMIC_FTRACE
38642875a08bSSteven Rostedt (Red Hat)
38652875a08bSSteven Rostedt (Red Hat) /* Avoid typos */
38662875a08bSSteven Rostedt (Red Hat) #define ENABLE_EVENT_STR "enable_event"
38672875a08bSSteven Rostedt (Red Hat) #define DISABLE_EVENT_STR "disable_event"
38682875a08bSSteven Rostedt (Red Hat)
38692875a08bSSteven Rostedt (Red Hat) struct event_probe_data {
38707f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
38712875a08bSSteven Rostedt (Red Hat) unsigned long count;
38722875a08bSSteven Rostedt (Red Hat) int ref;
38732875a08bSSteven Rostedt (Red Hat) bool enable;
38742875a08bSSteven Rostedt (Red Hat) };
38752875a08bSSteven Rostedt (Red Hat)
update_event_probe(struct event_probe_data * data)387641794f19SSteven Rostedt (VMware) static void update_event_probe(struct event_probe_data *data)
38773cd715deSSteven Rostedt (Red Hat) {
38783cd715deSSteven Rostedt (Red Hat) if (data->enable)
38795d6ad960SSteven Rostedt (Red Hat) clear_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &data->file->flags);
38803cd715deSSteven Rostedt (Red Hat) else
38815d6ad960SSteven Rostedt (Red Hat) set_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &data->file->flags);
38823cd715deSSteven Rostedt (Red Hat) }
38833cd715deSSteven Rostedt (Red Hat)
38843cd715deSSteven Rostedt (Red Hat) static void
event_enable_probe(unsigned long ip,unsigned long parent_ip,struct trace_array * tr,struct ftrace_probe_ops * ops,void * data)388541794f19SSteven Rostedt (VMware) event_enable_probe(unsigned long ip, unsigned long parent_ip,
3886b5f081b5SSteven Rostedt (VMware) struct trace_array *tr, struct ftrace_probe_ops *ops,
38876e444319SSteven Rostedt (VMware) void *data)
388841794f19SSteven Rostedt (VMware) {
38896e444319SSteven Rostedt (VMware) struct ftrace_func_mapper *mapper = data;
38906e444319SSteven Rostedt (VMware) struct event_probe_data *edata;
389141794f19SSteven Rostedt (VMware) void **pdata;
389241794f19SSteven Rostedt (VMware)
389341794f19SSteven Rostedt (VMware) pdata = ftrace_func_mapper_find_ip(mapper, ip);
389441794f19SSteven Rostedt (VMware) if (!pdata || !*pdata)
389541794f19SSteven Rostedt (VMware) return;
389641794f19SSteven Rostedt (VMware)
38976e444319SSteven Rostedt (VMware) edata = *pdata;
38986e444319SSteven Rostedt (VMware) update_event_probe(edata);
389941794f19SSteven Rostedt (VMware) }
390041794f19SSteven Rostedt (VMware)
390141794f19SSteven Rostedt (VMware) static void
event_enable_count_probe(unsigned long ip,unsigned long parent_ip,struct trace_array * tr,struct ftrace_probe_ops * ops,void * data)3902bca6c8d0SSteven Rostedt (VMware) event_enable_count_probe(unsigned long ip, unsigned long parent_ip,
3903b5f081b5SSteven Rostedt (VMware) struct trace_array *tr, struct ftrace_probe_ops *ops,
39046e444319SSteven Rostedt (VMware) void *data)
39053cd715deSSteven Rostedt (Red Hat) {
39066e444319SSteven Rostedt (VMware) struct ftrace_func_mapper *mapper = data;
39076e444319SSteven Rostedt (VMware) struct event_probe_data *edata;
390841794f19SSteven Rostedt (VMware) void **pdata;
39093cd715deSSteven Rostedt (Red Hat)
391041794f19SSteven Rostedt (VMware) pdata = ftrace_func_mapper_find_ip(mapper, ip);
391141794f19SSteven Rostedt (VMware) if (!pdata || !*pdata)
39123cd715deSSteven Rostedt (Red Hat) return;
39133cd715deSSteven Rostedt (Red Hat)
39146e444319SSteven Rostedt (VMware) edata = *pdata;
391541794f19SSteven Rostedt (VMware)
39166e444319SSteven Rostedt (VMware) if (!edata->count)
39173cd715deSSteven Rostedt (Red Hat) return;
39183cd715deSSteven Rostedt (Red Hat)
39193cd715deSSteven Rostedt (Red Hat) /* Skip if the event is in a state we want to switch to */
39206e444319SSteven Rostedt (VMware) if (edata->enable == !(edata->file->flags & EVENT_FILE_FL_SOFT_DISABLED))
39213cd715deSSteven Rostedt (Red Hat) return;
39223cd715deSSteven Rostedt (Red Hat)
39236e444319SSteven Rostedt (VMware) if (edata->count != -1)
39246e444319SSteven Rostedt (VMware) (edata->count)--;
39253cd715deSSteven Rostedt (Red Hat)
39266e444319SSteven Rostedt (VMware) update_event_probe(edata);
39273cd715deSSteven Rostedt (Red Hat) }
39283cd715deSSteven Rostedt (Red Hat)
39293cd715deSSteven Rostedt (Red Hat) static int
event_enable_print(struct seq_file * m,unsigned long ip,struct ftrace_probe_ops * ops,void * data)39303cd715deSSteven Rostedt (Red Hat) event_enable_print(struct seq_file *m, unsigned long ip,
39316e444319SSteven Rostedt (VMware) struct ftrace_probe_ops *ops, void *data)
39323cd715deSSteven Rostedt (Red Hat) {
39336e444319SSteven Rostedt (VMware) struct ftrace_func_mapper *mapper = data;
39346e444319SSteven Rostedt (VMware) struct event_probe_data *edata;
393541794f19SSteven Rostedt (VMware) void **pdata;
393641794f19SSteven Rostedt (VMware)
393741794f19SSteven Rostedt (VMware) pdata = ftrace_func_mapper_find_ip(mapper, ip);
393841794f19SSteven Rostedt (VMware)
393941794f19SSteven Rostedt (VMware) if (WARN_ON_ONCE(!pdata || !*pdata))
394041794f19SSteven Rostedt (VMware) return 0;
394141794f19SSteven Rostedt (VMware)
39426e444319SSteven Rostedt (VMware) edata = *pdata;
39433cd715deSSteven Rostedt (Red Hat)
39443cd715deSSteven Rostedt (Red Hat) seq_printf(m, "%ps:", (void *)ip);
39453cd715deSSteven Rostedt (Red Hat)
39463cd715deSSteven Rostedt (Red Hat) seq_printf(m, "%s:%s:%s",
39476e444319SSteven Rostedt (VMware) edata->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
39486e444319SSteven Rostedt (VMware) edata->file->event_call->class->system,
39496e444319SSteven Rostedt (VMware) trace_event_name(edata->file->event_call));
39503cd715deSSteven Rostedt (Red Hat)
39516e444319SSteven Rostedt (VMware) if (edata->count == -1)
3952fa6f0cc7SRasmus Villemoes seq_puts(m, ":unlimited\n");
39533cd715deSSteven Rostedt (Red Hat) else
39546e444319SSteven Rostedt (VMware) seq_printf(m, ":count=%ld\n", edata->count);
39553cd715deSSteven Rostedt (Red Hat)
39563cd715deSSteven Rostedt (Red Hat) return 0;
39573cd715deSSteven Rostedt (Red Hat) }
39583cd715deSSteven Rostedt (Red Hat)
39593cd715deSSteven Rostedt (Red Hat) static int
event_enable_init(struct ftrace_probe_ops * ops,struct trace_array * tr,unsigned long ip,void * init_data,void ** data)3960b5f081b5SSteven Rostedt (VMware) event_enable_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
39616e444319SSteven Rostedt (VMware) unsigned long ip, void *init_data, void **data)
39623cd715deSSteven Rostedt (Red Hat) {
39636e444319SSteven Rostedt (VMware) struct ftrace_func_mapper *mapper = *data;
39646e444319SSteven Rostedt (VMware) struct event_probe_data *edata = init_data;
396541794f19SSteven Rostedt (VMware) int ret;
396641794f19SSteven Rostedt (VMware)
39676e444319SSteven Rostedt (VMware) if (!mapper) {
39686e444319SSteven Rostedt (VMware) mapper = allocate_ftrace_func_mapper();
39696e444319SSteven Rostedt (VMware) if (!mapper)
39706e444319SSteven Rostedt (VMware) return -ENODEV;
39716e444319SSteven Rostedt (VMware) *data = mapper;
39726e444319SSteven Rostedt (VMware) }
39736e444319SSteven Rostedt (VMware)
39746e444319SSteven Rostedt (VMware) ret = ftrace_func_mapper_add_ip(mapper, ip, edata);
397541794f19SSteven Rostedt (VMware) if (ret < 0)
397641794f19SSteven Rostedt (VMware) return ret;
39773cd715deSSteven Rostedt (Red Hat)
39786e444319SSteven Rostedt (VMware) edata->ref++;
397941794f19SSteven Rostedt (VMware)
39803cd715deSSteven Rostedt (Red Hat) return 0;
39813cd715deSSteven Rostedt (Red Hat) }
39823cd715deSSteven Rostedt (Red Hat)
free_probe_data(void * data)39836e444319SSteven Rostedt (VMware) static int free_probe_data(void *data)
39846e444319SSteven Rostedt (VMware) {
39856e444319SSteven Rostedt (VMware) struct event_probe_data *edata = data;
39866e444319SSteven Rostedt (VMware)
39876e444319SSteven Rostedt (VMware) edata->ref--;
39886e444319SSteven Rostedt (VMware) if (!edata->ref) {
39896e444319SSteven Rostedt (VMware) /* Remove the SOFT_MODE flag */
39906e444319SSteven Rostedt (VMware) __ftrace_event_enable_disable(edata->file, 0, 1);
39911d18538eSSteven Rostedt (VMware) trace_event_put_ref(edata->file->event_call);
39926e444319SSteven Rostedt (VMware) kfree(edata);
39936e444319SSteven Rostedt (VMware) }
39946e444319SSteven Rostedt (VMware) return 0;
39956e444319SSteven Rostedt (VMware) }
39966e444319SSteven Rostedt (VMware)
39973cd715deSSteven Rostedt (Red Hat) static void
event_enable_free(struct ftrace_probe_ops * ops,struct trace_array * tr,unsigned long ip,void * data)3998b5f081b5SSteven Rostedt (VMware) event_enable_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
39996e444319SSteven Rostedt (VMware) unsigned long ip, void *data)
40003cd715deSSteven Rostedt (Red Hat) {
40016e444319SSteven Rostedt (VMware) struct ftrace_func_mapper *mapper = data;
40026e444319SSteven Rostedt (VMware) struct event_probe_data *edata;
400341794f19SSteven Rostedt (VMware)
40046e444319SSteven Rostedt (VMware) if (!ip) {
40056e444319SSteven Rostedt (VMware) if (!mapper)
400641794f19SSteven Rostedt (VMware) return;
40076e444319SSteven Rostedt (VMware) free_ftrace_func_mapper(mapper, free_probe_data);
40083cd715deSSteven Rostedt (Red Hat) return;
40093cd715deSSteven Rostedt (Red Hat) }
40106e444319SSteven Rostedt (VMware)
40116e444319SSteven Rostedt (VMware) edata = ftrace_func_mapper_remove_ip(mapper, ip);
40126e444319SSteven Rostedt (VMware)
40136e444319SSteven Rostedt (VMware) if (WARN_ON_ONCE(!edata))
40146e444319SSteven Rostedt (VMware) return;
40156e444319SSteven Rostedt (VMware)
40166e444319SSteven Rostedt (VMware) if (WARN_ON_ONCE(edata->ref <= 0))
40176e444319SSteven Rostedt (VMware) return;
40186e444319SSteven Rostedt (VMware)
40196e444319SSteven Rostedt (VMware) free_probe_data(edata);
40203cd715deSSteven Rostedt (Red Hat) }
40213cd715deSSteven Rostedt (Red Hat)
40223cd715deSSteven Rostedt (Red Hat) static struct ftrace_probe_ops event_enable_probe_ops = {
40233cd715deSSteven Rostedt (Red Hat) .func = event_enable_probe,
40243cd715deSSteven Rostedt (Red Hat) .print = event_enable_print,
40253cd715deSSteven Rostedt (Red Hat) .init = event_enable_init,
40263cd715deSSteven Rostedt (Red Hat) .free = event_enable_free,
40273cd715deSSteven Rostedt (Red Hat) };
40283cd715deSSteven Rostedt (Red Hat)
40293cd715deSSteven Rostedt (Red Hat) static struct ftrace_probe_ops event_enable_count_probe_ops = {
40303cd715deSSteven Rostedt (Red Hat) .func = event_enable_count_probe,
40313cd715deSSteven Rostedt (Red Hat) .print = event_enable_print,
40323cd715deSSteven Rostedt (Red Hat) .init = event_enable_init,
40333cd715deSSteven Rostedt (Red Hat) .free = event_enable_free,
40343cd715deSSteven Rostedt (Red Hat) };
40353cd715deSSteven Rostedt (Red Hat)
40363cd715deSSteven Rostedt (Red Hat) static struct ftrace_probe_ops event_disable_probe_ops = {
40373cd715deSSteven Rostedt (Red Hat) .func = event_enable_probe,
40383cd715deSSteven Rostedt (Red Hat) .print = event_enable_print,
40393cd715deSSteven Rostedt (Red Hat) .init = event_enable_init,
40403cd715deSSteven Rostedt (Red Hat) .free = event_enable_free,
40413cd715deSSteven Rostedt (Red Hat) };
40423cd715deSSteven Rostedt (Red Hat)
40433cd715deSSteven Rostedt (Red Hat) static struct ftrace_probe_ops event_disable_count_probe_ops = {
40443cd715deSSteven Rostedt (Red Hat) .func = event_enable_count_probe,
40453cd715deSSteven Rostedt (Red Hat) .print = event_enable_print,
40463cd715deSSteven Rostedt (Red Hat) .init = event_enable_init,
40473cd715deSSteven Rostedt (Red Hat) .free = event_enable_free,
40483cd715deSSteven Rostedt (Red Hat) };
40493cd715deSSteven Rostedt (Red Hat)
40503cd715deSSteven Rostedt (Red Hat) static int
event_enable_func(struct trace_array * tr,struct ftrace_hash * hash,char * glob,char * cmd,char * param,int enabled)405104ec7bb6SSteven Rostedt (VMware) event_enable_func(struct trace_array *tr, struct ftrace_hash *hash,
40523cd715deSSteven Rostedt (Red Hat) char *glob, char *cmd, char *param, int enabled)
40533cd715deSSteven Rostedt (Red Hat) {
40547f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
40553cd715deSSteven Rostedt (Red Hat) struct ftrace_probe_ops *ops;
40563cd715deSSteven Rostedt (Red Hat) struct event_probe_data *data;
4057c949dfb9SSteven Rostedt unsigned long count = -1;
40583cd715deSSteven Rostedt (Red Hat) const char *system;
40593cd715deSSteven Rostedt (Red Hat) const char *event;
40603cd715deSSteven Rostedt (Red Hat) char *number;
40613cd715deSSteven Rostedt (Red Hat) bool enable;
40623cd715deSSteven Rostedt (Red Hat) int ret;
40633cd715deSSteven Rostedt (Red Hat)
4064dc81e5e3SYoshihiro YUNOMAE if (!tr)
4065dc81e5e3SYoshihiro YUNOMAE return -ENODEV;
4066dc81e5e3SYoshihiro YUNOMAE
40673cd715deSSteven Rostedt (Red Hat) /* hash funcs only work with set_ftrace_filter */
40688092e808SHarsh Prateek Bora if (!enabled || !param)
40693cd715deSSteven Rostedt (Red Hat) return -EINVAL;
40703cd715deSSteven Rostedt (Red Hat)
40713cd715deSSteven Rostedt (Red Hat) system = strsep(¶m, ":");
40723cd715deSSteven Rostedt (Red Hat) if (!param)
40733cd715deSSteven Rostedt (Red Hat) return -EINVAL;
40743cd715deSSteven Rostedt (Red Hat)
40753cd715deSSteven Rostedt (Red Hat) event = strsep(¶m, ":");
40763cd715deSSteven Rostedt (Red Hat)
407759980d9bSSteven Rostedt guard(mutex)(&event_mutex);
40783cd715deSSteven Rostedt (Red Hat)
40793cd715deSSteven Rostedt (Red Hat) file = find_event_file(tr, system, event);
40803cd715deSSteven Rostedt (Red Hat) if (!file)
408159980d9bSSteven Rostedt return -EINVAL;
40823cd715deSSteven Rostedt (Red Hat)
40833cd715deSSteven Rostedt (Red Hat) enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
40843cd715deSSteven Rostedt (Red Hat)
40853cd715deSSteven Rostedt (Red Hat) if (enable)
40863cd715deSSteven Rostedt (Red Hat) ops = param ? &event_enable_count_probe_ops : &event_enable_probe_ops;
40873cd715deSSteven Rostedt (Red Hat) else
40883cd715deSSteven Rostedt (Red Hat) ops = param ? &event_disable_count_probe_ops : &event_disable_probe_ops;
40893cd715deSSteven Rostedt (Red Hat)
409059980d9bSSteven Rostedt if (glob[0] == '!')
409159980d9bSSteven Rostedt return unregister_ftrace_function_probe_func(glob+1, tr, ops);
40923cd715deSSteven Rostedt (Red Hat)
40934b8d63e5SSteven Rostedt if (param) {
40943cd715deSSteven Rostedt (Red Hat) number = strsep(¶m, ":");
40953cd715deSSteven Rostedt (Red Hat)
40963cd715deSSteven Rostedt (Red Hat) if (!strlen(number))
409759980d9bSSteven Rostedt return -EINVAL;
40983cd715deSSteven Rostedt (Red Hat)
40993cd715deSSteven Rostedt (Red Hat) /*
41003cd715deSSteven Rostedt (Red Hat) * We use the callback data field (which is a pointer)
41013cd715deSSteven Rostedt (Red Hat) * as our counter.
41023cd715deSSteven Rostedt (Red Hat) */
4103c949dfb9SSteven Rostedt ret = kstrtoul(number, 0, &count);
41043cd715deSSteven Rostedt (Red Hat) if (ret)
410559980d9bSSteven Rostedt return ret;
41064b8d63e5SSteven Rostedt }
41073cd715deSSteven Rostedt (Red Hat)
41083cd715deSSteven Rostedt (Red Hat) /* Don't let event modules unload while probe registered */
41091d18538eSSteven Rostedt (VMware) ret = trace_event_try_get_ref(file->event_call);
411059980d9bSSteven Rostedt if (!ret)
411159980d9bSSteven Rostedt return -EBUSY;
41123cd715deSSteven Rostedt (Red Hat)
41133cd715deSSteven Rostedt (Red Hat) ret = __ftrace_event_enable_disable(file, 1, 1);
41143cd715deSSteven Rostedt (Red Hat) if (ret < 0)
41153cd715deSSteven Rostedt (Red Hat) goto out_put;
411641794f19SSteven Rostedt (VMware)
411759980d9bSSteven Rostedt ret = -ENOMEM;
4118c949dfb9SSteven Rostedt data = kzalloc(sizeof(*data), GFP_KERNEL);
4119c949dfb9SSteven Rostedt if (!data)
4120c949dfb9SSteven Rostedt goto out_put;
4121c949dfb9SSteven Rostedt
4122c949dfb9SSteven Rostedt data->enable = enable;
4123c949dfb9SSteven Rostedt data->count = count;
4124c949dfb9SSteven Rostedt data->file = file;
4125c949dfb9SSteven Rostedt
412604ec7bb6SSteven Rostedt (VMware) ret = register_ftrace_function_probe(glob, tr, ops, data);
4127ff305dedSSteven Rostedt (Red Hat) /*
4128ff305dedSSteven Rostedt (Red Hat) * The above returns on success the # of functions enabled,
4129ff305dedSSteven Rostedt (Red Hat) * but if it didn't find any functions it returns zero.
4130ff305dedSSteven Rostedt (Red Hat) * Consider no functions a failure too.
4131ff305dedSSteven Rostedt (Red Hat) */
41323cd715deSSteven Rostedt (Red Hat)
413359980d9bSSteven Rostedt /* Just return zero, not the number of enabled functions */
413459980d9bSSteven Rostedt if (ret > 0)
413559980d9bSSteven Rostedt return 0;
413659980d9bSSteven Rostedt
4137c949dfb9SSteven Rostedt kfree(data);
413859980d9bSSteven Rostedt
413959980d9bSSteven Rostedt if (!ret)
414059980d9bSSteven Rostedt ret = -ENOENT;
414159980d9bSSteven Rostedt
41423cd715deSSteven Rostedt (Red Hat) __ftrace_event_enable_disable(file, 0, 1);
41433cd715deSSteven Rostedt (Red Hat) out_put:
41441d18538eSSteven Rostedt (VMware) trace_event_put_ref(file->event_call);
414559980d9bSSteven Rostedt return ret;
41463cd715deSSteven Rostedt (Red Hat) }
41473cd715deSSteven Rostedt (Red Hat)
41483cd715deSSteven Rostedt (Red Hat) static struct ftrace_func_command event_enable_cmd = {
41493cd715deSSteven Rostedt (Red Hat) .name = ENABLE_EVENT_STR,
41503cd715deSSteven Rostedt (Red Hat) .func = event_enable_func,
41513cd715deSSteven Rostedt (Red Hat) };
41523cd715deSSteven Rostedt (Red Hat)
41533cd715deSSteven Rostedt (Red Hat) static struct ftrace_func_command event_disable_cmd = {
41543cd715deSSteven Rostedt (Red Hat) .name = DISABLE_EVENT_STR,
41553cd715deSSteven Rostedt (Red Hat) .func = event_enable_func,
41563cd715deSSteven Rostedt (Red Hat) };
41573cd715deSSteven Rostedt (Red Hat)
register_event_cmds(void)41583cd715deSSteven Rostedt (Red Hat) static __init int register_event_cmds(void)
41593cd715deSSteven Rostedt (Red Hat) {
41603cd715deSSteven Rostedt (Red Hat) int ret;
41613cd715deSSteven Rostedt (Red Hat)
41623cd715deSSteven Rostedt (Red Hat) ret = register_ftrace_command(&event_enable_cmd);
41633cd715deSSteven Rostedt (Red Hat) if (WARN_ON(ret < 0))
41643cd715deSSteven Rostedt (Red Hat) return ret;
41653cd715deSSteven Rostedt (Red Hat) ret = register_ftrace_command(&event_disable_cmd);
41663cd715deSSteven Rostedt (Red Hat) if (WARN_ON(ret < 0))
41673cd715deSSteven Rostedt (Red Hat) unregister_ftrace_command(&event_enable_cmd);
41683cd715deSSteven Rostedt (Red Hat) return ret;
41693cd715deSSteven Rostedt (Red Hat) }
41703cd715deSSteven Rostedt (Red Hat) #else
register_event_cmds(void)41713cd715deSSteven Rostedt (Red Hat) static inline int register_event_cmds(void) { return 0; }
41723cd715deSSteven Rostedt (Red Hat) #endif /* CONFIG_DYNAMIC_FTRACE */
41733cd715deSSteven Rostedt (Red Hat)
417477248221SSteven Rostedt /*
4175720dee53SMasami Hiramatsu * The top level array and trace arrays created by boot-time tracing
4176720dee53SMasami Hiramatsu * have already had its trace_event_file descriptors created in order
4177720dee53SMasami Hiramatsu * to allow for early events to be recorded.
4178720dee53SMasami Hiramatsu * This function is called after the tracefs has been initialized,
4179720dee53SMasami Hiramatsu * and we now have to create the files associated to the events.
418077248221SSteven Rostedt */
__trace_early_add_event_dirs(struct trace_array * tr)4181720dee53SMasami Hiramatsu static void __trace_early_add_event_dirs(struct trace_array *tr)
418277248221SSteven Rostedt {
41837f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
418477248221SSteven Rostedt int ret;
418577248221SSteven Rostedt
418677248221SSteven Rostedt
418777248221SSteven Rostedt list_for_each_entry(file, &tr->events, list) {
4188620a30e9SOleg Nesterov ret = event_create_dir(tr->event_dir, file);
418977248221SSteven Rostedt if (ret < 0)
41903448bac3SFabian Frederick pr_warn("Could not create directory for event %s\n",
4191687fcc4aSSteven Rostedt (Red Hat) trace_event_name(file->event_call));
419277248221SSteven Rostedt }
419377248221SSteven Rostedt }
419477248221SSteven Rostedt
419577248221SSteven Rostedt /*
4196720dee53SMasami Hiramatsu * For early boot up, the top trace array and the trace arrays created
4197720dee53SMasami Hiramatsu * by boot-time tracing require to have a list of events that can be
4198720dee53SMasami Hiramatsu * enabled. This must be done before the filesystem is set up in order
4199720dee53SMasami Hiramatsu * to allow events to be traced early.
420077248221SSteven Rostedt */
__trace_early_add_events(struct trace_array * tr)4201720dee53SMasami Hiramatsu void __trace_early_add_events(struct trace_array *tr)
420277248221SSteven Rostedt {
42032425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call;
420477248221SSteven Rostedt int ret;
420577248221SSteven Rostedt
420677248221SSteven Rostedt list_for_each_entry(call, &ftrace_events, list) {
420777248221SSteven Rostedt /* Early boot up should not have any modules loaded */
42081d18538eSSteven Rostedt (VMware) if (!(call->flags & TRACE_EVENT_FL_DYNAMIC) &&
42091d18538eSSteven Rostedt (VMware) WARN_ON_ONCE(call->module))
421077248221SSteven Rostedt continue;
421177248221SSteven Rostedt
421277248221SSteven Rostedt ret = __trace_early_add_new_event(call, tr);
421377248221SSteven Rostedt if (ret < 0)
42143448bac3SFabian Frederick pr_warn("Could not create early event %s\n",
4215687fcc4aSSteven Rostedt (Red Hat) trace_event_name(call));
421677248221SSteven Rostedt }
421777248221SSteven Rostedt }
421877248221SSteven Rostedt
42190c8916c3SSteven Rostedt /* Remove the event directory structure for a trace directory. */
42200c8916c3SSteven Rostedt static void
__trace_remove_event_dirs(struct trace_array * tr)42210c8916c3SSteven Rostedt __trace_remove_event_dirs(struct trace_array *tr)
42220c8916c3SSteven Rostedt {
42237f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file, *next;
42240c8916c3SSteven Rostedt
4225f6a84bdcSOleg Nesterov list_for_each_entry_safe(file, next, &tr->events, list)
4226f6a84bdcSOleg Nesterov remove_event_file_dir(file);
42270c8916c3SSteven Rostedt }
42280c8916c3SSteven Rostedt
__add_event_to_tracers(struct trace_event_call * call)42292425bcb9SSteven Rostedt (Red Hat) static void __add_event_to_tracers(struct trace_event_call *call)
4230ae63b31eSSteven Rostedt {
4231ae63b31eSSteven Rostedt struct trace_array *tr;
4232ae63b31eSSteven Rostedt
4233620a30e9SOleg Nesterov list_for_each_entry(tr, &ftrace_trace_arrays, list)
4234620a30e9SOleg Nesterov __trace_add_new_event(call, tr);
4235ae63b31eSSteven Rostedt }
4236ae63b31eSSteven Rostedt
42372425bcb9SSteven Rostedt (Red Hat) extern struct trace_event_call *__start_ftrace_events[];
42382425bcb9SSteven Rostedt (Red Hat) extern struct trace_event_call *__stop_ftrace_events[];
4239a59fd602SSteven Rostedt
4240020e5f85SLi Zefan static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
4241020e5f85SLi Zefan
setup_trace_event(char * str)4242020e5f85SLi Zefan static __init int setup_trace_event(char *str)
4243020e5f85SLi Zefan {
4244c7dce4c5SAzeem Shaikh strscpy(bootup_event_buf, str, COMMAND_LINE_SIZE);
4245a1f157c7SZheng Yejian trace_set_ring_buffer_expanded(NULL);
424660efe21eSMasami Hiramatsu disable_tracing_selftest("running event tracing");
4247020e5f85SLi Zefan
4248020e5f85SLi Zefan return 1;
4249020e5f85SLi Zefan }
4250020e5f85SLi Zefan __setup("trace_event=", setup_trace_event);
4251020e5f85SLi Zefan
events_callback(const char * name,umode_t * mode,void ** data,const struct file_operations ** fops)42525790b1fbSSteven Rostedt (Google) static int events_callback(const char *name, umode_t *mode, void **data,
42535790b1fbSSteven Rostedt (Google) const struct file_operations **fops)
42545790b1fbSSteven Rostedt (Google) {
42555790b1fbSSteven Rostedt (Google) if (strcmp(name, "enable") == 0) {
42565790b1fbSSteven Rostedt (Google) *mode = TRACE_MODE_WRITE;
42575790b1fbSSteven Rostedt (Google) *fops = &ftrace_tr_enable_fops;
42585790b1fbSSteven Rostedt (Google) return 1;
42595790b1fbSSteven Rostedt (Google) }
42605790b1fbSSteven Rostedt (Google)
4261139f8400STzvetomir Stoyanov (VMware) if (strcmp(name, "header_page") == 0) {
4262139f8400STzvetomir Stoyanov (VMware) *mode = TRACE_MODE_READ;
4263139f8400STzvetomir Stoyanov (VMware) *fops = &ftrace_show_header_page_fops;
42645790b1fbSSteven Rostedt (Google)
4265139f8400STzvetomir Stoyanov (VMware) } else if (strcmp(name, "header_event") == 0) {
4266139f8400STzvetomir Stoyanov (VMware) *mode = TRACE_MODE_READ;
4267139f8400STzvetomir Stoyanov (VMware) *fops = &ftrace_show_header_event_fops;
4268139f8400STzvetomir Stoyanov (VMware) } else
42695790b1fbSSteven Rostedt (Google) return 0;
42705790b1fbSSteven Rostedt (Google)
42715790b1fbSSteven Rostedt (Google) return 1;
42725790b1fbSSteven Rostedt (Google) }
42735790b1fbSSteven Rostedt (Google)
427477248221SSteven Rostedt /* Expects to have event_mutex held when called */
427577248221SSteven Rostedt static int
create_event_toplevel_files(struct dentry * parent,struct trace_array * tr)427677248221SSteven Rostedt create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
4277ae63b31eSSteven Rostedt {
42785790b1fbSSteven Rostedt (Google) struct eventfs_inode *e_events;
4279ae63b31eSSteven Rostedt struct dentry *entry;
42805790b1fbSSteven Rostedt (Google) int nr_entries;
42815790b1fbSSteven Rostedt (Google) static struct eventfs_entry events_entries[] = {
42825790b1fbSSteven Rostedt (Google) {
42835790b1fbSSteven Rostedt (Google) .name = "enable",
42845790b1fbSSteven Rostedt (Google) .callback = events_callback,
42855790b1fbSSteven Rostedt (Google) },
42865790b1fbSSteven Rostedt (Google) {
42875790b1fbSSteven Rostedt (Google) .name = "header_page",
42885790b1fbSSteven Rostedt (Google) .callback = events_callback,
42895790b1fbSSteven Rostedt (Google) },
42905790b1fbSSteven Rostedt (Google) {
42915790b1fbSSteven Rostedt (Google) .name = "header_event",
42925790b1fbSSteven Rostedt (Google) .callback = events_callback,
42935790b1fbSSteven Rostedt (Google) },
42945790b1fbSSteven Rostedt (Google) };
4295ae63b31eSSteven Rostedt
4296e4931b82SYuntao Wang entry = trace_create_file("set_event", TRACE_MODE_WRITE, parent,
4297ae63b31eSSteven Rostedt tr, &ftrace_set_event_fops);
4298e4931b82SYuntao Wang if (!entry)
4299ae63b31eSSteven Rostedt return -ENOMEM;
4300ae63b31eSSteven Rostedt
43015790b1fbSSteven Rostedt (Google) nr_entries = ARRAY_SIZE(events_entries);
43025790b1fbSSteven Rostedt (Google)
43035790b1fbSSteven Rostedt (Google) e_events = eventfs_create_events_dir("events", parent, events_entries,
43045790b1fbSSteven Rostedt (Google) nr_entries, tr);
43055790b1fbSSteven Rostedt (Google) if (IS_ERR(e_events)) {
43068434dc93SSteven Rostedt (Red Hat) pr_warn("Could not create tracefs 'events' directory\n");
4307277ba044SSteven Rostedt return -ENOMEM;
4308277ba044SSteven Rostedt }
4309ae63b31eSSteven Rostedt
43107d436400SSteven Rostedt (Red Hat) /* There are not as crucial, just warn if they are not created */
43117d436400SSteven Rostedt (Red Hat)
4312e4931b82SYuntao Wang trace_create_file("set_event_pid", TRACE_MODE_WRITE, parent,
431349090107SSteven Rostedt (Red Hat) tr, &ftrace_set_event_pid_fops);
431449090107SSteven Rostedt (Red Hat)
4315e4931b82SYuntao Wang trace_create_file("set_event_notrace_pid",
431621ccc9cdSSteven Rostedt (VMware) TRACE_MODE_WRITE, parent, tr,
431721ccc9cdSSteven Rostedt (VMware) &ftrace_set_event_notrace_pid_fops);
431827683626SSteven Rostedt (VMware)
43195790b1fbSSteven Rostedt (Google) tr->event_dir = e_events;
432077248221SSteven Rostedt
432177248221SSteven Rostedt return 0;
432277248221SSteven Rostedt }
432377248221SSteven Rostedt
432477248221SSteven Rostedt /**
432577248221SSteven Rostedt * event_trace_add_tracer - add a instance of a trace_array to events
432677248221SSteven Rostedt * @parent: The parent dentry to place the files/directories for events in
432777248221SSteven Rostedt * @tr: The trace array associated with these events
432877248221SSteven Rostedt *
432977248221SSteven Rostedt * When a new instance is created, it needs to set up its events
433077248221SSteven Rostedt * directory, as well as other files associated with events. It also
43312b5894ccSQiujun Huang * creates the event hierarchy in the @parent/events directory.
433277248221SSteven Rostedt *
433377248221SSteven Rostedt * Returns 0 on success.
433412ecef0cSSteven Rostedt (VMware) *
433512ecef0cSSteven Rostedt (VMware) * Must be called with event_mutex held.
433677248221SSteven Rostedt */
event_trace_add_tracer(struct dentry * parent,struct trace_array * tr)433777248221SSteven Rostedt int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
433877248221SSteven Rostedt {
433977248221SSteven Rostedt int ret;
434077248221SSteven Rostedt
434112ecef0cSSteven Rostedt (VMware) lockdep_assert_held(&event_mutex);
434277248221SSteven Rostedt
434377248221SSteven Rostedt ret = create_event_toplevel_files(parent, tr);
434477248221SSteven Rostedt if (ret)
434512ecef0cSSteven Rostedt (VMware) goto out;
434677248221SSteven Rostedt
434752f6ad6dSzhangwei(Jovi) down_write(&trace_event_sem);
4348720dee53SMasami Hiramatsu /* If tr already has the event list, it is initialized in early boot. */
4349720dee53SMasami Hiramatsu if (unlikely(!list_empty(&tr->events)))
4350720dee53SMasami Hiramatsu __trace_early_add_event_dirs(tr);
4351720dee53SMasami Hiramatsu else
4352ae63b31eSSteven Rostedt __trace_add_event_dirs(tr);
435352f6ad6dSzhangwei(Jovi) up_write(&trace_event_sem);
4354277ba044SSteven Rostedt
435512ecef0cSSteven Rostedt (VMware) out:
435677248221SSteven Rostedt return ret;
435777248221SSteven Rostedt }
435877248221SSteven Rostedt
435977248221SSteven Rostedt /*
436077248221SSteven Rostedt * The top trace array already had its file descriptors created.
436177248221SSteven Rostedt * Now the files themselves need to be created.
436277248221SSteven Rostedt */
436377248221SSteven Rostedt static __init int
early_event_add_tracer(struct dentry * parent,struct trace_array * tr)436477248221SSteven Rostedt early_event_add_tracer(struct dentry *parent, struct trace_array *tr)
436577248221SSteven Rostedt {
436677248221SSteven Rostedt int ret;
436777248221SSteven Rostedt
436859980d9bSSteven Rostedt guard(mutex)(&event_mutex);
436977248221SSteven Rostedt
437077248221SSteven Rostedt ret = create_event_toplevel_files(parent, tr);
437177248221SSteven Rostedt if (ret)
437259980d9bSSteven Rostedt return ret;
437377248221SSteven Rostedt
437452f6ad6dSzhangwei(Jovi) down_write(&trace_event_sem);
437577248221SSteven Rostedt __trace_early_add_event_dirs(tr);
437652f6ad6dSzhangwei(Jovi) up_write(&trace_event_sem);
437777248221SSteven Rostedt
437859980d9bSSteven Rostedt return 0;
4379ae63b31eSSteven Rostedt }
4380ae63b31eSSteven Rostedt
438112ecef0cSSteven Rostedt (VMware) /* Must be called with event_mutex held */
event_trace_del_tracer(struct trace_array * tr)43820c8916c3SSteven Rostedt int event_trace_del_tracer(struct trace_array *tr)
43830c8916c3SSteven Rostedt {
438412ecef0cSSteven Rostedt (VMware) lockdep_assert_held(&event_mutex);
43850c8916c3SSteven Rostedt
438685f2b082STom Zanussi /* Disable any event triggers and associated soft-disabled events */
438785f2b082STom Zanussi clear_event_triggers(tr);
438885f2b082STom Zanussi
438949090107SSteven Rostedt (Red Hat) /* Clear the pid list */
439027683626SSteven Rostedt (VMware) __ftrace_clear_event_pids(tr, TRACE_PIDS | TRACE_NO_PIDS);
439149090107SSteven Rostedt (Red Hat)
43922a6c24afSSteven Rostedt (Red Hat) /* Disable any running events */
43934c86bc53SSteven Rostedt __ftrace_set_clr_event_nolock(tr, NULL, NULL, NULL, 0, NULL);
43942a6c24afSSteven Rostedt (Red Hat)
4395e0a568dcSSteven Rostedt (VMware) /* Make sure no more events are being executed */
4396e0a568dcSSteven Rostedt (VMware) tracepoint_synchronize_unregister();
43973ccb0123SSteven Rostedt
439852f6ad6dSzhangwei(Jovi) down_write(&trace_event_sem);
43990c8916c3SSteven Rostedt __trace_remove_event_dirs(tr);
44002819f23aSSteven Rostedt (Google) eventfs_remove_events_dir(tr->event_dir);
440152f6ad6dSzhangwei(Jovi) up_write(&trace_event_sem);
44020c8916c3SSteven Rostedt
44030c8916c3SSteven Rostedt tr->event_dir = NULL;
44040c8916c3SSteven Rostedt
44050c8916c3SSteven Rostedt return 0;
44060c8916c3SSteven Rostedt }
44070c8916c3SSteven Rostedt
event_trace_memsetup(void)4408d1a29143SSteven Rostedt static __init int event_trace_memsetup(void)
4409d1a29143SSteven Rostedt {
4410d1a29143SSteven Rostedt field_cachep = KMEM_CACHE(ftrace_event_field, SLAB_PANIC);
44117f1d2f82SSteven Rostedt (Red Hat) file_cachep = KMEM_CACHE(trace_event_file, SLAB_PANIC);
4412d1a29143SSteven Rostedt return 0;
4413d1a29143SSteven Rostedt }
4414d1a29143SSteven Rostedt
4415c4846480SSteven Rostedt (Google) __init void
early_enable_events(struct trace_array * tr,char * buf,bool disable_first)4416c4846480SSteven Rostedt (Google) early_enable_events(struct trace_array *tr, char *buf, bool disable_first)
4417ce1039bdSSteven Rostedt (Red Hat) {
4418ce1039bdSSteven Rostedt (Red Hat) char *token;
4419ce1039bdSSteven Rostedt (Red Hat) int ret;
4420ce1039bdSSteven Rostedt (Red Hat)
4421ce1039bdSSteven Rostedt (Red Hat) while (true) {
4422ce1039bdSSteven Rostedt (Red Hat) token = strsep(&buf, ",");
4423ce1039bdSSteven Rostedt (Red Hat)
4424ce1039bdSSteven Rostedt (Red Hat) if (!token)
4425ce1039bdSSteven Rostedt (Red Hat) break;
4426ce1039bdSSteven Rostedt (Red Hat)
442743ed3843SSteven Rostedt (Red Hat) if (*token) {
4428ce1039bdSSteven Rostedt (Red Hat) /* Restarting syscalls requires that we stop them first */
4429ce1039bdSSteven Rostedt (Red Hat) if (disable_first)
4430ce1039bdSSteven Rostedt (Red Hat) ftrace_set_clr_event(tr, token, 0);
4431ce1039bdSSteven Rostedt (Red Hat)
4432ce1039bdSSteven Rostedt (Red Hat) ret = ftrace_set_clr_event(tr, token, 1);
4433ce1039bdSSteven Rostedt (Red Hat) if (ret)
4434ce1039bdSSteven Rostedt (Red Hat) pr_warn("Failed to enable trace event: %s\n", token);
443543ed3843SSteven Rostedt (Red Hat) }
4436ce1039bdSSteven Rostedt (Red Hat)
4437ce1039bdSSteven Rostedt (Red Hat) /* Put back the comma to allow this to be called again */
4438ce1039bdSSteven Rostedt (Red Hat) if (buf)
4439ce1039bdSSteven Rostedt (Red Hat) *(buf - 1) = ',';
4440ce1039bdSSteven Rostedt (Red Hat) }
4441ce1039bdSSteven Rostedt (Red Hat) }
4442ce1039bdSSteven Rostedt (Red Hat)
event_trace_enable(void)44438781915aSEzequiel Garcia static __init int event_trace_enable(void)
44448781915aSEzequiel Garcia {
4445ae63b31eSSteven Rostedt struct trace_array *tr = top_trace_array();
44462425bcb9SSteven Rostedt (Red Hat) struct trace_event_call **iter, *call;
44478781915aSEzequiel Garcia int ret;
44488781915aSEzequiel Garcia
4449dc81e5e3SYoshihiro YUNOMAE if (!tr)
4450dc81e5e3SYoshihiro YUNOMAE return -ENODEV;
4451dc81e5e3SYoshihiro YUNOMAE
44528781915aSEzequiel Garcia for_each_event(iter, __start_ftrace_events, __stop_ftrace_events) {
44538781915aSEzequiel Garcia
44548781915aSEzequiel Garcia call = *iter;
44558781915aSEzequiel Garcia ret = event_init(call);
44568781915aSEzequiel Garcia if (!ret)
44578781915aSEzequiel Garcia list_add(&call->list, &ftrace_events);
44588781915aSEzequiel Garcia }
44598781915aSEzequiel Garcia
4460a01fdc89SSteven Rostedt (Google) register_trigger_cmds();
4461a01fdc89SSteven Rostedt (Google)
446277248221SSteven Rostedt /*
446377248221SSteven Rostedt * We need the top trace array to have a working set of trace
446477248221SSteven Rostedt * points at early init, before the debug files and directories
446577248221SSteven Rostedt * are created. Create the file entries now, and attach them
446677248221SSteven Rostedt * to the actual file dentries later.
446777248221SSteven Rostedt */
446877248221SSteven Rostedt __trace_early_add_events(tr);
446977248221SSteven Rostedt
4470c4846480SSteven Rostedt (Google) early_enable_events(tr, bootup_event_buf, false);
447181698831SSteven Rostedt
447281698831SSteven Rostedt trace_printk_start_comm();
447381698831SSteven Rostedt
44743cd715deSSteven Rostedt (Red Hat) register_event_cmds();
44753cd715deSSteven Rostedt (Red Hat)
447685f2b082STom Zanussi
44778781915aSEzequiel Garcia return 0;
44788781915aSEzequiel Garcia }
44798781915aSEzequiel Garcia
4480ce1039bdSSteven Rostedt (Red Hat) /*
4481ce1039bdSSteven Rostedt (Red Hat) * event_trace_enable() is called from trace_event_init() first to
4482ce1039bdSSteven Rostedt (Red Hat) * initialize events and perhaps start any events that are on the
4483ce1039bdSSteven Rostedt (Red Hat) * command line. Unfortunately, there are some events that will not
4484ce1039bdSSteven Rostedt (Red Hat) * start this early, like the system call tracepoints that need
4485524666cbSGabriel Krisman Bertazi * to set the %SYSCALL_WORK_SYSCALL_TRACEPOINT flag of pid 1. But
4486524666cbSGabriel Krisman Bertazi * event_trace_enable() is called before pid 1 starts, and this flag
4487524666cbSGabriel Krisman Bertazi * is never set, making the syscall tracepoint never get reached, but
4488524666cbSGabriel Krisman Bertazi * the event is enabled regardless (and not doing anything).
4489ce1039bdSSteven Rostedt (Red Hat) */
event_trace_enable_again(void)4490ce1039bdSSteven Rostedt (Red Hat) static __init int event_trace_enable_again(void)
4491ce1039bdSSteven Rostedt (Red Hat) {
4492ce1039bdSSteven Rostedt (Red Hat) struct trace_array *tr;
4493ce1039bdSSteven Rostedt (Red Hat)
4494ce1039bdSSteven Rostedt (Red Hat) tr = top_trace_array();
4495ce1039bdSSteven Rostedt (Red Hat) if (!tr)
4496ce1039bdSSteven Rostedt (Red Hat) return -ENODEV;
4497ce1039bdSSteven Rostedt (Red Hat)
4498c4846480SSteven Rostedt (Google) early_enable_events(tr, bootup_event_buf, true);
4499ce1039bdSSteven Rostedt (Red Hat)
4500ce1039bdSSteven Rostedt (Red Hat) return 0;
4501ce1039bdSSteven Rostedt (Red Hat) }
4502ce1039bdSSteven Rostedt (Red Hat)
4503ce1039bdSSteven Rostedt (Red Hat) early_initcall(event_trace_enable_again);
4504ce1039bdSSteven Rostedt (Red Hat)
4505ac343da7SMasami Hiramatsu /* Init fields which doesn't related to the tracefs */
event_trace_init_fields(void)4506ac343da7SMasami Hiramatsu static __init int event_trace_init_fields(void)
4507ac343da7SMasami Hiramatsu {
4508ac343da7SMasami Hiramatsu if (trace_define_generic_fields())
4509ac343da7SMasami Hiramatsu pr_warn("tracing: Failed to allocated generic fields");
4510ac343da7SMasami Hiramatsu
4511ac343da7SMasami Hiramatsu if (trace_define_common_fields())
4512ac343da7SMasami Hiramatsu pr_warn("tracing: Failed to allocate common fields");
4513ac343da7SMasami Hiramatsu
4514ac343da7SMasami Hiramatsu return 0;
4515ac343da7SMasami Hiramatsu }
4516ac343da7SMasami Hiramatsu
event_trace_init(void)451758b92547SSteven Rostedt (VMware) __init int event_trace_init(void)
4518b77e38aaSSteven Rostedt {
4519ae63b31eSSteven Rostedt struct trace_array *tr;
45206d723736SSteven Rostedt int ret;
4521b77e38aaSSteven Rostedt
4522ae63b31eSSteven Rostedt tr = top_trace_array();
4523dc81e5e3SYoshihiro YUNOMAE if (!tr)
4524dc81e5e3SYoshihiro YUNOMAE return -ENODEV;
4525ae63b31eSSteven Rostedt
4526e4931b82SYuntao Wang trace_create_file("available_events", TRACE_MODE_READ,
452721ccc9cdSSteven Rostedt (VMware) NULL, tr, &ftrace_avail_fops);
45282314c4aeSSteven Rostedt
4529dc300d77SWei Yang ret = early_event_add_tracer(NULL, tr);
4530ae63b31eSSteven Rostedt if (ret)
4531ae63b31eSSteven Rostedt return ret;
4532020e5f85SLi Zefan
4533836d481eSOleg Nesterov #ifdef CONFIG_MODULES
45346d723736SSteven Rostedt ret = register_module_notifier(&trace_module_nb);
453555379376SMing Lei if (ret)
45363448bac3SFabian Frederick pr_warn("Failed to register trace events module notifier\n");
4537836d481eSOleg Nesterov #endif
4538a838deabSMasami Hiramatsu
4539a838deabSMasami Hiramatsu eventdir_initialized = true;
4540a838deabSMasami Hiramatsu
4541b77e38aaSSteven Rostedt return 0;
4542b77e38aaSSteven Rostedt }
45435f893b26SSteven Rostedt (Red Hat)
trace_event_init(void)45445f893b26SSteven Rostedt (Red Hat) void __init trace_event_init(void)
45455f893b26SSteven Rostedt (Red Hat) {
45465f893b26SSteven Rostedt (Red Hat) event_trace_memsetup();
45475f893b26SSteven Rostedt (Red Hat) init_ftrace_syscalls();
45485f893b26SSteven Rostedt (Red Hat) event_trace_enable();
4549ac343da7SMasami Hiramatsu event_trace_init_fields();
45505f893b26SSteven Rostedt (Red Hat) }
45515f893b26SSteven Rostedt (Red Hat)
4552b3015fe4SSteven Rostedt (VMware) #ifdef CONFIG_EVENT_TRACE_STARTUP_TEST
4553e6187007SSteven Rostedt
4554e6187007SSteven Rostedt static DEFINE_SPINLOCK(test_spinlock);
4555e6187007SSteven Rostedt static DEFINE_SPINLOCK(test_spinlock_irq);
4556e6187007SSteven Rostedt static DEFINE_MUTEX(test_mutex);
4557e6187007SSteven Rostedt
test_work(struct work_struct * dummy)4558e6187007SSteven Rostedt static __init void test_work(struct work_struct *dummy)
4559e6187007SSteven Rostedt {
4560e6187007SSteven Rostedt spin_lock(&test_spinlock);
4561e6187007SSteven Rostedt spin_lock_irq(&test_spinlock_irq);
4562e6187007SSteven Rostedt udelay(1);
4563e6187007SSteven Rostedt spin_unlock_irq(&test_spinlock_irq);
4564e6187007SSteven Rostedt spin_unlock(&test_spinlock);
4565e6187007SSteven Rostedt
4566e6187007SSteven Rostedt mutex_lock(&test_mutex);
4567e6187007SSteven Rostedt msleep(1);
4568e6187007SSteven Rostedt mutex_unlock(&test_mutex);
4569e6187007SSteven Rostedt }
4570e6187007SSteven Rostedt
event_test_thread(void * unused)4571e6187007SSteven Rostedt static __init int event_test_thread(void *unused)
4572e6187007SSteven Rostedt {
4573e6187007SSteven Rostedt void *test_malloc;
4574e6187007SSteven Rostedt
4575e6187007SSteven Rostedt test_malloc = kmalloc(1234, GFP_KERNEL);
4576e6187007SSteven Rostedt if (!test_malloc)
4577e6187007SSteven Rostedt pr_info("failed to kmalloc\n");
4578e6187007SSteven Rostedt
4579e6187007SSteven Rostedt schedule_on_each_cpu(test_work);
4580e6187007SSteven Rostedt
4581e6187007SSteven Rostedt kfree(test_malloc);
4582e6187007SSteven Rostedt
4583e6187007SSteven Rostedt set_current_state(TASK_INTERRUPTIBLE);
4584fe0e01c7SPeter Zijlstra while (!kthread_should_stop()) {
4585e6187007SSteven Rostedt schedule();
4586fe0e01c7SPeter Zijlstra set_current_state(TASK_INTERRUPTIBLE);
4587fe0e01c7SPeter Zijlstra }
4588fe0e01c7SPeter Zijlstra __set_current_state(TASK_RUNNING);
4589e6187007SSteven Rostedt
4590e6187007SSteven Rostedt return 0;
4591e6187007SSteven Rostedt }
4592e6187007SSteven Rostedt
4593e6187007SSteven Rostedt /*
4594e6187007SSteven Rostedt * Do various things that may trigger events.
4595e6187007SSteven Rostedt */
event_test_stuff(void)4596e6187007SSteven Rostedt static __init void event_test_stuff(void)
4597e6187007SSteven Rostedt {
4598e6187007SSteven Rostedt struct task_struct *test_thread;
4599e6187007SSteven Rostedt
4600e6187007SSteven Rostedt test_thread = kthread_run(event_test_thread, NULL, "test-events");
4601e6187007SSteven Rostedt msleep(1);
4602e6187007SSteven Rostedt kthread_stop(test_thread);
4603e6187007SSteven Rostedt }
4604e6187007SSteven Rostedt
4605e6187007SSteven Rostedt /*
4606e6187007SSteven Rostedt * For every trace event defined, we will test each trace point separately,
4607e6187007SSteven Rostedt * and then by groups, and finally all trace points.
4608e6187007SSteven Rostedt */
event_trace_self_tests(void)46099ea21c1eSSteven Rostedt static __init void event_trace_self_tests(void)
4610e6187007SSteven Rostedt {
46117967b3e0SSteven Rostedt (Red Hat) struct trace_subsystem_dir *dir;
46127f1d2f82SSteven Rostedt (Red Hat) struct trace_event_file *file;
46132425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call;
4614e6187007SSteven Rostedt struct event_subsystem *system;
4615ae63b31eSSteven Rostedt struct trace_array *tr;
4616e6187007SSteven Rostedt int ret;
4617e6187007SSteven Rostedt
4618ae63b31eSSteven Rostedt tr = top_trace_array();
4619dc81e5e3SYoshihiro YUNOMAE if (!tr)
4620dc81e5e3SYoshihiro YUNOMAE return;
4621ae63b31eSSteven Rostedt
4622e6187007SSteven Rostedt pr_info("Running tests on trace events:\n");
4623e6187007SSteven Rostedt
4624ae63b31eSSteven Rostedt list_for_each_entry(file, &tr->events, list) {
4625ae63b31eSSteven Rostedt
4626ae63b31eSSteven Rostedt call = file->event_call;
4627e6187007SSteven Rostedt
46282239291aSSteven Rostedt /* Only test those that have a probe */
46292239291aSSteven Rostedt if (!call->class || !call->class->probe)
4630e6187007SSteven Rostedt continue;
4631e6187007SSteven Rostedt
46321f5a6b45SSteven Rostedt /*
46331f5a6b45SSteven Rostedt * Testing syscall events here is pretty useless, but
46341f5a6b45SSteven Rostedt * we still do it if configured. But this is time consuming.
46351f5a6b45SSteven Rostedt * What we really need is a user thread to perform the
46361f5a6b45SSteven Rostedt * syscalls as we test.
46371f5a6b45SSteven Rostedt */
46381f5a6b45SSteven Rostedt #ifndef CONFIG_EVENT_TRACE_TEST_SYSCALLS
46398f082018SSteven Rostedt if (call->class->system &&
46408f082018SSteven Rostedt strcmp(call->class->system, "syscalls") == 0)
46411f5a6b45SSteven Rostedt continue;
46421f5a6b45SSteven Rostedt #endif
46431f5a6b45SSteven Rostedt
4644687fcc4aSSteven Rostedt (Red Hat) pr_info("Testing event %s: ", trace_event_name(call));
4645e6187007SSteven Rostedt
4646e6187007SSteven Rostedt /*
4647e6187007SSteven Rostedt * If an event is already enabled, someone is using
4648e6187007SSteven Rostedt * it and the self test should not be on.
4649e6187007SSteven Rostedt */
46505d6ad960SSteven Rostedt (Red Hat) if (file->flags & EVENT_FILE_FL_ENABLED) {
46513448bac3SFabian Frederick pr_warn("Enabled event during self test!\n");
4652e6187007SSteven Rostedt WARN_ON_ONCE(1);
4653e6187007SSteven Rostedt continue;
4654e6187007SSteven Rostedt }
4655e6187007SSteven Rostedt
4656ae63b31eSSteven Rostedt ftrace_event_enable_disable(file, 1);
4657e6187007SSteven Rostedt event_test_stuff();
4658ae63b31eSSteven Rostedt ftrace_event_enable_disable(file, 0);
4659e6187007SSteven Rostedt
4660e6187007SSteven Rostedt pr_cont("OK\n");
4661e6187007SSteven Rostedt }
4662e6187007SSteven Rostedt
4663e6187007SSteven Rostedt /* Now test at the sub system level */
4664e6187007SSteven Rostedt
4665e6187007SSteven Rostedt pr_info("Running tests on trace event systems:\n");
4666e6187007SSteven Rostedt
4667ae63b31eSSteven Rostedt list_for_each_entry(dir, &tr->systems, list) {
4668ae63b31eSSteven Rostedt
4669ae63b31eSSteven Rostedt system = dir->subsystem;
4670e6187007SSteven Rostedt
4671e6187007SSteven Rostedt /* the ftrace system is special, skip it */
4672e6187007SSteven Rostedt if (strcmp(system->name, "ftrace") == 0)
4673e6187007SSteven Rostedt continue;
4674e6187007SSteven Rostedt
4675e6187007SSteven Rostedt pr_info("Testing event system %s: ", system->name);
4676e6187007SSteven Rostedt
46774c86bc53SSteven Rostedt ret = __ftrace_set_clr_event(tr, NULL, system->name, NULL, 1, NULL);
4678e6187007SSteven Rostedt if (WARN_ON_ONCE(ret)) {
46793448bac3SFabian Frederick pr_warn("error enabling system %s\n",
4680e6187007SSteven Rostedt system->name);
4681e6187007SSteven Rostedt continue;
4682e6187007SSteven Rostedt }
4683e6187007SSteven Rostedt
4684e6187007SSteven Rostedt event_test_stuff();
4685e6187007SSteven Rostedt
46864c86bc53SSteven Rostedt ret = __ftrace_set_clr_event(tr, NULL, system->name, NULL, 0, NULL);
468776bab1b7SYuanhan Liu if (WARN_ON_ONCE(ret)) {
46883448bac3SFabian Frederick pr_warn("error disabling system %s\n",
4689e6187007SSteven Rostedt system->name);
469076bab1b7SYuanhan Liu continue;
469176bab1b7SYuanhan Liu }
4692e6187007SSteven Rostedt
4693e6187007SSteven Rostedt pr_cont("OK\n");
4694e6187007SSteven Rostedt }
4695e6187007SSteven Rostedt
4696e6187007SSteven Rostedt /* Test with all events enabled */
4697e6187007SSteven Rostedt
4698e6187007SSteven Rostedt pr_info("Running tests on all trace events:\n");
4699e6187007SSteven Rostedt pr_info("Testing all events: ");
4700e6187007SSteven Rostedt
47014c86bc53SSteven Rostedt ret = __ftrace_set_clr_event(tr, NULL, NULL, NULL, 1, NULL);
4702e6187007SSteven Rostedt if (WARN_ON_ONCE(ret)) {
47033448bac3SFabian Frederick pr_warn("error enabling all events\n");
47049ea21c1eSSteven Rostedt return;
4705e6187007SSteven Rostedt }
4706e6187007SSteven Rostedt
4707e6187007SSteven Rostedt event_test_stuff();
4708e6187007SSteven Rostedt
4709e6187007SSteven Rostedt /* reset sysname */
47104c86bc53SSteven Rostedt ret = __ftrace_set_clr_event(tr, NULL, NULL, NULL, 0, NULL);
4711e6187007SSteven Rostedt if (WARN_ON_ONCE(ret)) {
47123448bac3SFabian Frederick pr_warn("error disabling all events\n");
47139ea21c1eSSteven Rostedt return;
4714e6187007SSteven Rostedt }
4715e6187007SSteven Rostedt
4716e6187007SSteven Rostedt pr_cont("OK\n");
47179ea21c1eSSteven Rostedt }
47189ea21c1eSSteven Rostedt
47199ea21c1eSSteven Rostedt #ifdef CONFIG_FUNCTION_TRACER
47209ea21c1eSSteven Rostedt
4721245b2e70STejun Heo static DEFINE_PER_CPU(atomic_t, ftrace_test_event_disable);
47229ea21c1eSSteven Rostedt
47239b9db275SSteven Rostedt (Red Hat) static struct trace_event_file event_trace_file __initdata;
4724b7f0c959SSteven Rostedt (Red Hat)
4725b7f0c959SSteven Rostedt (Red Hat) static void __init
function_test_events_call(unsigned long ip,unsigned long parent_ip,struct ftrace_ops * op,struct ftrace_regs * regs)47262f5f6ad9SSteven Rostedt function_test_events_call(unsigned long ip, unsigned long parent_ip,
4727d19ad077SSteven Rostedt (VMware) struct ftrace_ops *op, struct ftrace_regs *regs)
47289ea21c1eSSteven Rostedt {
472913292494SSteven Rostedt (VMware) struct trace_buffer *buffer;
47309ea21c1eSSteven Rostedt struct ring_buffer_event *event;
47319ea21c1eSSteven Rostedt struct ftrace_entry *entry;
473236590c50SSebastian Andrzej Siewior unsigned int trace_ctx;
47339ea21c1eSSteven Rostedt long disabled;
47349ea21c1eSSteven Rostedt int cpu;
47359ea21c1eSSteven Rostedt
473636590c50SSebastian Andrzej Siewior trace_ctx = tracing_gen_ctx();
47375168ae50SSteven Rostedt preempt_disable_notrace();
47389ea21c1eSSteven Rostedt cpu = raw_smp_processor_id();
4739245b2e70STejun Heo disabled = atomic_inc_return(&per_cpu(ftrace_test_event_disable, cpu));
47409ea21c1eSSteven Rostedt
47419ea21c1eSSteven Rostedt if (disabled != 1)
47429ea21c1eSSteven Rostedt goto out;
47439ea21c1eSSteven Rostedt
47449b9db275SSteven Rostedt (Red Hat) event = trace_event_buffer_lock_reserve(&buffer, &event_trace_file,
4745e77405adSSteven Rostedt TRACE_FN, sizeof(*entry),
474636590c50SSebastian Andrzej Siewior trace_ctx);
47479ea21c1eSSteven Rostedt if (!event)
47489ea21c1eSSteven Rostedt goto out;
47499ea21c1eSSteven Rostedt entry = ring_buffer_event_data(event);
47509ea21c1eSSteven Rostedt entry->ip = ip;
47519ea21c1eSSteven Rostedt entry->parent_ip = parent_ip;
47529ea21c1eSSteven Rostedt
47539b9db275SSteven Rostedt (Red Hat) event_trigger_unlock_commit(&event_trace_file, buffer, event,
475436590c50SSebastian Andrzej Siewior entry, trace_ctx);
47559ea21c1eSSteven Rostedt out:
4756245b2e70STejun Heo atomic_dec(&per_cpu(ftrace_test_event_disable, cpu));
47575168ae50SSteven Rostedt preempt_enable_notrace();
47589ea21c1eSSteven Rostedt }
47599ea21c1eSSteven Rostedt
47609ea21c1eSSteven Rostedt static struct ftrace_ops trace_ops __initdata =
47619ea21c1eSSteven Rostedt {
47629ea21c1eSSteven Rostedt .func = function_test_events_call,
47639ea21c1eSSteven Rostedt };
47649ea21c1eSSteven Rostedt
event_trace_self_test_with_function(void)47659ea21c1eSSteven Rostedt static __init void event_trace_self_test_with_function(void)
47669ea21c1eSSteven Rostedt {
476717bb615aSSteven Rostedt int ret;
47689b9db275SSteven Rostedt (Red Hat)
47699b9db275SSteven Rostedt (Red Hat) event_trace_file.tr = top_trace_array();
47709b9db275SSteven Rostedt (Red Hat) if (WARN_ON(!event_trace_file.tr))
47712d34f489SSteven Rostedt (Red Hat) return;
47729b9db275SSteven Rostedt (Red Hat)
477317bb615aSSteven Rostedt ret = register_ftrace_function(&trace_ops);
477417bb615aSSteven Rostedt if (WARN_ON(ret < 0)) {
477517bb615aSSteven Rostedt pr_info("Failed to enable function tracer for event tests\n");
477617bb615aSSteven Rostedt return;
477717bb615aSSteven Rostedt }
47789ea21c1eSSteven Rostedt pr_info("Running tests again, along with the function tracer\n");
47799ea21c1eSSteven Rostedt event_trace_self_tests();
47809ea21c1eSSteven Rostedt unregister_ftrace_function(&trace_ops);
47819ea21c1eSSteven Rostedt }
47829ea21c1eSSteven Rostedt #else
event_trace_self_test_with_function(void)47839ea21c1eSSteven Rostedt static __init void event_trace_self_test_with_function(void)
47849ea21c1eSSteven Rostedt {
47859ea21c1eSSteven Rostedt }
47869ea21c1eSSteven Rostedt #endif
47879ea21c1eSSteven Rostedt
event_trace_self_tests_init(void)47889ea21c1eSSteven Rostedt static __init int event_trace_self_tests_init(void)
47899ea21c1eSSteven Rostedt {
4790020e5f85SLi Zefan if (!tracing_selftest_disabled) {
47919ea21c1eSSteven Rostedt event_trace_self_tests();
47929ea21c1eSSteven Rostedt event_trace_self_test_with_function();
4793020e5f85SLi Zefan }
4794e6187007SSteven Rostedt
4795e6187007SSteven Rostedt return 0;
4796e6187007SSteven Rostedt }
4797e6187007SSteven Rostedt
479828d20e2dSSteven Rostedt late_initcall(event_trace_self_tests_init);
4799e6187007SSteven Rostedt
4800e6187007SSteven Rostedt #endif
4801