1*287e80b3SSadaf Ebrahimi // SPDX-License-Identifier: LGPL-2.1
2*287e80b3SSadaf Ebrahimi /*
3*287e80b3SSadaf Ebrahimi * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <[email protected]>
4*287e80b3SSadaf Ebrahimi *
5*287e80b3SSadaf Ebrahimi * Updates:
6*287e80b3SSadaf Ebrahimi * Copyright (C) 2019, VMware, Tzvetomir Stoyanov <[email protected]>
7*287e80b3SSadaf Ebrahimi *
8*287e80b3SSadaf Ebrahimi */
9*287e80b3SSadaf Ebrahimi #include <stdio.h>
10*287e80b3SSadaf Ebrahimi #include <stdlib.h>
11*287e80b3SSadaf Ebrahimi #include <dirent.h>
12*287e80b3SSadaf Ebrahimi #include <unistd.h>
13*287e80b3SSadaf Ebrahimi #include <errno.h>
14*287e80b3SSadaf Ebrahimi #include <sys/stat.h>
15*287e80b3SSadaf Ebrahimi #include <fcntl.h>
16*287e80b3SSadaf Ebrahimi #include <limits.h>
17*287e80b3SSadaf Ebrahimi
18*287e80b3SSadaf Ebrahimi #include <kbuffer.h>
19*287e80b3SSadaf Ebrahimi
20*287e80b3SSadaf Ebrahimi #include "tracefs.h"
21*287e80b3SSadaf Ebrahimi #include "tracefs-local.h"
22*287e80b3SSadaf Ebrahimi
23*287e80b3SSadaf Ebrahimi static struct follow_event *root_followers;
24*287e80b3SSadaf Ebrahimi static int nr_root_followers;
25*287e80b3SSadaf Ebrahimi
26*287e80b3SSadaf Ebrahimi static struct follow_event *root_missed_followers;
27*287e80b3SSadaf Ebrahimi static int nr_root_missed_followers;
28*287e80b3SSadaf Ebrahimi
29*287e80b3SSadaf Ebrahimi struct cpu_iterate {
30*287e80b3SSadaf Ebrahimi struct tracefs_cpu *tcpu;
31*287e80b3SSadaf Ebrahimi struct tep_record record;
32*287e80b3SSadaf Ebrahimi struct tep_event *event;
33*287e80b3SSadaf Ebrahimi struct kbuffer *kbuf;
34*287e80b3SSadaf Ebrahimi void *page;
35*287e80b3SSadaf Ebrahimi int psize;
36*287e80b3SSadaf Ebrahimi int cpu;
37*287e80b3SSadaf Ebrahimi };
38*287e80b3SSadaf Ebrahimi
read_kbuf_record(struct cpu_iterate * cpu)39*287e80b3SSadaf Ebrahimi static int read_kbuf_record(struct cpu_iterate *cpu)
40*287e80b3SSadaf Ebrahimi {
41*287e80b3SSadaf Ebrahimi unsigned long long ts;
42*287e80b3SSadaf Ebrahimi void *ptr;
43*287e80b3SSadaf Ebrahimi
44*287e80b3SSadaf Ebrahimi if (!cpu || !cpu->kbuf)
45*287e80b3SSadaf Ebrahimi return -1;
46*287e80b3SSadaf Ebrahimi ptr = kbuffer_read_event(cpu->kbuf, &ts);
47*287e80b3SSadaf Ebrahimi if (!ptr)
48*287e80b3SSadaf Ebrahimi return -1;
49*287e80b3SSadaf Ebrahimi
50*287e80b3SSadaf Ebrahimi memset(&cpu->record, 0, sizeof(cpu->record));
51*287e80b3SSadaf Ebrahimi cpu->record.ts = ts;
52*287e80b3SSadaf Ebrahimi cpu->record.size = kbuffer_event_size(cpu->kbuf);
53*287e80b3SSadaf Ebrahimi cpu->record.record_size = kbuffer_curr_size(cpu->kbuf);
54*287e80b3SSadaf Ebrahimi cpu->record.missed_events = kbuffer_missed_events(cpu->kbuf);
55*287e80b3SSadaf Ebrahimi cpu->record.cpu = cpu->cpu;
56*287e80b3SSadaf Ebrahimi cpu->record.data = ptr;
57*287e80b3SSadaf Ebrahimi cpu->record.ref_count = 1;
58*287e80b3SSadaf Ebrahimi
59*287e80b3SSadaf Ebrahimi kbuffer_next_event(cpu->kbuf, NULL);
60*287e80b3SSadaf Ebrahimi
61*287e80b3SSadaf Ebrahimi return 0;
62*287e80b3SSadaf Ebrahimi }
63*287e80b3SSadaf Ebrahimi
read_next_page(struct tep_handle * tep,struct cpu_iterate * cpu)64*287e80b3SSadaf Ebrahimi int read_next_page(struct tep_handle *tep, struct cpu_iterate *cpu)
65*287e80b3SSadaf Ebrahimi {
66*287e80b3SSadaf Ebrahimi enum kbuffer_long_size long_size;
67*287e80b3SSadaf Ebrahimi enum kbuffer_endian endian;
68*287e80b3SSadaf Ebrahimi int r;
69*287e80b3SSadaf Ebrahimi
70*287e80b3SSadaf Ebrahimi if (!cpu->tcpu)
71*287e80b3SSadaf Ebrahimi return -1;
72*287e80b3SSadaf Ebrahimi
73*287e80b3SSadaf Ebrahimi r = tracefs_cpu_buffered_read(cpu->tcpu, cpu->page, true);
74*287e80b3SSadaf Ebrahimi /*
75*287e80b3SSadaf Ebrahimi * tracefs_cpu_buffered_read() only reads in full subbuffer size,
76*287e80b3SSadaf Ebrahimi * but this wants partial buffers as well. If the function returns
77*287e80b3SSadaf Ebrahimi * empty (-1 for EAGAIN), try tracefs_cpu_read() next, as that can
78*287e80b3SSadaf Ebrahimi * read partially filled buffers too, but isn't as efficient.
79*287e80b3SSadaf Ebrahimi */
80*287e80b3SSadaf Ebrahimi if (r <= 0)
81*287e80b3SSadaf Ebrahimi r = tracefs_cpu_read(cpu->tcpu, cpu->page, true);
82*287e80b3SSadaf Ebrahimi if (r <= 0)
83*287e80b3SSadaf Ebrahimi return -1;
84*287e80b3SSadaf Ebrahimi
85*287e80b3SSadaf Ebrahimi if (!cpu->kbuf) {
86*287e80b3SSadaf Ebrahimi if (tep_is_file_bigendian(tep))
87*287e80b3SSadaf Ebrahimi endian = KBUFFER_ENDIAN_BIG;
88*287e80b3SSadaf Ebrahimi else
89*287e80b3SSadaf Ebrahimi endian = KBUFFER_ENDIAN_LITTLE;
90*287e80b3SSadaf Ebrahimi
91*287e80b3SSadaf Ebrahimi if (tep_get_header_page_size(tep) == 8)
92*287e80b3SSadaf Ebrahimi long_size = KBUFFER_LSIZE_8;
93*287e80b3SSadaf Ebrahimi else
94*287e80b3SSadaf Ebrahimi long_size = KBUFFER_LSIZE_4;
95*287e80b3SSadaf Ebrahimi
96*287e80b3SSadaf Ebrahimi cpu->kbuf = kbuffer_alloc(long_size, endian);
97*287e80b3SSadaf Ebrahimi if (!cpu->kbuf)
98*287e80b3SSadaf Ebrahimi return -1;
99*287e80b3SSadaf Ebrahimi }
100*287e80b3SSadaf Ebrahimi
101*287e80b3SSadaf Ebrahimi kbuffer_load_subbuffer(cpu->kbuf, cpu->page);
102*287e80b3SSadaf Ebrahimi if (kbuffer_subbuffer_size(cpu->kbuf) > r) {
103*287e80b3SSadaf Ebrahimi tracefs_warning("%s: page_size > %d", __func__, r);
104*287e80b3SSadaf Ebrahimi return -1;
105*287e80b3SSadaf Ebrahimi }
106*287e80b3SSadaf Ebrahimi
107*287e80b3SSadaf Ebrahimi return 0;
108*287e80b3SSadaf Ebrahimi }
109*287e80b3SSadaf Ebrahimi
read_next_record(struct tep_handle * tep,struct cpu_iterate * cpu)110*287e80b3SSadaf Ebrahimi int read_next_record(struct tep_handle *tep, struct cpu_iterate *cpu)
111*287e80b3SSadaf Ebrahimi {
112*287e80b3SSadaf Ebrahimi int id;
113*287e80b3SSadaf Ebrahimi
114*287e80b3SSadaf Ebrahimi do {
115*287e80b3SSadaf Ebrahimi while (!read_kbuf_record(cpu)) {
116*287e80b3SSadaf Ebrahimi id = tep_data_type(tep, &(cpu->record));
117*287e80b3SSadaf Ebrahimi cpu->event = tep_find_event(tep, id);
118*287e80b3SSadaf Ebrahimi if (cpu->event)
119*287e80b3SSadaf Ebrahimi return 0;
120*287e80b3SSadaf Ebrahimi }
121*287e80b3SSadaf Ebrahimi } while (!read_next_page(tep, cpu));
122*287e80b3SSadaf Ebrahimi
123*287e80b3SSadaf Ebrahimi return -1;
124*287e80b3SSadaf Ebrahimi }
125*287e80b3SSadaf Ebrahimi
126*287e80b3SSadaf Ebrahimi /**
127*287e80b3SSadaf Ebrahimi * tracefs_follow_missed_events - Add callback for missed events for iterators
128*287e80b3SSadaf Ebrahimi * @instance: The instance to follow
129*287e80b3SSadaf Ebrahimi * @callback: The function to call when missed events is detected
130*287e80b3SSadaf Ebrahimi * @callback_data: The data to pass to @callback
131*287e80b3SSadaf Ebrahimi *
132*287e80b3SSadaf Ebrahimi * This attaches a callback to an @instance or the root instance if @instance
133*287e80b3SSadaf Ebrahimi * is NULL, where if tracefs_iterate_raw_events() is called, that if missed
134*287e80b3SSadaf Ebrahimi * events are detected, it will call @callback, with the following parameters:
135*287e80b3SSadaf Ebrahimi * @event: The event pointer of the record with the missing events
136*287e80b3SSadaf Ebrahimi * @record; The event instance of @event.
137*287e80b3SSadaf Ebrahimi * @cpu: The cpu that the event happened on.
138*287e80b3SSadaf Ebrahimi * @callback_data: The same as @callback_data passed to the function.
139*287e80b3SSadaf Ebrahimi *
140*287e80b3SSadaf Ebrahimi * If the count of missing events is available, @record->missed_events
141*287e80b3SSadaf Ebrahimi * will have a positive number holding the number of missed events since
142*287e80b3SSadaf Ebrahimi * the last event on the same CPU, or just -1 if that number is unknown
143*287e80b3SSadaf Ebrahimi * but missed events did happen.
144*287e80b3SSadaf Ebrahimi *
145*287e80b3SSadaf Ebrahimi * Returns 0 on success and -1 on error.
146*287e80b3SSadaf Ebrahimi */
tracefs_follow_missed_events(struct tracefs_instance * instance,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_data)147*287e80b3SSadaf Ebrahimi int tracefs_follow_missed_events(struct tracefs_instance *instance,
148*287e80b3SSadaf Ebrahimi int (*callback)(struct tep_event *,
149*287e80b3SSadaf Ebrahimi struct tep_record *,
150*287e80b3SSadaf Ebrahimi int, void *),
151*287e80b3SSadaf Ebrahimi void *callback_data)
152*287e80b3SSadaf Ebrahimi {
153*287e80b3SSadaf Ebrahimi struct follow_event **followers;
154*287e80b3SSadaf Ebrahimi struct follow_event *follower;
155*287e80b3SSadaf Ebrahimi struct follow_event follow;
156*287e80b3SSadaf Ebrahimi int *nr_followers;
157*287e80b3SSadaf Ebrahimi
158*287e80b3SSadaf Ebrahimi follow.event = NULL;
159*287e80b3SSadaf Ebrahimi follow.callback = callback;
160*287e80b3SSadaf Ebrahimi follow.callback_data = callback_data;
161*287e80b3SSadaf Ebrahimi
162*287e80b3SSadaf Ebrahimi if (instance) {
163*287e80b3SSadaf Ebrahimi followers = &instance->missed_followers;
164*287e80b3SSadaf Ebrahimi nr_followers = &instance->nr_missed_followers;
165*287e80b3SSadaf Ebrahimi } else {
166*287e80b3SSadaf Ebrahimi followers = &root_missed_followers;
167*287e80b3SSadaf Ebrahimi nr_followers = &nr_root_missed_followers;
168*287e80b3SSadaf Ebrahimi }
169*287e80b3SSadaf Ebrahimi follower = realloc(*followers, sizeof(*follower) *
170*287e80b3SSadaf Ebrahimi ((*nr_followers) + 1));
171*287e80b3SSadaf Ebrahimi if (!follower)
172*287e80b3SSadaf Ebrahimi return -1;
173*287e80b3SSadaf Ebrahimi
174*287e80b3SSadaf Ebrahimi *followers = follower;
175*287e80b3SSadaf Ebrahimi follower[(*nr_followers)++] = follow;
176*287e80b3SSadaf Ebrahimi
177*287e80b3SSadaf Ebrahimi return 0;
178*287e80b3SSadaf Ebrahimi }
179*287e80b3SSadaf Ebrahimi
call_missed_events(struct tracefs_instance * instance,struct tep_event * event,struct tep_record * record,int cpu)180*287e80b3SSadaf Ebrahimi static int call_missed_events(struct tracefs_instance *instance,
181*287e80b3SSadaf Ebrahimi struct tep_event *event, struct tep_record *record, int cpu)
182*287e80b3SSadaf Ebrahimi {
183*287e80b3SSadaf Ebrahimi struct follow_event *followers;
184*287e80b3SSadaf Ebrahimi int nr_followers;
185*287e80b3SSadaf Ebrahimi int ret = 0;
186*287e80b3SSadaf Ebrahimi int i;
187*287e80b3SSadaf Ebrahimi
188*287e80b3SSadaf Ebrahimi if (instance) {
189*287e80b3SSadaf Ebrahimi followers = instance->missed_followers;
190*287e80b3SSadaf Ebrahimi nr_followers = instance->nr_missed_followers;
191*287e80b3SSadaf Ebrahimi } else {
192*287e80b3SSadaf Ebrahimi followers = root_missed_followers;
193*287e80b3SSadaf Ebrahimi nr_followers = nr_root_missed_followers;
194*287e80b3SSadaf Ebrahimi }
195*287e80b3SSadaf Ebrahimi
196*287e80b3SSadaf Ebrahimi if (!followers)
197*287e80b3SSadaf Ebrahimi return 0;
198*287e80b3SSadaf Ebrahimi
199*287e80b3SSadaf Ebrahimi for (i = 0; i < nr_followers; i++) {
200*287e80b3SSadaf Ebrahimi ret |= followers[i].callback(event, record,
201*287e80b3SSadaf Ebrahimi cpu, followers[i].callback_data);
202*287e80b3SSadaf Ebrahimi }
203*287e80b3SSadaf Ebrahimi
204*287e80b3SSadaf Ebrahimi return ret;
205*287e80b3SSadaf Ebrahimi }
206*287e80b3SSadaf Ebrahimi
call_followers(struct tracefs_instance * instance,struct tep_event * event,struct tep_record * record,int cpu)207*287e80b3SSadaf Ebrahimi static int call_followers(struct tracefs_instance *instance,
208*287e80b3SSadaf Ebrahimi struct tep_event *event, struct tep_record *record, int cpu)
209*287e80b3SSadaf Ebrahimi {
210*287e80b3SSadaf Ebrahimi struct follow_event *followers;
211*287e80b3SSadaf Ebrahimi int nr_followers;
212*287e80b3SSadaf Ebrahimi int ret = 0;
213*287e80b3SSadaf Ebrahimi int i;
214*287e80b3SSadaf Ebrahimi
215*287e80b3SSadaf Ebrahimi if (record->missed_events)
216*287e80b3SSadaf Ebrahimi ret = call_missed_events(instance, event, record, cpu);
217*287e80b3SSadaf Ebrahimi if (ret)
218*287e80b3SSadaf Ebrahimi return ret;
219*287e80b3SSadaf Ebrahimi
220*287e80b3SSadaf Ebrahimi if (instance) {
221*287e80b3SSadaf Ebrahimi followers = instance->followers;
222*287e80b3SSadaf Ebrahimi nr_followers = instance->nr_followers;
223*287e80b3SSadaf Ebrahimi } else {
224*287e80b3SSadaf Ebrahimi followers = root_followers;
225*287e80b3SSadaf Ebrahimi nr_followers = nr_root_followers;
226*287e80b3SSadaf Ebrahimi }
227*287e80b3SSadaf Ebrahimi
228*287e80b3SSadaf Ebrahimi if (!followers)
229*287e80b3SSadaf Ebrahimi return 0;
230*287e80b3SSadaf Ebrahimi
231*287e80b3SSadaf Ebrahimi for (i = 0; i < nr_followers; i++) {
232*287e80b3SSadaf Ebrahimi if (followers[i].event == event)
233*287e80b3SSadaf Ebrahimi ret |= followers[i].callback(event, record,
234*287e80b3SSadaf Ebrahimi cpu, followers[i].callback_data);
235*287e80b3SSadaf Ebrahimi }
236*287e80b3SSadaf Ebrahimi
237*287e80b3SSadaf Ebrahimi return ret;
238*287e80b3SSadaf Ebrahimi }
239*287e80b3SSadaf Ebrahimi
read_cpu_pages(struct tep_handle * tep,struct tracefs_instance * instance,struct cpu_iterate * cpus,int count,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_context,bool * keep_going)240*287e80b3SSadaf Ebrahimi static int read_cpu_pages(struct tep_handle *tep, struct tracefs_instance *instance,
241*287e80b3SSadaf Ebrahimi struct cpu_iterate *cpus, int count,
242*287e80b3SSadaf Ebrahimi int (*callback)(struct tep_event *,
243*287e80b3SSadaf Ebrahimi struct tep_record *,
244*287e80b3SSadaf Ebrahimi int, void *),
245*287e80b3SSadaf Ebrahimi void *callback_context,
246*287e80b3SSadaf Ebrahimi bool *keep_going)
247*287e80b3SSadaf Ebrahimi {
248*287e80b3SSadaf Ebrahimi bool has_data = false;
249*287e80b3SSadaf Ebrahimi int ret;
250*287e80b3SSadaf Ebrahimi int i, j;
251*287e80b3SSadaf Ebrahimi
252*287e80b3SSadaf Ebrahimi for (i = 0; i < count; i++) {
253*287e80b3SSadaf Ebrahimi ret = read_next_record(tep, cpus + i);
254*287e80b3SSadaf Ebrahimi if (!ret)
255*287e80b3SSadaf Ebrahimi has_data = true;
256*287e80b3SSadaf Ebrahimi }
257*287e80b3SSadaf Ebrahimi
258*287e80b3SSadaf Ebrahimi while (has_data && *(volatile bool *)keep_going) {
259*287e80b3SSadaf Ebrahimi j = count;
260*287e80b3SSadaf Ebrahimi for (i = 0; i < count; i++) {
261*287e80b3SSadaf Ebrahimi if (!cpus[i].event)
262*287e80b3SSadaf Ebrahimi continue;
263*287e80b3SSadaf Ebrahimi if (j == count || cpus[j].record.ts > cpus[i].record.ts)
264*287e80b3SSadaf Ebrahimi j = i;
265*287e80b3SSadaf Ebrahimi }
266*287e80b3SSadaf Ebrahimi if (j < count) {
267*287e80b3SSadaf Ebrahimi if (call_followers(instance, cpus[j].event, &cpus[j].record, cpus[j].cpu))
268*287e80b3SSadaf Ebrahimi break;
269*287e80b3SSadaf Ebrahimi if (callback &&
270*287e80b3SSadaf Ebrahimi callback(cpus[j].event, &cpus[j].record, cpus[j].cpu, callback_context))
271*287e80b3SSadaf Ebrahimi break;
272*287e80b3SSadaf Ebrahimi cpus[j].event = NULL;
273*287e80b3SSadaf Ebrahimi read_next_record(tep, cpus + j);
274*287e80b3SSadaf Ebrahimi } else {
275*287e80b3SSadaf Ebrahimi has_data = false;
276*287e80b3SSadaf Ebrahimi }
277*287e80b3SSadaf Ebrahimi }
278*287e80b3SSadaf Ebrahimi
279*287e80b3SSadaf Ebrahimi return 0;
280*287e80b3SSadaf Ebrahimi }
281*287e80b3SSadaf Ebrahimi
open_cpu_files(struct tracefs_instance * instance,cpu_set_t * cpus,int cpu_size,struct cpu_iterate ** all_cpus,int * count)282*287e80b3SSadaf Ebrahimi static int open_cpu_files(struct tracefs_instance *instance, cpu_set_t *cpus,
283*287e80b3SSadaf Ebrahimi int cpu_size, struct cpu_iterate **all_cpus, int *count)
284*287e80b3SSadaf Ebrahimi {
285*287e80b3SSadaf Ebrahimi struct tracefs_cpu *tcpu;
286*287e80b3SSadaf Ebrahimi struct cpu_iterate *tmp;
287*287e80b3SSadaf Ebrahimi int nr_cpus;
288*287e80b3SSadaf Ebrahimi int cpu;
289*287e80b3SSadaf Ebrahimi int i = 0;
290*287e80b3SSadaf Ebrahimi
291*287e80b3SSadaf Ebrahimi *all_cpus = NULL;
292*287e80b3SSadaf Ebrahimi
293*287e80b3SSadaf Ebrahimi nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
294*287e80b3SSadaf Ebrahimi for (cpu = 0; cpu < nr_cpus; cpu++) {
295*287e80b3SSadaf Ebrahimi if (cpus && !CPU_ISSET_S(cpu, cpu_size, cpus))
296*287e80b3SSadaf Ebrahimi continue;
297*287e80b3SSadaf Ebrahimi tcpu = tracefs_cpu_open(instance, cpu, true);
298*287e80b3SSadaf Ebrahimi tmp = realloc(*all_cpus, (i + 1) * sizeof(*tmp));
299*287e80b3SSadaf Ebrahimi if (!tmp) {
300*287e80b3SSadaf Ebrahimi i--;
301*287e80b3SSadaf Ebrahimi goto error;
302*287e80b3SSadaf Ebrahimi }
303*287e80b3SSadaf Ebrahimi
304*287e80b3SSadaf Ebrahimi *all_cpus = tmp;
305*287e80b3SSadaf Ebrahimi
306*287e80b3SSadaf Ebrahimi memset(tmp + i, 0, sizeof(*tmp));
307*287e80b3SSadaf Ebrahimi
308*287e80b3SSadaf Ebrahimi if (!tcpu)
309*287e80b3SSadaf Ebrahimi goto error;
310*287e80b3SSadaf Ebrahimi
311*287e80b3SSadaf Ebrahimi tmp[i].tcpu = tcpu;
312*287e80b3SSadaf Ebrahimi tmp[i].cpu = cpu;
313*287e80b3SSadaf Ebrahimi tmp[i].psize = tracefs_cpu_read_size(tcpu);
314*287e80b3SSadaf Ebrahimi tmp[i].page = malloc(tmp[i].psize);
315*287e80b3SSadaf Ebrahimi
316*287e80b3SSadaf Ebrahimi if (!tmp[i++].page)
317*287e80b3SSadaf Ebrahimi goto error;
318*287e80b3SSadaf Ebrahimi }
319*287e80b3SSadaf Ebrahimi *count = i;
320*287e80b3SSadaf Ebrahimi return 0;
321*287e80b3SSadaf Ebrahimi error:
322*287e80b3SSadaf Ebrahimi tmp = *all_cpus;
323*287e80b3SSadaf Ebrahimi for (; i >= 0; i--) {
324*287e80b3SSadaf Ebrahimi tracefs_cpu_close(tmp[i].tcpu);
325*287e80b3SSadaf Ebrahimi free(tmp[i].page);
326*287e80b3SSadaf Ebrahimi }
327*287e80b3SSadaf Ebrahimi free(tmp);
328*287e80b3SSadaf Ebrahimi *all_cpus = NULL;
329*287e80b3SSadaf Ebrahimi return -1;
330*287e80b3SSadaf Ebrahimi }
331*287e80b3SSadaf Ebrahimi
332*287e80b3SSadaf Ebrahimi /**
333*287e80b3SSadaf Ebrahimi * tracefs_follow_event - Add callback for specific events for iterators
334*287e80b3SSadaf Ebrahimi * @tep: a handle to the trace event parser context
335*287e80b3SSadaf Ebrahimi * @instance: The instance to follow
336*287e80b3SSadaf Ebrahimi * @system: The system of the event to track
337*287e80b3SSadaf Ebrahimi * @event_name: The name of the event to track
338*287e80b3SSadaf Ebrahimi * @callback: The function to call when the event is hit in an iterator
339*287e80b3SSadaf Ebrahimi * @callback_data: The data to pass to @callback
340*287e80b3SSadaf Ebrahimi *
341*287e80b3SSadaf Ebrahimi * This attaches a callback to an @instance or the root instance if @instance
342*287e80b3SSadaf Ebrahimi * is NULL, where if tracefs_iterate_raw_events() is called, that if the specified
343*287e80b3SSadaf Ebrahimi * event is hit, it will call @callback, with the following parameters:
344*287e80b3SSadaf Ebrahimi * @event: The event pointer that was found by @system and @event_name.
345*287e80b3SSadaf Ebrahimi * @record; The event instance of @event.
346*287e80b3SSadaf Ebrahimi * @cpu: The cpu that the event happened on.
347*287e80b3SSadaf Ebrahimi * @callback_data: The same as @callback_data passed to the function.
348*287e80b3SSadaf Ebrahimi *
349*287e80b3SSadaf Ebrahimi * Returns 0 on success and -1 on error.
350*287e80b3SSadaf Ebrahimi */
tracefs_follow_event(struct tep_handle * tep,struct tracefs_instance * instance,const char * system,const char * event_name,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_data)351*287e80b3SSadaf Ebrahimi int tracefs_follow_event(struct tep_handle *tep, struct tracefs_instance *instance,
352*287e80b3SSadaf Ebrahimi const char *system, const char *event_name,
353*287e80b3SSadaf Ebrahimi int (*callback)(struct tep_event *,
354*287e80b3SSadaf Ebrahimi struct tep_record *,
355*287e80b3SSadaf Ebrahimi int, void *),
356*287e80b3SSadaf Ebrahimi void *callback_data)
357*287e80b3SSadaf Ebrahimi {
358*287e80b3SSadaf Ebrahimi struct follow_event **followers;
359*287e80b3SSadaf Ebrahimi struct follow_event *follower;
360*287e80b3SSadaf Ebrahimi struct follow_event follow;
361*287e80b3SSadaf Ebrahimi int *nr_followers;
362*287e80b3SSadaf Ebrahimi
363*287e80b3SSadaf Ebrahimi if (!tep) {
364*287e80b3SSadaf Ebrahimi errno = EINVAL;
365*287e80b3SSadaf Ebrahimi return -1;
366*287e80b3SSadaf Ebrahimi }
367*287e80b3SSadaf Ebrahimi
368*287e80b3SSadaf Ebrahimi follow.event = tep_find_event_by_name(tep, system, event_name);
369*287e80b3SSadaf Ebrahimi if (!follow.event) {
370*287e80b3SSadaf Ebrahimi errno = ENOENT;
371*287e80b3SSadaf Ebrahimi return -1;
372*287e80b3SSadaf Ebrahimi }
373*287e80b3SSadaf Ebrahimi
374*287e80b3SSadaf Ebrahimi follow.callback = callback;
375*287e80b3SSadaf Ebrahimi follow.callback_data = callback_data;
376*287e80b3SSadaf Ebrahimi
377*287e80b3SSadaf Ebrahimi if (instance) {
378*287e80b3SSadaf Ebrahimi followers = &instance->followers;
379*287e80b3SSadaf Ebrahimi nr_followers = &instance->nr_followers;
380*287e80b3SSadaf Ebrahimi } else {
381*287e80b3SSadaf Ebrahimi followers = &root_followers;
382*287e80b3SSadaf Ebrahimi nr_followers = &nr_root_followers;
383*287e80b3SSadaf Ebrahimi }
384*287e80b3SSadaf Ebrahimi follower = realloc(*followers, sizeof(*follower) *
385*287e80b3SSadaf Ebrahimi ((*nr_followers) + 1));
386*287e80b3SSadaf Ebrahimi if (!follower)
387*287e80b3SSadaf Ebrahimi return -1;
388*287e80b3SSadaf Ebrahimi
389*287e80b3SSadaf Ebrahimi *followers = follower;
390*287e80b3SSadaf Ebrahimi follower[(*nr_followers)++] = follow;
391*287e80b3SSadaf Ebrahimi
392*287e80b3SSadaf Ebrahimi return 0;
393*287e80b3SSadaf Ebrahimi }
394*287e80b3SSadaf Ebrahimi
395*287e80b3SSadaf Ebrahimi static bool top_iterate_keep_going;
396*287e80b3SSadaf Ebrahimi
397*287e80b3SSadaf Ebrahimi /*
398*287e80b3SSadaf Ebrahimi * tracefs_iterate_raw_events - Iterate through events in trace_pipe_raw,
399*287e80b3SSadaf Ebrahimi * per CPU trace buffers
400*287e80b3SSadaf Ebrahimi * @tep: a handle to the trace event parser context
401*287e80b3SSadaf Ebrahimi * @instance: ftrace instance, can be NULL for the top instance
402*287e80b3SSadaf Ebrahimi * @cpus: Iterate only through the buffers of CPUs, set in the mask.
403*287e80b3SSadaf Ebrahimi * If NULL, iterate through all CPUs.
404*287e80b3SSadaf Ebrahimi * @cpu_size: size of @cpus set
405*287e80b3SSadaf Ebrahimi * @callback: A user function, called for each record from the file
406*287e80b3SSadaf Ebrahimi * @callback_context: A custom context, passed to the user callback function
407*287e80b3SSadaf Ebrahimi *
408*287e80b3SSadaf Ebrahimi * If the @callback returns non-zero, the iteration stops - in that case all
409*287e80b3SSadaf Ebrahimi * records from the current page will be lost from future reads
410*287e80b3SSadaf Ebrahimi * The events are iterated in sorted order, oldest first.
411*287e80b3SSadaf Ebrahimi *
412*287e80b3SSadaf Ebrahimi * Returns -1 in case of an error, or 0 otherwise
413*287e80b3SSadaf Ebrahimi */
tracefs_iterate_raw_events(struct tep_handle * tep,struct tracefs_instance * instance,cpu_set_t * cpus,int cpu_size,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_context)414*287e80b3SSadaf Ebrahimi int tracefs_iterate_raw_events(struct tep_handle *tep,
415*287e80b3SSadaf Ebrahimi struct tracefs_instance *instance,
416*287e80b3SSadaf Ebrahimi cpu_set_t *cpus, int cpu_size,
417*287e80b3SSadaf Ebrahimi int (*callback)(struct tep_event *,
418*287e80b3SSadaf Ebrahimi struct tep_record *,
419*287e80b3SSadaf Ebrahimi int, void *),
420*287e80b3SSadaf Ebrahimi void *callback_context)
421*287e80b3SSadaf Ebrahimi {
422*287e80b3SSadaf Ebrahimi bool *keep_going = instance ? &instance->iterate_keep_going :
423*287e80b3SSadaf Ebrahimi &top_iterate_keep_going;
424*287e80b3SSadaf Ebrahimi struct follow_event *followers;
425*287e80b3SSadaf Ebrahimi struct cpu_iterate *all_cpus;
426*287e80b3SSadaf Ebrahimi int count = 0;
427*287e80b3SSadaf Ebrahimi int ret;
428*287e80b3SSadaf Ebrahimi int i;
429*287e80b3SSadaf Ebrahimi
430*287e80b3SSadaf Ebrahimi (*(volatile bool *)keep_going) = true;
431*287e80b3SSadaf Ebrahimi
432*287e80b3SSadaf Ebrahimi if (!tep)
433*287e80b3SSadaf Ebrahimi return -1;
434*287e80b3SSadaf Ebrahimi
435*287e80b3SSadaf Ebrahimi if (instance)
436*287e80b3SSadaf Ebrahimi followers = instance->followers;
437*287e80b3SSadaf Ebrahimi else
438*287e80b3SSadaf Ebrahimi followers = root_followers;
439*287e80b3SSadaf Ebrahimi if (!callback && !followers)
440*287e80b3SSadaf Ebrahimi return -1;
441*287e80b3SSadaf Ebrahimi
442*287e80b3SSadaf Ebrahimi ret = open_cpu_files(instance, cpus, cpu_size, &all_cpus, &count);
443*287e80b3SSadaf Ebrahimi if (ret < 0)
444*287e80b3SSadaf Ebrahimi goto out;
445*287e80b3SSadaf Ebrahimi ret = read_cpu_pages(tep, instance, all_cpus, count,
446*287e80b3SSadaf Ebrahimi callback, callback_context,
447*287e80b3SSadaf Ebrahimi keep_going);
448*287e80b3SSadaf Ebrahimi
449*287e80b3SSadaf Ebrahimi out:
450*287e80b3SSadaf Ebrahimi if (all_cpus) {
451*287e80b3SSadaf Ebrahimi for (i = 0; i < count; i++) {
452*287e80b3SSadaf Ebrahimi kbuffer_free(all_cpus[i].kbuf);
453*287e80b3SSadaf Ebrahimi tracefs_cpu_close(all_cpus[i].tcpu);
454*287e80b3SSadaf Ebrahimi free(all_cpus[i].page);
455*287e80b3SSadaf Ebrahimi }
456*287e80b3SSadaf Ebrahimi free(all_cpus);
457*287e80b3SSadaf Ebrahimi }
458*287e80b3SSadaf Ebrahimi
459*287e80b3SSadaf Ebrahimi return ret;
460*287e80b3SSadaf Ebrahimi }
461*287e80b3SSadaf Ebrahimi
462*287e80b3SSadaf Ebrahimi /**
463*287e80b3SSadaf Ebrahimi * tracefs_iterate_stop - stop the iteration over the raw events.
464*287e80b3SSadaf Ebrahimi * @instance: ftrace instance, can be NULL for top tracing instance.
465*287e80b3SSadaf Ebrahimi */
tracefs_iterate_stop(struct tracefs_instance * instance)466*287e80b3SSadaf Ebrahimi void tracefs_iterate_stop(struct tracefs_instance *instance)
467*287e80b3SSadaf Ebrahimi {
468*287e80b3SSadaf Ebrahimi if (instance)
469*287e80b3SSadaf Ebrahimi instance->iterate_keep_going = false;
470*287e80b3SSadaf Ebrahimi else
471*287e80b3SSadaf Ebrahimi top_iterate_keep_going = false;
472*287e80b3SSadaf Ebrahimi }
473*287e80b3SSadaf Ebrahimi
add_list_string(char *** list,const char * name)474*287e80b3SSadaf Ebrahimi static int add_list_string(char ***list, const char *name)
475*287e80b3SSadaf Ebrahimi {
476*287e80b3SSadaf Ebrahimi char **tmp;
477*287e80b3SSadaf Ebrahimi
478*287e80b3SSadaf Ebrahimi tmp = tracefs_list_add(*list, name);
479*287e80b3SSadaf Ebrahimi if (!tmp) {
480*287e80b3SSadaf Ebrahimi tracefs_list_free(*list);
481*287e80b3SSadaf Ebrahimi *list = NULL;
482*287e80b3SSadaf Ebrahimi return -1;
483*287e80b3SSadaf Ebrahimi }
484*287e80b3SSadaf Ebrahimi
485*287e80b3SSadaf Ebrahimi *list = tmp;
486*287e80b3SSadaf Ebrahimi return 0;
487*287e80b3SSadaf Ebrahimi }
488*287e80b3SSadaf Ebrahimi
trace_append_file(const char * dir,const char * name)489*287e80b3SSadaf Ebrahimi __hidden char *trace_append_file(const char *dir, const char *name)
490*287e80b3SSadaf Ebrahimi {
491*287e80b3SSadaf Ebrahimi char *file;
492*287e80b3SSadaf Ebrahimi int ret;
493*287e80b3SSadaf Ebrahimi
494*287e80b3SSadaf Ebrahimi ret = asprintf(&file, "%s/%s", dir, name);
495*287e80b3SSadaf Ebrahimi
496*287e80b3SSadaf Ebrahimi return ret < 0 ? NULL : file;
497*287e80b3SSadaf Ebrahimi }
498*287e80b3SSadaf Ebrahimi
event_file(char ** path,const char * system,const char * event,const char * file)499*287e80b3SSadaf Ebrahimi static int event_file(char **path, const char *system,
500*287e80b3SSadaf Ebrahimi const char *event, const char *file)
501*287e80b3SSadaf Ebrahimi {
502*287e80b3SSadaf Ebrahimi if (!system || !event || !file)
503*287e80b3SSadaf Ebrahimi return -1;
504*287e80b3SSadaf Ebrahimi
505*287e80b3SSadaf Ebrahimi return asprintf(path, "events/%s/%s/%s",
506*287e80b3SSadaf Ebrahimi system, event, file);
507*287e80b3SSadaf Ebrahimi }
508*287e80b3SSadaf Ebrahimi
509*287e80b3SSadaf Ebrahimi /**
510*287e80b3SSadaf Ebrahimi * tracefs_event_get_file - return a file in an event directory
511*287e80b3SSadaf Ebrahimi * @instance: The instance the event is in (NULL for top level)
512*287e80b3SSadaf Ebrahimi * @system: The system name that the event file is in
513*287e80b3SSadaf Ebrahimi * @event: The event name of the event
514*287e80b3SSadaf Ebrahimi * @file: The name of the file in the event directory.
515*287e80b3SSadaf Ebrahimi *
516*287e80b3SSadaf Ebrahimi * Returns a path to a file in the event director.
517*287e80b3SSadaf Ebrahimi * or NULL on error. The path returned must be freed with
518*287e80b3SSadaf Ebrahimi * tracefs_put_tracing_file().
519*287e80b3SSadaf Ebrahimi */
tracefs_event_get_file(struct tracefs_instance * instance,const char * system,const char * event,const char * file)520*287e80b3SSadaf Ebrahimi char *tracefs_event_get_file(struct tracefs_instance *instance,
521*287e80b3SSadaf Ebrahimi const char *system, const char *event,
522*287e80b3SSadaf Ebrahimi const char *file)
523*287e80b3SSadaf Ebrahimi {
524*287e80b3SSadaf Ebrahimi char *instance_path;
525*287e80b3SSadaf Ebrahimi char *path;
526*287e80b3SSadaf Ebrahimi int ret;
527*287e80b3SSadaf Ebrahimi
528*287e80b3SSadaf Ebrahimi ret = event_file(&path, system, event, file);
529*287e80b3SSadaf Ebrahimi if (ret < 0)
530*287e80b3SSadaf Ebrahimi return NULL;
531*287e80b3SSadaf Ebrahimi
532*287e80b3SSadaf Ebrahimi instance_path = tracefs_instance_get_file(instance, path);
533*287e80b3SSadaf Ebrahimi free(path);
534*287e80b3SSadaf Ebrahimi
535*287e80b3SSadaf Ebrahimi return instance_path;
536*287e80b3SSadaf Ebrahimi }
537*287e80b3SSadaf Ebrahimi
538*287e80b3SSadaf Ebrahimi /**
539*287e80b3SSadaf Ebrahimi * tracefs_event_file_read - read the content from an event file
540*287e80b3SSadaf Ebrahimi * @instance: The instance the event is in (NULL for top level)
541*287e80b3SSadaf Ebrahimi * @system: The system name that the event file is in
542*287e80b3SSadaf Ebrahimi * @event: The event name of the event
543*287e80b3SSadaf Ebrahimi * @file: The name of the file in the event directory.
544*287e80b3SSadaf Ebrahimi * @psize: the size of the content read.
545*287e80b3SSadaf Ebrahimi *
546*287e80b3SSadaf Ebrahimi * Reads the content of the event file that is passed via the
547*287e80b3SSadaf Ebrahimi * arguments and returns the content.
548*287e80b3SSadaf Ebrahimi *
549*287e80b3SSadaf Ebrahimi * Return a string containing the content of the file or NULL
550*287e80b3SSadaf Ebrahimi * on error. The string returned must be freed with free().
551*287e80b3SSadaf Ebrahimi */
tracefs_event_file_read(struct tracefs_instance * instance,const char * system,const char * event,const char * file,int * psize)552*287e80b3SSadaf Ebrahimi char *tracefs_event_file_read(struct tracefs_instance *instance,
553*287e80b3SSadaf Ebrahimi const char *system, const char *event,
554*287e80b3SSadaf Ebrahimi const char *file, int *psize)
555*287e80b3SSadaf Ebrahimi {
556*287e80b3SSadaf Ebrahimi char *content;
557*287e80b3SSadaf Ebrahimi char *path;
558*287e80b3SSadaf Ebrahimi int ret;
559*287e80b3SSadaf Ebrahimi
560*287e80b3SSadaf Ebrahimi ret = event_file(&path, system, event, file);
561*287e80b3SSadaf Ebrahimi if (ret < 0)
562*287e80b3SSadaf Ebrahimi return NULL;
563*287e80b3SSadaf Ebrahimi
564*287e80b3SSadaf Ebrahimi content = tracefs_instance_file_read(instance, path, psize);
565*287e80b3SSadaf Ebrahimi free(path);
566*287e80b3SSadaf Ebrahimi return content;
567*287e80b3SSadaf Ebrahimi }
568*287e80b3SSadaf Ebrahimi
569*287e80b3SSadaf Ebrahimi /**
570*287e80b3SSadaf Ebrahimi * tracefs_event_file_write - write to an event file
571*287e80b3SSadaf Ebrahimi * @instance: The instance the event is in (NULL for top level)
572*287e80b3SSadaf Ebrahimi * @system: The system name that the event file is in
573*287e80b3SSadaf Ebrahimi * @event: The event name of the event
574*287e80b3SSadaf Ebrahimi * @file: The name of the file in the event directory.
575*287e80b3SSadaf Ebrahimi * @str: The string to write into the file
576*287e80b3SSadaf Ebrahimi *
577*287e80b3SSadaf Ebrahimi * Writes the content of @str to a file in the instance directory.
578*287e80b3SSadaf Ebrahimi * The content of the file will be overwritten by @str.
579*287e80b3SSadaf Ebrahimi *
580*287e80b3SSadaf Ebrahimi * Return 0 on success, and -1 on error.
581*287e80b3SSadaf Ebrahimi */
tracefs_event_file_write(struct tracefs_instance * instance,const char * system,const char * event,const char * file,const char * str)582*287e80b3SSadaf Ebrahimi int tracefs_event_file_write(struct tracefs_instance *instance,
583*287e80b3SSadaf Ebrahimi const char *system, const char *event,
584*287e80b3SSadaf Ebrahimi const char *file, const char *str)
585*287e80b3SSadaf Ebrahimi {
586*287e80b3SSadaf Ebrahimi char *path;
587*287e80b3SSadaf Ebrahimi int ret;
588*287e80b3SSadaf Ebrahimi
589*287e80b3SSadaf Ebrahimi ret = event_file(&path, system, event, file);
590*287e80b3SSadaf Ebrahimi if (ret < 0)
591*287e80b3SSadaf Ebrahimi return -1;
592*287e80b3SSadaf Ebrahimi
593*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_write(instance, path, str);
594*287e80b3SSadaf Ebrahimi free(path);
595*287e80b3SSadaf Ebrahimi return ret;
596*287e80b3SSadaf Ebrahimi }
597*287e80b3SSadaf Ebrahimi
598*287e80b3SSadaf Ebrahimi /**
599*287e80b3SSadaf Ebrahimi * tracefs_event_file_append - write to an event file
600*287e80b3SSadaf Ebrahimi * @instance: The instance the event is in (NULL for top level)
601*287e80b3SSadaf Ebrahimi * @system: The system name that the event file is in
602*287e80b3SSadaf Ebrahimi * @event: The event name of the event
603*287e80b3SSadaf Ebrahimi * @file: The name of the file in the event directory.
604*287e80b3SSadaf Ebrahimi * @str: The string to write into the file
605*287e80b3SSadaf Ebrahimi *
606*287e80b3SSadaf Ebrahimi * Writes the content of @str to a file in the instance directory.
607*287e80b3SSadaf Ebrahimi * The content of @str will be appended to the content of the file.
608*287e80b3SSadaf Ebrahimi * The current content should not be lost.
609*287e80b3SSadaf Ebrahimi *
610*287e80b3SSadaf Ebrahimi * Return 0 on success, and -1 on error.
611*287e80b3SSadaf Ebrahimi */
tracefs_event_file_append(struct tracefs_instance * instance,const char * system,const char * event,const char * file,const char * str)612*287e80b3SSadaf Ebrahimi int tracefs_event_file_append(struct tracefs_instance *instance,
613*287e80b3SSadaf Ebrahimi const char *system, const char *event,
614*287e80b3SSadaf Ebrahimi const char *file, const char *str)
615*287e80b3SSadaf Ebrahimi {
616*287e80b3SSadaf Ebrahimi char *path;
617*287e80b3SSadaf Ebrahimi int ret;
618*287e80b3SSadaf Ebrahimi
619*287e80b3SSadaf Ebrahimi ret = event_file(&path, system, event, file);
620*287e80b3SSadaf Ebrahimi if (ret < 0)
621*287e80b3SSadaf Ebrahimi return -1;
622*287e80b3SSadaf Ebrahimi
623*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_append(instance, path, str);
624*287e80b3SSadaf Ebrahimi free(path);
625*287e80b3SSadaf Ebrahimi return ret;
626*287e80b3SSadaf Ebrahimi }
627*287e80b3SSadaf Ebrahimi
628*287e80b3SSadaf Ebrahimi /**
629*287e80b3SSadaf Ebrahimi * tracefs_event_file_clear - clear an event file
630*287e80b3SSadaf Ebrahimi * @instance: The instance the event is in (NULL for top level)
631*287e80b3SSadaf Ebrahimi * @system: The system name that the event file is in
632*287e80b3SSadaf Ebrahimi * @event: The event name of the event
633*287e80b3SSadaf Ebrahimi * @file: The name of the file in the event directory.
634*287e80b3SSadaf Ebrahimi *
635*287e80b3SSadaf Ebrahimi * Clears the content of the event file. That is, it is opened
636*287e80b3SSadaf Ebrahimi * with O_TRUNC and then closed.
637*287e80b3SSadaf Ebrahimi *
638*287e80b3SSadaf Ebrahimi * Return 0 on success, and -1 on error.
639*287e80b3SSadaf Ebrahimi */
tracefs_event_file_clear(struct tracefs_instance * instance,const char * system,const char * event,const char * file)640*287e80b3SSadaf Ebrahimi int tracefs_event_file_clear(struct tracefs_instance *instance,
641*287e80b3SSadaf Ebrahimi const char *system, const char *event,
642*287e80b3SSadaf Ebrahimi const char *file)
643*287e80b3SSadaf Ebrahimi {
644*287e80b3SSadaf Ebrahimi char *path;
645*287e80b3SSadaf Ebrahimi int ret;
646*287e80b3SSadaf Ebrahimi
647*287e80b3SSadaf Ebrahimi ret = event_file(&path, system, event, file);
648*287e80b3SSadaf Ebrahimi if (ret < 0)
649*287e80b3SSadaf Ebrahimi return -1;
650*287e80b3SSadaf Ebrahimi
651*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_clear(instance, path);
652*287e80b3SSadaf Ebrahimi free(path);
653*287e80b3SSadaf Ebrahimi return ret;
654*287e80b3SSadaf Ebrahimi }
655*287e80b3SSadaf Ebrahimi
656*287e80b3SSadaf Ebrahimi /**
657*287e80b3SSadaf Ebrahimi * tracefs_event_file_exits - test if a file exists
658*287e80b3SSadaf Ebrahimi * @instance: The instance the event is in (NULL for top level)
659*287e80b3SSadaf Ebrahimi * @system: The system name that the event file is in
660*287e80b3SSadaf Ebrahimi * @event: The event name of the event
661*287e80b3SSadaf Ebrahimi * @file: The name of the file in the event directory.
662*287e80b3SSadaf Ebrahimi *
663*287e80b3SSadaf Ebrahimi * Return true if the file exists, false if it odes not or
664*287e80b3SSadaf Ebrahimi * an error occurred.
665*287e80b3SSadaf Ebrahimi */
tracefs_event_file_exists(struct tracefs_instance * instance,const char * system,const char * event,const char * file)666*287e80b3SSadaf Ebrahimi bool tracefs_event_file_exists(struct tracefs_instance *instance,
667*287e80b3SSadaf Ebrahimi const char *system, const char *event,
668*287e80b3SSadaf Ebrahimi const char *file)
669*287e80b3SSadaf Ebrahimi {
670*287e80b3SSadaf Ebrahimi char *path;
671*287e80b3SSadaf Ebrahimi bool ret;
672*287e80b3SSadaf Ebrahimi
673*287e80b3SSadaf Ebrahimi if (event_file(&path, system, event, file) < 0)
674*287e80b3SSadaf Ebrahimi return false;
675*287e80b3SSadaf Ebrahimi
676*287e80b3SSadaf Ebrahimi ret = tracefs_file_exists(instance, path);
677*287e80b3SSadaf Ebrahimi free(path);
678*287e80b3SSadaf Ebrahimi return ret;
679*287e80b3SSadaf Ebrahimi }
680*287e80b3SSadaf Ebrahimi
681*287e80b3SSadaf Ebrahimi /**
682*287e80b3SSadaf Ebrahimi * tracefs_event_systems - return list of systems for tracing
683*287e80b3SSadaf Ebrahimi * @tracing_dir: directory holding the "events" directory
684*287e80b3SSadaf Ebrahimi * if NULL, top tracing directory is used
685*287e80b3SSadaf Ebrahimi *
686*287e80b3SSadaf Ebrahimi * Returns an allocated list of system names. Both the names and
687*287e80b3SSadaf Ebrahimi * the list must be freed with tracefs_list_free()
688*287e80b3SSadaf Ebrahimi * The list returned ends with a "NULL" pointer
689*287e80b3SSadaf Ebrahimi */
tracefs_event_systems(const char * tracing_dir)690*287e80b3SSadaf Ebrahimi char **tracefs_event_systems(const char *tracing_dir)
691*287e80b3SSadaf Ebrahimi {
692*287e80b3SSadaf Ebrahimi struct dirent *dent;
693*287e80b3SSadaf Ebrahimi char **systems = NULL;
694*287e80b3SSadaf Ebrahimi char *events_dir;
695*287e80b3SSadaf Ebrahimi struct stat st;
696*287e80b3SSadaf Ebrahimi DIR *dir;
697*287e80b3SSadaf Ebrahimi int ret;
698*287e80b3SSadaf Ebrahimi
699*287e80b3SSadaf Ebrahimi if (!tracing_dir)
700*287e80b3SSadaf Ebrahimi tracing_dir = tracefs_tracing_dir();
701*287e80b3SSadaf Ebrahimi
702*287e80b3SSadaf Ebrahimi if (!tracing_dir)
703*287e80b3SSadaf Ebrahimi return NULL;
704*287e80b3SSadaf Ebrahimi
705*287e80b3SSadaf Ebrahimi events_dir = trace_append_file(tracing_dir, "events");
706*287e80b3SSadaf Ebrahimi if (!events_dir)
707*287e80b3SSadaf Ebrahimi return NULL;
708*287e80b3SSadaf Ebrahimi
709*287e80b3SSadaf Ebrahimi /*
710*287e80b3SSadaf Ebrahimi * Search all the directories in the events directory,
711*287e80b3SSadaf Ebrahimi * and collect the ones that have the "enable" file.
712*287e80b3SSadaf Ebrahimi */
713*287e80b3SSadaf Ebrahimi ret = stat(events_dir, &st);
714*287e80b3SSadaf Ebrahimi if (ret < 0 || !S_ISDIR(st.st_mode))
715*287e80b3SSadaf Ebrahimi goto out_free;
716*287e80b3SSadaf Ebrahimi
717*287e80b3SSadaf Ebrahimi dir = opendir(events_dir);
718*287e80b3SSadaf Ebrahimi if (!dir)
719*287e80b3SSadaf Ebrahimi goto out_free;
720*287e80b3SSadaf Ebrahimi
721*287e80b3SSadaf Ebrahimi while ((dent = readdir(dir))) {
722*287e80b3SSadaf Ebrahimi const char *name = dent->d_name;
723*287e80b3SSadaf Ebrahimi char *enable;
724*287e80b3SSadaf Ebrahimi char *sys;
725*287e80b3SSadaf Ebrahimi
726*287e80b3SSadaf Ebrahimi if (strcmp(name, ".") == 0 ||
727*287e80b3SSadaf Ebrahimi strcmp(name, "..") == 0)
728*287e80b3SSadaf Ebrahimi continue;
729*287e80b3SSadaf Ebrahimi
730*287e80b3SSadaf Ebrahimi sys = trace_append_file(events_dir, name);
731*287e80b3SSadaf Ebrahimi ret = stat(sys, &st);
732*287e80b3SSadaf Ebrahimi if (ret < 0 || !S_ISDIR(st.st_mode)) {
733*287e80b3SSadaf Ebrahimi free(sys);
734*287e80b3SSadaf Ebrahimi continue;
735*287e80b3SSadaf Ebrahimi }
736*287e80b3SSadaf Ebrahimi
737*287e80b3SSadaf Ebrahimi enable = trace_append_file(sys, "enable");
738*287e80b3SSadaf Ebrahimi
739*287e80b3SSadaf Ebrahimi ret = stat(enable, &st);
740*287e80b3SSadaf Ebrahimi if (ret >= 0) {
741*287e80b3SSadaf Ebrahimi if (add_list_string(&systems, name) < 0)
742*287e80b3SSadaf Ebrahimi goto out_free;
743*287e80b3SSadaf Ebrahimi }
744*287e80b3SSadaf Ebrahimi free(enable);
745*287e80b3SSadaf Ebrahimi free(sys);
746*287e80b3SSadaf Ebrahimi }
747*287e80b3SSadaf Ebrahimi
748*287e80b3SSadaf Ebrahimi closedir(dir);
749*287e80b3SSadaf Ebrahimi
750*287e80b3SSadaf Ebrahimi out_free:
751*287e80b3SSadaf Ebrahimi free(events_dir);
752*287e80b3SSadaf Ebrahimi return systems;
753*287e80b3SSadaf Ebrahimi }
754*287e80b3SSadaf Ebrahimi
755*287e80b3SSadaf Ebrahimi /**
756*287e80b3SSadaf Ebrahimi * tracefs_system_events - return list of events for system
757*287e80b3SSadaf Ebrahimi * @tracing_dir: directory holding the "events" directory
758*287e80b3SSadaf Ebrahimi * @system: the system to return the events for
759*287e80b3SSadaf Ebrahimi *
760*287e80b3SSadaf Ebrahimi * Returns an allocated list of event names. Both the names and
761*287e80b3SSadaf Ebrahimi * the list must be freed with tracefs_list_free()
762*287e80b3SSadaf Ebrahimi * The list returned ends with a "NULL" pointer
763*287e80b3SSadaf Ebrahimi */
tracefs_system_events(const char * tracing_dir,const char * system)764*287e80b3SSadaf Ebrahimi char **tracefs_system_events(const char *tracing_dir, const char *system)
765*287e80b3SSadaf Ebrahimi {
766*287e80b3SSadaf Ebrahimi struct dirent *dent;
767*287e80b3SSadaf Ebrahimi char **events = NULL;
768*287e80b3SSadaf Ebrahimi char *system_dir = NULL;
769*287e80b3SSadaf Ebrahimi struct stat st;
770*287e80b3SSadaf Ebrahimi DIR *dir;
771*287e80b3SSadaf Ebrahimi int ret;
772*287e80b3SSadaf Ebrahimi
773*287e80b3SSadaf Ebrahimi if (!tracing_dir)
774*287e80b3SSadaf Ebrahimi tracing_dir = tracefs_tracing_dir();
775*287e80b3SSadaf Ebrahimi
776*287e80b3SSadaf Ebrahimi if (!tracing_dir || !system)
777*287e80b3SSadaf Ebrahimi return NULL;
778*287e80b3SSadaf Ebrahimi
779*287e80b3SSadaf Ebrahimi asprintf(&system_dir, "%s/events/%s", tracing_dir, system);
780*287e80b3SSadaf Ebrahimi if (!system_dir)
781*287e80b3SSadaf Ebrahimi return NULL;
782*287e80b3SSadaf Ebrahimi
783*287e80b3SSadaf Ebrahimi ret = stat(system_dir, &st);
784*287e80b3SSadaf Ebrahimi if (ret < 0 || !S_ISDIR(st.st_mode))
785*287e80b3SSadaf Ebrahimi goto out_free;
786*287e80b3SSadaf Ebrahimi
787*287e80b3SSadaf Ebrahimi dir = opendir(system_dir);
788*287e80b3SSadaf Ebrahimi if (!dir)
789*287e80b3SSadaf Ebrahimi goto out_free;
790*287e80b3SSadaf Ebrahimi
791*287e80b3SSadaf Ebrahimi while ((dent = readdir(dir))) {
792*287e80b3SSadaf Ebrahimi const char *name = dent->d_name;
793*287e80b3SSadaf Ebrahimi char *event;
794*287e80b3SSadaf Ebrahimi
795*287e80b3SSadaf Ebrahimi if (strcmp(name, ".") == 0 ||
796*287e80b3SSadaf Ebrahimi strcmp(name, "..") == 0)
797*287e80b3SSadaf Ebrahimi continue;
798*287e80b3SSadaf Ebrahimi
799*287e80b3SSadaf Ebrahimi event = trace_append_file(system_dir, name);
800*287e80b3SSadaf Ebrahimi ret = stat(event, &st);
801*287e80b3SSadaf Ebrahimi if (ret < 0 || !S_ISDIR(st.st_mode)) {
802*287e80b3SSadaf Ebrahimi free(event);
803*287e80b3SSadaf Ebrahimi continue;
804*287e80b3SSadaf Ebrahimi }
805*287e80b3SSadaf Ebrahimi
806*287e80b3SSadaf Ebrahimi if (add_list_string(&events, name) < 0)
807*287e80b3SSadaf Ebrahimi goto out_free;
808*287e80b3SSadaf Ebrahimi
809*287e80b3SSadaf Ebrahimi free(event);
810*287e80b3SSadaf Ebrahimi }
811*287e80b3SSadaf Ebrahimi
812*287e80b3SSadaf Ebrahimi closedir(dir);
813*287e80b3SSadaf Ebrahimi
814*287e80b3SSadaf Ebrahimi out_free:
815*287e80b3SSadaf Ebrahimi free(system_dir);
816*287e80b3SSadaf Ebrahimi
817*287e80b3SSadaf Ebrahimi return events;
818*287e80b3SSadaf Ebrahimi }
819*287e80b3SSadaf Ebrahimi
820*287e80b3SSadaf Ebrahimi /**
821*287e80b3SSadaf Ebrahimi * tracefs_tracers - returns an array of available tracers
822*287e80b3SSadaf Ebrahimi * @tracing_dir: The directory that contains the tracing directory
823*287e80b3SSadaf Ebrahimi *
824*287e80b3SSadaf Ebrahimi * Returns an allocate list of plugins. The array ends with NULL
825*287e80b3SSadaf Ebrahimi * Both the plugin names and array must be freed with tracefs_list_free()
826*287e80b3SSadaf Ebrahimi */
tracefs_tracers(const char * tracing_dir)827*287e80b3SSadaf Ebrahimi char **tracefs_tracers(const char *tracing_dir)
828*287e80b3SSadaf Ebrahimi {
829*287e80b3SSadaf Ebrahimi char *available_tracers;
830*287e80b3SSadaf Ebrahimi struct stat st;
831*287e80b3SSadaf Ebrahimi char **plugins = NULL;
832*287e80b3SSadaf Ebrahimi char *buf;
833*287e80b3SSadaf Ebrahimi char *str, *saveptr;
834*287e80b3SSadaf Ebrahimi char *plugin;
835*287e80b3SSadaf Ebrahimi int slen;
836*287e80b3SSadaf Ebrahimi int len;
837*287e80b3SSadaf Ebrahimi int ret;
838*287e80b3SSadaf Ebrahimi
839*287e80b3SSadaf Ebrahimi if (!tracing_dir)
840*287e80b3SSadaf Ebrahimi tracing_dir = tracefs_tracing_dir();
841*287e80b3SSadaf Ebrahimi
842*287e80b3SSadaf Ebrahimi if (!tracing_dir)
843*287e80b3SSadaf Ebrahimi return NULL;
844*287e80b3SSadaf Ebrahimi
845*287e80b3SSadaf Ebrahimi available_tracers = trace_append_file(tracing_dir, "available_tracers");
846*287e80b3SSadaf Ebrahimi if (!available_tracers)
847*287e80b3SSadaf Ebrahimi return NULL;
848*287e80b3SSadaf Ebrahimi
849*287e80b3SSadaf Ebrahimi ret = stat(available_tracers, &st);
850*287e80b3SSadaf Ebrahimi if (ret < 0)
851*287e80b3SSadaf Ebrahimi goto out_free;
852*287e80b3SSadaf Ebrahimi
853*287e80b3SSadaf Ebrahimi len = str_read_file(available_tracers, &buf, true);
854*287e80b3SSadaf Ebrahimi if (len <= 0)
855*287e80b3SSadaf Ebrahimi goto out_free;
856*287e80b3SSadaf Ebrahimi
857*287e80b3SSadaf Ebrahimi for (str = buf; ; str = NULL) {
858*287e80b3SSadaf Ebrahimi plugin = strtok_r(str, " ", &saveptr);
859*287e80b3SSadaf Ebrahimi if (!plugin)
860*287e80b3SSadaf Ebrahimi break;
861*287e80b3SSadaf Ebrahimi slen = strlen(plugin);
862*287e80b3SSadaf Ebrahimi if (!slen)
863*287e80b3SSadaf Ebrahimi continue;
864*287e80b3SSadaf Ebrahimi
865*287e80b3SSadaf Ebrahimi /* chop off any newlines */
866*287e80b3SSadaf Ebrahimi if (plugin[slen - 1] == '\n')
867*287e80b3SSadaf Ebrahimi plugin[slen - 1] = '\0';
868*287e80b3SSadaf Ebrahimi
869*287e80b3SSadaf Ebrahimi /* Skip the non tracers */
870*287e80b3SSadaf Ebrahimi if (strcmp(plugin, "nop") == 0 ||
871*287e80b3SSadaf Ebrahimi strcmp(plugin, "none") == 0)
872*287e80b3SSadaf Ebrahimi continue;
873*287e80b3SSadaf Ebrahimi
874*287e80b3SSadaf Ebrahimi if (add_list_string(&plugins, plugin) < 0)
875*287e80b3SSadaf Ebrahimi break;
876*287e80b3SSadaf Ebrahimi }
877*287e80b3SSadaf Ebrahimi free(buf);
878*287e80b3SSadaf Ebrahimi
879*287e80b3SSadaf Ebrahimi out_free:
880*287e80b3SSadaf Ebrahimi free(available_tracers);
881*287e80b3SSadaf Ebrahimi
882*287e80b3SSadaf Ebrahimi return plugins;
883*287e80b3SSadaf Ebrahimi }
884*287e80b3SSadaf Ebrahimi
load_events(struct tep_handle * tep,const char * tracing_dir,const char * system,bool check)885*287e80b3SSadaf Ebrahimi static int load_events(struct tep_handle *tep,
886*287e80b3SSadaf Ebrahimi const char *tracing_dir, const char *system, bool check)
887*287e80b3SSadaf Ebrahimi {
888*287e80b3SSadaf Ebrahimi int ret = 0, failure = 0;
889*287e80b3SSadaf Ebrahimi char **events = NULL;
890*287e80b3SSadaf Ebrahimi struct stat st;
891*287e80b3SSadaf Ebrahimi int len = 0;
892*287e80b3SSadaf Ebrahimi int i;
893*287e80b3SSadaf Ebrahimi
894*287e80b3SSadaf Ebrahimi if (!tracing_dir)
895*287e80b3SSadaf Ebrahimi tracing_dir = tracefs_tracing_dir();
896*287e80b3SSadaf Ebrahimi
897*287e80b3SSadaf Ebrahimi events = tracefs_system_events(tracing_dir, system);
898*287e80b3SSadaf Ebrahimi if (!events)
899*287e80b3SSadaf Ebrahimi return -ENOENT;
900*287e80b3SSadaf Ebrahimi
901*287e80b3SSadaf Ebrahimi for (i = 0; events[i]; i++) {
902*287e80b3SSadaf Ebrahimi char *format;
903*287e80b3SSadaf Ebrahimi char *buf;
904*287e80b3SSadaf Ebrahimi
905*287e80b3SSadaf Ebrahimi ret = asprintf(&format, "%s/events/%s/%s/format",
906*287e80b3SSadaf Ebrahimi tracing_dir, system, events[i]);
907*287e80b3SSadaf Ebrahimi if (ret < 0) {
908*287e80b3SSadaf Ebrahimi failure = -ENOMEM;
909*287e80b3SSadaf Ebrahimi break;
910*287e80b3SSadaf Ebrahimi }
911*287e80b3SSadaf Ebrahimi
912*287e80b3SSadaf Ebrahimi ret = stat(format, &st);
913*287e80b3SSadaf Ebrahimi if (ret < 0)
914*287e80b3SSadaf Ebrahimi goto next_event;
915*287e80b3SSadaf Ebrahimi
916*287e80b3SSadaf Ebrahimi /* check if event is already added, to avoid duplicates */
917*287e80b3SSadaf Ebrahimi if (check && tep_find_event_by_name(tep, system, events[i]))
918*287e80b3SSadaf Ebrahimi goto next_event;
919*287e80b3SSadaf Ebrahimi
920*287e80b3SSadaf Ebrahimi len = str_read_file(format, &buf, true);
921*287e80b3SSadaf Ebrahimi if (len <= 0)
922*287e80b3SSadaf Ebrahimi goto next_event;
923*287e80b3SSadaf Ebrahimi
924*287e80b3SSadaf Ebrahimi ret = tep_parse_event(tep, buf, len, system);
925*287e80b3SSadaf Ebrahimi free(buf);
926*287e80b3SSadaf Ebrahimi next_event:
927*287e80b3SSadaf Ebrahimi free(format);
928*287e80b3SSadaf Ebrahimi if (ret)
929*287e80b3SSadaf Ebrahimi failure = ret;
930*287e80b3SSadaf Ebrahimi }
931*287e80b3SSadaf Ebrahimi
932*287e80b3SSadaf Ebrahimi tracefs_list_free(events);
933*287e80b3SSadaf Ebrahimi return failure;
934*287e80b3SSadaf Ebrahimi }
935*287e80b3SSadaf Ebrahimi
trace_rescan_events(struct tep_handle * tep,const char * tracing_dir,const char * system)936*287e80b3SSadaf Ebrahimi __hidden int trace_rescan_events(struct tep_handle *tep,
937*287e80b3SSadaf Ebrahimi const char *tracing_dir, const char *system)
938*287e80b3SSadaf Ebrahimi {
939*287e80b3SSadaf Ebrahimi /* ToDo: add here logic for deleting removed events from tep handle */
940*287e80b3SSadaf Ebrahimi return load_events(tep, tracing_dir, system, true);
941*287e80b3SSadaf Ebrahimi }
942*287e80b3SSadaf Ebrahimi
trace_load_events(struct tep_handle * tep,const char * tracing_dir,const char * system)943*287e80b3SSadaf Ebrahimi __hidden int trace_load_events(struct tep_handle *tep,
944*287e80b3SSadaf Ebrahimi const char *tracing_dir, const char *system)
945*287e80b3SSadaf Ebrahimi {
946*287e80b3SSadaf Ebrahimi return load_events(tep, tracing_dir, system, false);
947*287e80b3SSadaf Ebrahimi }
948*287e80b3SSadaf Ebrahimi
get_tep_event(struct tep_handle * tep,const char * system,const char * name)949*287e80b3SSadaf Ebrahimi __hidden struct tep_event *get_tep_event(struct tep_handle *tep,
950*287e80b3SSadaf Ebrahimi const char *system, const char *name)
951*287e80b3SSadaf Ebrahimi {
952*287e80b3SSadaf Ebrahimi struct tep_event *event;
953*287e80b3SSadaf Ebrahimi
954*287e80b3SSadaf Ebrahimi /* Check if event exists in the system */
955*287e80b3SSadaf Ebrahimi if (!tracefs_event_file_exists(NULL, system, name, "format"))
956*287e80b3SSadaf Ebrahimi return NULL;
957*287e80b3SSadaf Ebrahimi
958*287e80b3SSadaf Ebrahimi /* If the event is already loaded in the tep, return it */
959*287e80b3SSadaf Ebrahimi event = tep_find_event_by_name(tep, system, name);
960*287e80b3SSadaf Ebrahimi if (event)
961*287e80b3SSadaf Ebrahimi return event;
962*287e80b3SSadaf Ebrahimi
963*287e80b3SSadaf Ebrahimi /* Try to load any new events from the given system */
964*287e80b3SSadaf Ebrahimi if (trace_rescan_events(tep, NULL, system))
965*287e80b3SSadaf Ebrahimi return NULL;
966*287e80b3SSadaf Ebrahimi
967*287e80b3SSadaf Ebrahimi return tep_find_event_by_name(tep, system, name);
968*287e80b3SSadaf Ebrahimi }
969*287e80b3SSadaf Ebrahimi
read_header(struct tep_handle * tep,const char * tracing_dir)970*287e80b3SSadaf Ebrahimi static int read_header(struct tep_handle *tep, const char *tracing_dir)
971*287e80b3SSadaf Ebrahimi {
972*287e80b3SSadaf Ebrahimi struct stat st;
973*287e80b3SSadaf Ebrahimi char *header;
974*287e80b3SSadaf Ebrahimi char *buf;
975*287e80b3SSadaf Ebrahimi int len;
976*287e80b3SSadaf Ebrahimi int ret = -1;
977*287e80b3SSadaf Ebrahimi
978*287e80b3SSadaf Ebrahimi header = trace_append_file(tracing_dir, "events/header_page");
979*287e80b3SSadaf Ebrahimi
980*287e80b3SSadaf Ebrahimi ret = stat(header, &st);
981*287e80b3SSadaf Ebrahimi if (ret < 0)
982*287e80b3SSadaf Ebrahimi goto out;
983*287e80b3SSadaf Ebrahimi
984*287e80b3SSadaf Ebrahimi len = str_read_file(header, &buf, true);
985*287e80b3SSadaf Ebrahimi if (len <= 0)
986*287e80b3SSadaf Ebrahimi goto out;
987*287e80b3SSadaf Ebrahimi
988*287e80b3SSadaf Ebrahimi tep_parse_header_page(tep, buf, len, sizeof(long));
989*287e80b3SSadaf Ebrahimi
990*287e80b3SSadaf Ebrahimi free(buf);
991*287e80b3SSadaf Ebrahimi
992*287e80b3SSadaf Ebrahimi ret = 0;
993*287e80b3SSadaf Ebrahimi out:
994*287e80b3SSadaf Ebrahimi free(header);
995*287e80b3SSadaf Ebrahimi return ret;
996*287e80b3SSadaf Ebrahimi }
997*287e80b3SSadaf Ebrahimi
contains(const char * name,const char * const * names)998*287e80b3SSadaf Ebrahimi static bool contains(const char *name, const char * const *names)
999*287e80b3SSadaf Ebrahimi {
1000*287e80b3SSadaf Ebrahimi if (!names)
1001*287e80b3SSadaf Ebrahimi return false;
1002*287e80b3SSadaf Ebrahimi for (; *names; names++)
1003*287e80b3SSadaf Ebrahimi if (strcmp(name, *names) == 0)
1004*287e80b3SSadaf Ebrahimi return true;
1005*287e80b3SSadaf Ebrahimi return false;
1006*287e80b3SSadaf Ebrahimi }
1007*287e80b3SSadaf Ebrahimi
load_kallsyms(struct tep_handle * tep)1008*287e80b3SSadaf Ebrahimi static void load_kallsyms(struct tep_handle *tep)
1009*287e80b3SSadaf Ebrahimi {
1010*287e80b3SSadaf Ebrahimi char *buf;
1011*287e80b3SSadaf Ebrahimi
1012*287e80b3SSadaf Ebrahimi if (str_read_file("/proc/kallsyms", &buf, false) <= 0)
1013*287e80b3SSadaf Ebrahimi return;
1014*287e80b3SSadaf Ebrahimi
1015*287e80b3SSadaf Ebrahimi tep_parse_kallsyms(tep, buf);
1016*287e80b3SSadaf Ebrahimi free(buf);
1017*287e80b3SSadaf Ebrahimi }
1018*287e80b3SSadaf Ebrahimi
load_saved_cmdlines(const char * tracing_dir,struct tep_handle * tep,bool warn)1019*287e80b3SSadaf Ebrahimi static int load_saved_cmdlines(const char *tracing_dir,
1020*287e80b3SSadaf Ebrahimi struct tep_handle *tep, bool warn)
1021*287e80b3SSadaf Ebrahimi {
1022*287e80b3SSadaf Ebrahimi char *path;
1023*287e80b3SSadaf Ebrahimi char *buf;
1024*287e80b3SSadaf Ebrahimi int ret;
1025*287e80b3SSadaf Ebrahimi
1026*287e80b3SSadaf Ebrahimi path = trace_append_file(tracing_dir, "saved_cmdlines");
1027*287e80b3SSadaf Ebrahimi if (!path)
1028*287e80b3SSadaf Ebrahimi return -1;
1029*287e80b3SSadaf Ebrahimi
1030*287e80b3SSadaf Ebrahimi ret = str_read_file(path, &buf, false);
1031*287e80b3SSadaf Ebrahimi free(path);
1032*287e80b3SSadaf Ebrahimi if (ret <= 0)
1033*287e80b3SSadaf Ebrahimi return -1;
1034*287e80b3SSadaf Ebrahimi
1035*287e80b3SSadaf Ebrahimi ret = tep_parse_saved_cmdlines(tep, buf);
1036*287e80b3SSadaf Ebrahimi free(buf);
1037*287e80b3SSadaf Ebrahimi
1038*287e80b3SSadaf Ebrahimi return ret;
1039*287e80b3SSadaf Ebrahimi }
1040*287e80b3SSadaf Ebrahimi
load_printk_formats(const char * tracing_dir,struct tep_handle * tep)1041*287e80b3SSadaf Ebrahimi static void load_printk_formats(const char *tracing_dir,
1042*287e80b3SSadaf Ebrahimi struct tep_handle *tep)
1043*287e80b3SSadaf Ebrahimi {
1044*287e80b3SSadaf Ebrahimi char *path;
1045*287e80b3SSadaf Ebrahimi char *buf;
1046*287e80b3SSadaf Ebrahimi int ret;
1047*287e80b3SSadaf Ebrahimi
1048*287e80b3SSadaf Ebrahimi path = trace_append_file(tracing_dir, "printk_formats");
1049*287e80b3SSadaf Ebrahimi if (!path)
1050*287e80b3SSadaf Ebrahimi return;
1051*287e80b3SSadaf Ebrahimi
1052*287e80b3SSadaf Ebrahimi ret = str_read_file(path, &buf, false);
1053*287e80b3SSadaf Ebrahimi free(path);
1054*287e80b3SSadaf Ebrahimi if (ret <= 0)
1055*287e80b3SSadaf Ebrahimi return;
1056*287e80b3SSadaf Ebrahimi
1057*287e80b3SSadaf Ebrahimi tep_parse_printk_formats(tep, buf);
1058*287e80b3SSadaf Ebrahimi free(buf);
1059*287e80b3SSadaf Ebrahimi }
1060*287e80b3SSadaf Ebrahimi
1061*287e80b3SSadaf Ebrahimi /*
1062*287e80b3SSadaf Ebrahimi * Do a best effort attempt to load kallsyms, saved_cmdlines and
1063*287e80b3SSadaf Ebrahimi * printk_formats. If they can not be loaded, then this will not
1064*287e80b3SSadaf Ebrahimi * do the mappings. But this does not fail the loading of events.
1065*287e80b3SSadaf Ebrahimi */
load_mappings(const char * tracing_dir,struct tep_handle * tep)1066*287e80b3SSadaf Ebrahimi static void load_mappings(const char *tracing_dir,
1067*287e80b3SSadaf Ebrahimi struct tep_handle *tep)
1068*287e80b3SSadaf Ebrahimi {
1069*287e80b3SSadaf Ebrahimi load_kallsyms(tep);
1070*287e80b3SSadaf Ebrahimi
1071*287e80b3SSadaf Ebrahimi /* If there's no tracing_dir no reason to go further */
1072*287e80b3SSadaf Ebrahimi if (!tracing_dir)
1073*287e80b3SSadaf Ebrahimi tracing_dir = tracefs_tracing_dir();
1074*287e80b3SSadaf Ebrahimi
1075*287e80b3SSadaf Ebrahimi if (!tracing_dir)
1076*287e80b3SSadaf Ebrahimi return;
1077*287e80b3SSadaf Ebrahimi
1078*287e80b3SSadaf Ebrahimi load_saved_cmdlines(tracing_dir, tep, false);
1079*287e80b3SSadaf Ebrahimi load_printk_formats(tracing_dir, tep);
1080*287e80b3SSadaf Ebrahimi }
1081*287e80b3SSadaf Ebrahimi
tracefs_load_cmdlines(const char * tracing_dir,struct tep_handle * tep)1082*287e80b3SSadaf Ebrahimi int tracefs_load_cmdlines(const char *tracing_dir, struct tep_handle *tep)
1083*287e80b3SSadaf Ebrahimi {
1084*287e80b3SSadaf Ebrahimi
1085*287e80b3SSadaf Ebrahimi if (!tracing_dir)
1086*287e80b3SSadaf Ebrahimi tracing_dir = tracefs_tracing_dir();
1087*287e80b3SSadaf Ebrahimi
1088*287e80b3SSadaf Ebrahimi if (!tracing_dir)
1089*287e80b3SSadaf Ebrahimi return -1;
1090*287e80b3SSadaf Ebrahimi
1091*287e80b3SSadaf Ebrahimi return load_saved_cmdlines(tracing_dir, tep, true);
1092*287e80b3SSadaf Ebrahimi }
1093*287e80b3SSadaf Ebrahimi
fill_local_events_system(const char * tracing_dir,struct tep_handle * tep,const char * const * sys_names,int * parsing_failures)1094*287e80b3SSadaf Ebrahimi static int fill_local_events_system(const char *tracing_dir,
1095*287e80b3SSadaf Ebrahimi struct tep_handle *tep,
1096*287e80b3SSadaf Ebrahimi const char * const *sys_names,
1097*287e80b3SSadaf Ebrahimi int *parsing_failures)
1098*287e80b3SSadaf Ebrahimi {
1099*287e80b3SSadaf Ebrahimi char **systems = NULL;
1100*287e80b3SSadaf Ebrahimi int ret;
1101*287e80b3SSadaf Ebrahimi int i;
1102*287e80b3SSadaf Ebrahimi
1103*287e80b3SSadaf Ebrahimi if (!tracing_dir)
1104*287e80b3SSadaf Ebrahimi tracing_dir = tracefs_tracing_dir();
1105*287e80b3SSadaf Ebrahimi if (!tracing_dir)
1106*287e80b3SSadaf Ebrahimi return -1;
1107*287e80b3SSadaf Ebrahimi
1108*287e80b3SSadaf Ebrahimi systems = tracefs_event_systems(tracing_dir);
1109*287e80b3SSadaf Ebrahimi if (!systems)
1110*287e80b3SSadaf Ebrahimi return -1;
1111*287e80b3SSadaf Ebrahimi
1112*287e80b3SSadaf Ebrahimi ret = read_header(tep, tracing_dir);
1113*287e80b3SSadaf Ebrahimi if (ret < 0) {
1114*287e80b3SSadaf Ebrahimi ret = -1;
1115*287e80b3SSadaf Ebrahimi goto out;
1116*287e80b3SSadaf Ebrahimi }
1117*287e80b3SSadaf Ebrahimi
1118*287e80b3SSadaf Ebrahimi if (parsing_failures)
1119*287e80b3SSadaf Ebrahimi *parsing_failures = 0;
1120*287e80b3SSadaf Ebrahimi
1121*287e80b3SSadaf Ebrahimi for (i = 0; systems[i]; i++) {
1122*287e80b3SSadaf Ebrahimi if (sys_names && !contains(systems[i], sys_names))
1123*287e80b3SSadaf Ebrahimi continue;
1124*287e80b3SSadaf Ebrahimi ret = trace_load_events(tep, tracing_dir, systems[i]);
1125*287e80b3SSadaf Ebrahimi if (ret && parsing_failures)
1126*287e80b3SSadaf Ebrahimi (*parsing_failures)++;
1127*287e80b3SSadaf Ebrahimi }
1128*287e80b3SSadaf Ebrahimi
1129*287e80b3SSadaf Ebrahimi /* Include ftrace, as it is excluded for not having "enable" file */
1130*287e80b3SSadaf Ebrahimi if (!sys_names || contains("ftrace", sys_names))
1131*287e80b3SSadaf Ebrahimi trace_load_events(tep, tracing_dir, "ftrace");
1132*287e80b3SSadaf Ebrahimi
1133*287e80b3SSadaf Ebrahimi load_mappings(tracing_dir, tep);
1134*287e80b3SSadaf Ebrahimi
1135*287e80b3SSadaf Ebrahimi /* always succeed because parsing failures are not critical */
1136*287e80b3SSadaf Ebrahimi ret = 0;
1137*287e80b3SSadaf Ebrahimi out:
1138*287e80b3SSadaf Ebrahimi tracefs_list_free(systems);
1139*287e80b3SSadaf Ebrahimi return ret;
1140*287e80b3SSadaf Ebrahimi }
1141*287e80b3SSadaf Ebrahimi
set_tep_cpus(const char * tracing_dir,struct tep_handle * tep)1142*287e80b3SSadaf Ebrahimi static void set_tep_cpus(const char *tracing_dir, struct tep_handle *tep)
1143*287e80b3SSadaf Ebrahimi {
1144*287e80b3SSadaf Ebrahimi struct stat st;
1145*287e80b3SSadaf Ebrahimi char path[PATH_MAX];
1146*287e80b3SSadaf Ebrahimi int cpus = sysconf(_SC_NPROCESSORS_CONF);
1147*287e80b3SSadaf Ebrahimi int max_cpu = 0;
1148*287e80b3SSadaf Ebrahimi int ret;
1149*287e80b3SSadaf Ebrahimi int i;
1150*287e80b3SSadaf Ebrahimi
1151*287e80b3SSadaf Ebrahimi if (!tracing_dir)
1152*287e80b3SSadaf Ebrahimi tracing_dir = tracefs_tracing_dir();
1153*287e80b3SSadaf Ebrahimi
1154*287e80b3SSadaf Ebrahimi /*
1155*287e80b3SSadaf Ebrahimi * Paranoid: in case sysconf() above does not work.
1156*287e80b3SSadaf Ebrahimi * And we also only care about the number of tracing
1157*287e80b3SSadaf Ebrahimi * buffers that exist. If cpus is 32, but the top half
1158*287e80b3SSadaf Ebrahimi * is offline, there may only be 16 tracing buffers.
1159*287e80b3SSadaf Ebrahimi * That's what we want to know.
1160*287e80b3SSadaf Ebrahimi */
1161*287e80b3SSadaf Ebrahimi for (i = 0; !cpus || i < cpus; i++) {
1162*287e80b3SSadaf Ebrahimi snprintf(path, PATH_MAX, "%s/per_cpu/cpu%d", tracing_dir, i);
1163*287e80b3SSadaf Ebrahimi ret = stat(path, &st);
1164*287e80b3SSadaf Ebrahimi if (!ret && S_ISDIR(st.st_mode))
1165*287e80b3SSadaf Ebrahimi max_cpu = i + 1;
1166*287e80b3SSadaf Ebrahimi else if (i >= cpus)
1167*287e80b3SSadaf Ebrahimi break;
1168*287e80b3SSadaf Ebrahimi }
1169*287e80b3SSadaf Ebrahimi
1170*287e80b3SSadaf Ebrahimi if (!max_cpu)
1171*287e80b3SSadaf Ebrahimi max_cpu = cpus;
1172*287e80b3SSadaf Ebrahimi
1173*287e80b3SSadaf Ebrahimi tep_set_cpus(tep, max_cpu);
1174*287e80b3SSadaf Ebrahimi }
1175*287e80b3SSadaf Ebrahimi
1176*287e80b3SSadaf Ebrahimi /**
1177*287e80b3SSadaf Ebrahimi * tracefs_local_events_system - create a tep from the events of the specified subsystem.
1178*287e80b3SSadaf Ebrahimi *
1179*287e80b3SSadaf Ebrahimi * @tracing_dir: The directory that contains the events.
1180*287e80b3SSadaf Ebrahimi * @sys_name: Array of system names, to load the events from.
1181*287e80b3SSadaf Ebrahimi * The last element from the array must be NULL
1182*287e80b3SSadaf Ebrahimi *
1183*287e80b3SSadaf Ebrahimi * Returns a tep structure that contains the tep local to
1184*287e80b3SSadaf Ebrahimi * the system.
1185*287e80b3SSadaf Ebrahimi */
tracefs_local_events_system(const char * tracing_dir,const char * const * sys_names)1186*287e80b3SSadaf Ebrahimi struct tep_handle *tracefs_local_events_system(const char *tracing_dir,
1187*287e80b3SSadaf Ebrahimi const char * const *sys_names)
1188*287e80b3SSadaf Ebrahimi {
1189*287e80b3SSadaf Ebrahimi struct tep_handle *tep = NULL;
1190*287e80b3SSadaf Ebrahimi
1191*287e80b3SSadaf Ebrahimi tep = tep_alloc();
1192*287e80b3SSadaf Ebrahimi if (!tep)
1193*287e80b3SSadaf Ebrahimi return NULL;
1194*287e80b3SSadaf Ebrahimi
1195*287e80b3SSadaf Ebrahimi if (fill_local_events_system(tracing_dir, tep, sys_names, NULL)) {
1196*287e80b3SSadaf Ebrahimi tep_free(tep);
1197*287e80b3SSadaf Ebrahimi tep = NULL;
1198*287e80b3SSadaf Ebrahimi }
1199*287e80b3SSadaf Ebrahimi
1200*287e80b3SSadaf Ebrahimi set_tep_cpus(tracing_dir, tep);
1201*287e80b3SSadaf Ebrahimi
1202*287e80b3SSadaf Ebrahimi /* Set the long size for this tep handle */
1203*287e80b3SSadaf Ebrahimi tep_set_long_size(tep, tep_get_header_page_size(tep));
1204*287e80b3SSadaf Ebrahimi
1205*287e80b3SSadaf Ebrahimi return tep;
1206*287e80b3SSadaf Ebrahimi }
1207*287e80b3SSadaf Ebrahimi
1208*287e80b3SSadaf Ebrahimi /**
1209*287e80b3SSadaf Ebrahimi * tracefs_local_events - create a tep from the events on system
1210*287e80b3SSadaf Ebrahimi * @tracing_dir: The directory that contains the events.
1211*287e80b3SSadaf Ebrahimi *
1212*287e80b3SSadaf Ebrahimi * Returns a tep structure that contains the teps local to
1213*287e80b3SSadaf Ebrahimi * the system.
1214*287e80b3SSadaf Ebrahimi */
tracefs_local_events(const char * tracing_dir)1215*287e80b3SSadaf Ebrahimi struct tep_handle *tracefs_local_events(const char *tracing_dir)
1216*287e80b3SSadaf Ebrahimi {
1217*287e80b3SSadaf Ebrahimi return tracefs_local_events_system(tracing_dir, NULL);
1218*287e80b3SSadaf Ebrahimi }
1219*287e80b3SSadaf Ebrahimi
1220*287e80b3SSadaf Ebrahimi /**
1221*287e80b3SSadaf Ebrahimi * tracefs_fill_local_events - Fill a tep with the events on system
1222*287e80b3SSadaf Ebrahimi * @tracing_dir: The directory that contains the events.
1223*287e80b3SSadaf Ebrahimi * @tep: Allocated tep handler which will be filled
1224*287e80b3SSadaf Ebrahimi * @parsing_failures: return number of failures while parsing the event files
1225*287e80b3SSadaf Ebrahimi *
1226*287e80b3SSadaf Ebrahimi * Returns whether the operation succeeded
1227*287e80b3SSadaf Ebrahimi */
tracefs_fill_local_events(const char * tracing_dir,struct tep_handle * tep,int * parsing_failures)1228*287e80b3SSadaf Ebrahimi int tracefs_fill_local_events(const char *tracing_dir,
1229*287e80b3SSadaf Ebrahimi struct tep_handle *tep, int *parsing_failures)
1230*287e80b3SSadaf Ebrahimi {
1231*287e80b3SSadaf Ebrahimi return fill_local_events_system(tracing_dir, tep,
1232*287e80b3SSadaf Ebrahimi NULL, parsing_failures);
1233*287e80b3SSadaf Ebrahimi }
1234*287e80b3SSadaf Ebrahimi
match(const char * str,regex_t * re)1235*287e80b3SSadaf Ebrahimi static bool match(const char *str, regex_t *re)
1236*287e80b3SSadaf Ebrahimi {
1237*287e80b3SSadaf Ebrahimi return regexec(re, str, 0, NULL, 0) == 0;
1238*287e80b3SSadaf Ebrahimi }
1239*287e80b3SSadaf Ebrahimi
1240*287e80b3SSadaf Ebrahimi enum event_state {
1241*287e80b3SSadaf Ebrahimi STATE_INIT,
1242*287e80b3SSadaf Ebrahimi STATE_ENABLED,
1243*287e80b3SSadaf Ebrahimi STATE_DISABLED,
1244*287e80b3SSadaf Ebrahimi STATE_MIXED,
1245*287e80b3SSadaf Ebrahimi STATE_ERROR,
1246*287e80b3SSadaf Ebrahimi };
1247*287e80b3SSadaf Ebrahimi
read_event_state(struct tracefs_instance * instance,const char * file,enum event_state * state)1248*287e80b3SSadaf Ebrahimi static int read_event_state(struct tracefs_instance *instance, const char *file,
1249*287e80b3SSadaf Ebrahimi enum event_state *state)
1250*287e80b3SSadaf Ebrahimi {
1251*287e80b3SSadaf Ebrahimi char *val;
1252*287e80b3SSadaf Ebrahimi int ret = 0;
1253*287e80b3SSadaf Ebrahimi
1254*287e80b3SSadaf Ebrahimi if (*state == STATE_ERROR)
1255*287e80b3SSadaf Ebrahimi return -1;
1256*287e80b3SSadaf Ebrahimi
1257*287e80b3SSadaf Ebrahimi val = tracefs_instance_file_read(instance, file, NULL);
1258*287e80b3SSadaf Ebrahimi if (!val)
1259*287e80b3SSadaf Ebrahimi return -1;
1260*287e80b3SSadaf Ebrahimi
1261*287e80b3SSadaf Ebrahimi switch (val[0]) {
1262*287e80b3SSadaf Ebrahimi case '0':
1263*287e80b3SSadaf Ebrahimi switch (*state) {
1264*287e80b3SSadaf Ebrahimi case STATE_INIT:
1265*287e80b3SSadaf Ebrahimi *state = STATE_DISABLED;
1266*287e80b3SSadaf Ebrahimi break;
1267*287e80b3SSadaf Ebrahimi case STATE_ENABLED:
1268*287e80b3SSadaf Ebrahimi *state = STATE_MIXED;
1269*287e80b3SSadaf Ebrahimi break;
1270*287e80b3SSadaf Ebrahimi default:
1271*287e80b3SSadaf Ebrahimi break;
1272*287e80b3SSadaf Ebrahimi }
1273*287e80b3SSadaf Ebrahimi break;
1274*287e80b3SSadaf Ebrahimi case '1':
1275*287e80b3SSadaf Ebrahimi switch (*state) {
1276*287e80b3SSadaf Ebrahimi case STATE_INIT:
1277*287e80b3SSadaf Ebrahimi *state = STATE_ENABLED;
1278*287e80b3SSadaf Ebrahimi break;
1279*287e80b3SSadaf Ebrahimi case STATE_DISABLED:
1280*287e80b3SSadaf Ebrahimi *state = STATE_MIXED;
1281*287e80b3SSadaf Ebrahimi break;
1282*287e80b3SSadaf Ebrahimi default:
1283*287e80b3SSadaf Ebrahimi break;
1284*287e80b3SSadaf Ebrahimi }
1285*287e80b3SSadaf Ebrahimi break;
1286*287e80b3SSadaf Ebrahimi case 'X':
1287*287e80b3SSadaf Ebrahimi *state = STATE_MIXED;
1288*287e80b3SSadaf Ebrahimi break;
1289*287e80b3SSadaf Ebrahimi default:
1290*287e80b3SSadaf Ebrahimi *state = TRACEFS_ERROR;
1291*287e80b3SSadaf Ebrahimi ret = -1;
1292*287e80b3SSadaf Ebrahimi break;
1293*287e80b3SSadaf Ebrahimi }
1294*287e80b3SSadaf Ebrahimi free(val);
1295*287e80b3SSadaf Ebrahimi
1296*287e80b3SSadaf Ebrahimi return ret;
1297*287e80b3SSadaf Ebrahimi }
1298*287e80b3SSadaf Ebrahimi
enable_disable_event(struct tracefs_instance * instance,const char * system,const char * event,bool enable,enum event_state * state)1299*287e80b3SSadaf Ebrahimi static int enable_disable_event(struct tracefs_instance *instance,
1300*287e80b3SSadaf Ebrahimi const char *system, const char *event,
1301*287e80b3SSadaf Ebrahimi bool enable, enum event_state *state)
1302*287e80b3SSadaf Ebrahimi {
1303*287e80b3SSadaf Ebrahimi const char *str = enable ? "1" : "0";
1304*287e80b3SSadaf Ebrahimi char *system_event;
1305*287e80b3SSadaf Ebrahimi int ret;
1306*287e80b3SSadaf Ebrahimi
1307*287e80b3SSadaf Ebrahimi ret = asprintf(&system_event, "events/%s/%s/enable", system, event);
1308*287e80b3SSadaf Ebrahimi if (ret < 0)
1309*287e80b3SSadaf Ebrahimi return ret;
1310*287e80b3SSadaf Ebrahimi
1311*287e80b3SSadaf Ebrahimi if (state)
1312*287e80b3SSadaf Ebrahimi ret = read_event_state(instance, system_event, state);
1313*287e80b3SSadaf Ebrahimi else
1314*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_write(instance, system_event, str);
1315*287e80b3SSadaf Ebrahimi free(system_event);
1316*287e80b3SSadaf Ebrahimi
1317*287e80b3SSadaf Ebrahimi return ret;
1318*287e80b3SSadaf Ebrahimi }
1319*287e80b3SSadaf Ebrahimi
enable_disable_system(struct tracefs_instance * instance,const char * system,bool enable,enum event_state * state)1320*287e80b3SSadaf Ebrahimi static int enable_disable_system(struct tracefs_instance *instance,
1321*287e80b3SSadaf Ebrahimi const char *system, bool enable,
1322*287e80b3SSadaf Ebrahimi enum event_state *state)
1323*287e80b3SSadaf Ebrahimi {
1324*287e80b3SSadaf Ebrahimi const char *str = enable ? "1" : "0";
1325*287e80b3SSadaf Ebrahimi char *system_path;
1326*287e80b3SSadaf Ebrahimi int ret;
1327*287e80b3SSadaf Ebrahimi
1328*287e80b3SSadaf Ebrahimi ret = asprintf(&system_path, "events/%s/enable", system);
1329*287e80b3SSadaf Ebrahimi if (ret < 0)
1330*287e80b3SSadaf Ebrahimi return ret;
1331*287e80b3SSadaf Ebrahimi
1332*287e80b3SSadaf Ebrahimi if (state)
1333*287e80b3SSadaf Ebrahimi ret = read_event_state(instance, system_path, state);
1334*287e80b3SSadaf Ebrahimi else
1335*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_write(instance, system_path, str);
1336*287e80b3SSadaf Ebrahimi free(system_path);
1337*287e80b3SSadaf Ebrahimi
1338*287e80b3SSadaf Ebrahimi return ret;
1339*287e80b3SSadaf Ebrahimi }
1340*287e80b3SSadaf Ebrahimi
enable_disable_all(struct tracefs_instance * instance,bool enable)1341*287e80b3SSadaf Ebrahimi static int enable_disable_all(struct tracefs_instance *instance,
1342*287e80b3SSadaf Ebrahimi bool enable)
1343*287e80b3SSadaf Ebrahimi {
1344*287e80b3SSadaf Ebrahimi const char *str = enable ? "1" : "0";
1345*287e80b3SSadaf Ebrahimi int ret;
1346*287e80b3SSadaf Ebrahimi
1347*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_write(instance, "events/enable", str);
1348*287e80b3SSadaf Ebrahimi return ret < 0 ? ret : 0;
1349*287e80b3SSadaf Ebrahimi }
1350*287e80b3SSadaf Ebrahimi
make_regex(regex_t * re,const char * match)1351*287e80b3SSadaf Ebrahimi static int make_regex(regex_t *re, const char *match)
1352*287e80b3SSadaf Ebrahimi {
1353*287e80b3SSadaf Ebrahimi int len = strlen(match);
1354*287e80b3SSadaf Ebrahimi char str[len + 3];
1355*287e80b3SSadaf Ebrahimi char *p = &str[0];
1356*287e80b3SSadaf Ebrahimi
1357*287e80b3SSadaf Ebrahimi if (!len || match[0] != '^')
1358*287e80b3SSadaf Ebrahimi *(p++) = '^';
1359*287e80b3SSadaf Ebrahimi
1360*287e80b3SSadaf Ebrahimi strcpy(p, match);
1361*287e80b3SSadaf Ebrahimi p += len;
1362*287e80b3SSadaf Ebrahimi
1363*287e80b3SSadaf Ebrahimi if (!len || match[len-1] != '$')
1364*287e80b3SSadaf Ebrahimi *(p++) = '$';
1365*287e80b3SSadaf Ebrahimi
1366*287e80b3SSadaf Ebrahimi *p = '\0';
1367*287e80b3SSadaf Ebrahimi
1368*287e80b3SSadaf Ebrahimi return regcomp(re, str, REG_ICASE|REG_NOSUB);
1369*287e80b3SSadaf Ebrahimi }
1370*287e80b3SSadaf Ebrahimi
event_enable_disable(struct tracefs_instance * instance,const char * system,const char * event,bool enable,enum event_state * state)1371*287e80b3SSadaf Ebrahimi static int event_enable_disable(struct tracefs_instance *instance,
1372*287e80b3SSadaf Ebrahimi const char *system, const char *event,
1373*287e80b3SSadaf Ebrahimi bool enable, enum event_state *state)
1374*287e80b3SSadaf Ebrahimi {
1375*287e80b3SSadaf Ebrahimi regex_t system_re, event_re;
1376*287e80b3SSadaf Ebrahimi char **systems;
1377*287e80b3SSadaf Ebrahimi char **events = NULL;
1378*287e80b3SSadaf Ebrahimi int ret = -1;
1379*287e80b3SSadaf Ebrahimi int s, e;
1380*287e80b3SSadaf Ebrahimi
1381*287e80b3SSadaf Ebrahimi /* Handle all events first */
1382*287e80b3SSadaf Ebrahimi if (!system && !event)
1383*287e80b3SSadaf Ebrahimi return enable_disable_all(instance, enable);
1384*287e80b3SSadaf Ebrahimi
1385*287e80b3SSadaf Ebrahimi systems = tracefs_event_systems(NULL);
1386*287e80b3SSadaf Ebrahimi if (!systems)
1387*287e80b3SSadaf Ebrahimi goto out_free;
1388*287e80b3SSadaf Ebrahimi
1389*287e80b3SSadaf Ebrahimi if (system) {
1390*287e80b3SSadaf Ebrahimi ret = make_regex(&system_re, system);
1391*287e80b3SSadaf Ebrahimi if (ret < 0)
1392*287e80b3SSadaf Ebrahimi goto out_free;
1393*287e80b3SSadaf Ebrahimi }
1394*287e80b3SSadaf Ebrahimi if (event) {
1395*287e80b3SSadaf Ebrahimi ret = make_regex(&event_re, event);
1396*287e80b3SSadaf Ebrahimi if (ret < 0) {
1397*287e80b3SSadaf Ebrahimi if (system)
1398*287e80b3SSadaf Ebrahimi regfree(&system_re);
1399*287e80b3SSadaf Ebrahimi goto out_free;
1400*287e80b3SSadaf Ebrahimi }
1401*287e80b3SSadaf Ebrahimi }
1402*287e80b3SSadaf Ebrahimi
1403*287e80b3SSadaf Ebrahimi ret = -1;
1404*287e80b3SSadaf Ebrahimi for (s = 0; systems[s]; s++) {
1405*287e80b3SSadaf Ebrahimi if (system && !match(systems[s], &system_re))
1406*287e80b3SSadaf Ebrahimi continue;
1407*287e80b3SSadaf Ebrahimi
1408*287e80b3SSadaf Ebrahimi /* Check for the short cut first */
1409*287e80b3SSadaf Ebrahimi if (!event) {
1410*287e80b3SSadaf Ebrahimi ret = enable_disable_system(instance, systems[s], enable, state);
1411*287e80b3SSadaf Ebrahimi if (ret < 0)
1412*287e80b3SSadaf Ebrahimi break;
1413*287e80b3SSadaf Ebrahimi ret = 0;
1414*287e80b3SSadaf Ebrahimi continue;
1415*287e80b3SSadaf Ebrahimi }
1416*287e80b3SSadaf Ebrahimi
1417*287e80b3SSadaf Ebrahimi events = tracefs_system_events(NULL, systems[s]);
1418*287e80b3SSadaf Ebrahimi if (!events)
1419*287e80b3SSadaf Ebrahimi continue; /* Error? */
1420*287e80b3SSadaf Ebrahimi
1421*287e80b3SSadaf Ebrahimi for (e = 0; events[e]; e++) {
1422*287e80b3SSadaf Ebrahimi if (!match(events[e], &event_re))
1423*287e80b3SSadaf Ebrahimi continue;
1424*287e80b3SSadaf Ebrahimi ret = enable_disable_event(instance, systems[s],
1425*287e80b3SSadaf Ebrahimi events[e], enable, state);
1426*287e80b3SSadaf Ebrahimi if (ret < 0)
1427*287e80b3SSadaf Ebrahimi break;
1428*287e80b3SSadaf Ebrahimi ret = 0;
1429*287e80b3SSadaf Ebrahimi }
1430*287e80b3SSadaf Ebrahimi tracefs_list_free(events);
1431*287e80b3SSadaf Ebrahimi events = NULL;
1432*287e80b3SSadaf Ebrahimi }
1433*287e80b3SSadaf Ebrahimi if (system)
1434*287e80b3SSadaf Ebrahimi regfree(&system_re);
1435*287e80b3SSadaf Ebrahimi if (event)
1436*287e80b3SSadaf Ebrahimi regfree(&event_re);
1437*287e80b3SSadaf Ebrahimi
1438*287e80b3SSadaf Ebrahimi out_free:
1439*287e80b3SSadaf Ebrahimi tracefs_list_free(systems);
1440*287e80b3SSadaf Ebrahimi tracefs_list_free(events);
1441*287e80b3SSadaf Ebrahimi return ret;
1442*287e80b3SSadaf Ebrahimi }
1443*287e80b3SSadaf Ebrahimi
1444*287e80b3SSadaf Ebrahimi /**
1445*287e80b3SSadaf Ebrahimi * tracefs_event_enable - enable specified events
1446*287e80b3SSadaf Ebrahimi * @instance: ftrace instance, can be NULL for the top instance
1447*287e80b3SSadaf Ebrahimi * @system: A regex of a system (NULL to match all systems)
1448*287e80b3SSadaf Ebrahimi * @event: A regex of the event in the system (NULL to match all events)
1449*287e80b3SSadaf Ebrahimi *
1450*287e80b3SSadaf Ebrahimi * This will enable events that match the @system and @event.
1451*287e80b3SSadaf Ebrahimi * If both @system and @event are NULL, then it will enable all events.
1452*287e80b3SSadaf Ebrahimi * If @system is NULL, it will look at all systems for matching events
1453*287e80b3SSadaf Ebrahimi * to @event.
1454*287e80b3SSadaf Ebrahimi * If @event is NULL, then it will enable all events in the systems
1455*287e80b3SSadaf Ebrahimi * that match @system.
1456*287e80b3SSadaf Ebrahimi *
1457*287e80b3SSadaf Ebrahimi * Returns 0 on success, and -1 if it encountered an error,
1458*287e80b3SSadaf Ebrahimi * or if no events matched. If no events matched, then -1 is set
1459*287e80b3SSadaf Ebrahimi * but errno will not be.
1460*287e80b3SSadaf Ebrahimi */
tracefs_event_enable(struct tracefs_instance * instance,const char * system,const char * event)1461*287e80b3SSadaf Ebrahimi int tracefs_event_enable(struct tracefs_instance *instance,
1462*287e80b3SSadaf Ebrahimi const char *system, const char *event)
1463*287e80b3SSadaf Ebrahimi {
1464*287e80b3SSadaf Ebrahimi return event_enable_disable(instance, system, event, true, NULL);
1465*287e80b3SSadaf Ebrahimi }
1466*287e80b3SSadaf Ebrahimi
tracefs_event_disable(struct tracefs_instance * instance,const char * system,const char * event)1467*287e80b3SSadaf Ebrahimi int tracefs_event_disable(struct tracefs_instance *instance,
1468*287e80b3SSadaf Ebrahimi const char *system, const char *event)
1469*287e80b3SSadaf Ebrahimi {
1470*287e80b3SSadaf Ebrahimi return event_enable_disable(instance, system, event, false, NULL);
1471*287e80b3SSadaf Ebrahimi }
1472*287e80b3SSadaf Ebrahimi
1473*287e80b3SSadaf Ebrahimi /**
1474*287e80b3SSadaf Ebrahimi * tracefs_event_is_enabled - return if the event is enabled or not
1475*287e80b3SSadaf Ebrahimi * @instance: ftrace instance, can be NULL for the top instance
1476*287e80b3SSadaf Ebrahimi * @system: The name of the system to check
1477*287e80b3SSadaf Ebrahimi * @event: The name of the event to check
1478*287e80b3SSadaf Ebrahimi *
1479*287e80b3SSadaf Ebrahimi * Checks is an event or multiple events are enabled.
1480*287e80b3SSadaf Ebrahimi *
1481*287e80b3SSadaf Ebrahimi * If @system is NULL, then it will check all the systems where @event is
1482*287e80b3SSadaf Ebrahimi * a match.
1483*287e80b3SSadaf Ebrahimi *
1484*287e80b3SSadaf Ebrahimi * If @event is NULL, then it will check all events where @system is a match.
1485*287e80b3SSadaf Ebrahimi *
1486*287e80b3SSadaf Ebrahimi * If both @system and @event are NULL, then it will check all events
1487*287e80b3SSadaf Ebrahimi *
1488*287e80b3SSadaf Ebrahimi * Returns TRACEFS_ALL_ENABLED if all matching are enabled.
1489*287e80b3SSadaf Ebrahimi * Returns TRACEFS_SOME_ENABLED if some are enabled and some are not
1490*287e80b3SSadaf Ebrahimi * Returns TRACEFS_ALL_DISABLED if none of the events are enabled.
1491*287e80b3SSadaf Ebrahimi * Returns TRACEFS_ERROR if there is an error reading the events.
1492*287e80b3SSadaf Ebrahimi */
1493*287e80b3SSadaf Ebrahimi enum tracefs_enable_state
tracefs_event_is_enabled(struct tracefs_instance * instance,const char * system,const char * event)1494*287e80b3SSadaf Ebrahimi tracefs_event_is_enabled(struct tracefs_instance *instance,
1495*287e80b3SSadaf Ebrahimi const char *system, const char *event)
1496*287e80b3SSadaf Ebrahimi {
1497*287e80b3SSadaf Ebrahimi enum event_state state = STATE_INIT;
1498*287e80b3SSadaf Ebrahimi int ret;
1499*287e80b3SSadaf Ebrahimi
1500*287e80b3SSadaf Ebrahimi ret = event_enable_disable(instance, system, event, false, &state);
1501*287e80b3SSadaf Ebrahimi
1502*287e80b3SSadaf Ebrahimi if (ret < 0)
1503*287e80b3SSadaf Ebrahimi return TRACEFS_ERROR;
1504*287e80b3SSadaf Ebrahimi
1505*287e80b3SSadaf Ebrahimi switch (state) {
1506*287e80b3SSadaf Ebrahimi case STATE_ENABLED:
1507*287e80b3SSadaf Ebrahimi return TRACEFS_ALL_ENABLED;
1508*287e80b3SSadaf Ebrahimi case STATE_DISABLED:
1509*287e80b3SSadaf Ebrahimi return TRACEFS_ALL_DISABLED;
1510*287e80b3SSadaf Ebrahimi case STATE_MIXED:
1511*287e80b3SSadaf Ebrahimi return TRACEFS_SOME_ENABLED;
1512*287e80b3SSadaf Ebrahimi default:
1513*287e80b3SSadaf Ebrahimi return TRACEFS_ERROR;
1514*287e80b3SSadaf Ebrahimi }
1515*287e80b3SSadaf Ebrahimi }
1516