tracing/filters: don't remove old filters when failed to write subsys->filter
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / trace / trace_events_filter.c
CommitLineData
7ce7e424
TZ
1/*
2 * trace_events_filter - generic event filtering
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
19 */
20
21#include <linux/debugfs.h>
22#include <linux/uaccess.h>
23#include <linux/module.h>
24#include <linux/ctype.h>
ac1adc55 25#include <linux/mutex.h>
7ce7e424
TZ
26
27#include "trace.h"
4bda2d51 28#include "trace_output.h"
7ce7e424 29
ac1adc55
TZ
30static DEFINE_MUTEX(filter_mutex);
31
7ce7e424
TZ
32static int filter_pred_64(struct filter_pred *pred, void *event)
33{
34 u64 *addr = (u64 *)(event + pred->offset);
35 u64 val = (u64)pred->val;
36 int match;
37
38 match = (val == *addr) ^ pred->not;
39
40 return match;
41}
42
43static int filter_pred_32(struct filter_pred *pred, void *event)
44{
45 u32 *addr = (u32 *)(event + pred->offset);
46 u32 val = (u32)pred->val;
47 int match;
48
49 match = (val == *addr) ^ pred->not;
50
51 return match;
52}
53
54static int filter_pred_16(struct filter_pred *pred, void *event)
55{
56 u16 *addr = (u16 *)(event + pred->offset);
57 u16 val = (u16)pred->val;
58 int match;
59
60 match = (val == *addr) ^ pred->not;
61
62 return match;
63}
64
65static int filter_pred_8(struct filter_pred *pred, void *event)
66{
67 u8 *addr = (u8 *)(event + pred->offset);
68 u8 val = (u8)pred->val;
69 int match;
70
71 match = (val == *addr) ^ pred->not;
72
73 return match;
74}
75
76static int filter_pred_string(struct filter_pred *pred, void *event)
77{
78 char *addr = (char *)(event + pred->offset);
79 int cmp, match;
80
81 cmp = strncmp(addr, pred->str_val, pred->str_len);
82
83 match = (!cmp) ^ pred->not;
84
85 return match;
86}
87
0a19e53c
TZ
88static int filter_pred_none(struct filter_pred *pred, void *event)
89{
90 return 0;
91}
92
7ce7e424
TZ
93/* return 1 if event matches, 0 otherwise (discard) */
94int filter_match_preds(struct ftrace_event_call *call, void *rec)
95{
96 int i, matched, and_failed = 0;
97 struct filter_pred *pred;
98
0a19e53c
TZ
99 for (i = 0; i < call->n_preds; i++) {
100 pred = call->preds[i];
101 if (and_failed && !pred->or)
102 continue;
103 matched = pred->fn(pred, rec);
104 if (!matched && !pred->or) {
105 and_failed = 1;
106 continue;
107 } else if (matched && pred->or)
108 return 1;
7ce7e424
TZ
109 }
110
111 if (and_failed)
112 return 0;
113
114 return 1;
115}
17c873ec 116EXPORT_SYMBOL_GPL(filter_match_preds);
7ce7e424 117
ac1adc55
TZ
118static void __filter_print_preds(struct filter_pred **preds, int n_preds,
119 struct trace_seq *s)
7ce7e424 120{
7ce7e424
TZ
121 char *field_name;
122 struct filter_pred *pred;
123 int i;
124
0a19e53c 125 if (!n_preds) {
4bda2d51
TZ
126 trace_seq_printf(s, "none\n");
127 return;
7ce7e424
TZ
128 }
129
0a19e53c
TZ
130 for (i = 0; i < n_preds; i++) {
131 pred = preds[i];
132 field_name = pred->field_name;
133 if (i)
134 trace_seq_printf(s, pred->or ? "|| " : "&& ");
135 trace_seq_printf(s, "%s ", field_name);
136 trace_seq_printf(s, pred->not ? "!= " : "== ");
137 if (pred->str_len)
138 trace_seq_printf(s, "%s\n", pred->str_val);
139 else
140 trace_seq_printf(s, "%llu\n", pred->val);
7ce7e424 141 }
7ce7e424
TZ
142}
143
ac1adc55
TZ
144void filter_print_preds(struct ftrace_event_call *call, struct trace_seq *s)
145{
146 mutex_lock(&filter_mutex);
147 __filter_print_preds(call->preds, call->n_preds, s);
148 mutex_unlock(&filter_mutex);
149}
150
151void filter_print_subsystem_preds(struct event_subsystem *system,
152 struct trace_seq *s)
153{
154 mutex_lock(&filter_mutex);
155 __filter_print_preds(system->preds, system->n_preds, s);
156 mutex_unlock(&filter_mutex);
157}
158
7ce7e424
TZ
159static struct ftrace_event_field *
160find_event_field(struct ftrace_event_call *call, char *name)
161{
1fc2d5c1 162 struct ftrace_event_field *field;
7ce7e424 163
1fc2d5c1 164 list_for_each_entry(field, &call->fields, link) {
7ce7e424
TZ
165 if (!strcmp(field->name, name))
166 return field;
167 }
168
169 return NULL;
170}
171
172void filter_free_pred(struct filter_pred *pred)
173{
174 if (!pred)
175 return;
176
177 kfree(pred->field_name);
7ce7e424
TZ
178 kfree(pred);
179}
180
0a19e53c
TZ
181static void filter_clear_pred(struct filter_pred *pred)
182{
183 kfree(pred->field_name);
184 pred->field_name = NULL;
185 pred->str_len = 0;
186}
187
188static int filter_set_pred(struct filter_pred *dest,
189 struct filter_pred *src,
190 filter_pred_fn_t fn)
191{
192 *dest = *src;
193 dest->field_name = kstrdup(src->field_name, GFP_KERNEL);
194 if (!dest->field_name)
195 return -ENOMEM;
196 dest->fn = fn;
197
198 return 0;
199}
200
ac1adc55 201static void __filter_disable_preds(struct ftrace_event_call *call)
7ce7e424
TZ
202{
203 int i;
204
0a19e53c
TZ
205 call->n_preds = 0;
206
207 for (i = 0; i < MAX_FILTER_PRED; i++)
208 call->preds[i]->fn = filter_pred_none;
209}
210
ac1adc55
TZ
211void filter_disable_preds(struct ftrace_event_call *call)
212{
213 mutex_lock(&filter_mutex);
214 __filter_disable_preds(call);
215 mutex_unlock(&filter_mutex);
216}
217
0a19e53c
TZ
218int init_preds(struct ftrace_event_call *call)
219{
220 struct filter_pred *pred;
221 int i;
222
223 call->n_preds = 0;
224
225 call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
226 if (!call->preds)
227 return -ENOMEM;
228
229 for (i = 0; i < MAX_FILTER_PRED; i++) {
230 pred = kzalloc(sizeof(*pred), GFP_KERNEL);
231 if (!pred)
232 goto oom;
233 pred->fn = filter_pred_none;
234 call->preds[i] = pred;
235 }
236
237 return 0;
238
239oom:
240 for (i = 0; i < MAX_FILTER_PRED; i++) {
241 if (call->preds[i])
7ce7e424 242 filter_free_pred(call->preds[i]);
7ce7e424 243 }
0a19e53c
TZ
244 kfree(call->preds);
245 call->preds = NULL;
246
247 return -ENOMEM;
7ce7e424 248}
17c873ec 249EXPORT_SYMBOL_GPL(init_preds);
7ce7e424 250
ac1adc55 251static void __filter_free_subsystem_preds(struct event_subsystem *system)
cfb180f3 252{
a59fd602 253 struct ftrace_event_call *call;
cfb180f3
TZ
254 int i;
255
0a19e53c
TZ
256 if (system->n_preds) {
257 for (i = 0; i < system->n_preds; i++)
cfb180f3
TZ
258 filter_free_pred(system->preds[i]);
259 kfree(system->preds);
260 system->preds = NULL;
0a19e53c 261 system->n_preds = 0;
cfb180f3
TZ
262 }
263
a59fd602 264 list_for_each_entry(call, &ftrace_events, list) {
e1112b4d 265 if (!call->define_fields)
cfb180f3
TZ
266 continue;
267
268 if (!strcmp(call->system, system->name))
ac1adc55 269 __filter_disable_preds(call);
cfb180f3
TZ
270 }
271}
272
ac1adc55
TZ
273void filter_free_subsystem_preds(struct event_subsystem *system)
274{
275 mutex_lock(&filter_mutex);
276 __filter_free_subsystem_preds(system);
277 mutex_unlock(&filter_mutex);
278}
279
280static int filter_add_pred_fn(struct ftrace_event_call *call,
281 struct filter_pred *pred,
282 filter_pred_fn_t fn)
7ce7e424 283{
0a19e53c 284 int idx, err;
7ce7e424 285
0a19e53c 286 if (call->n_preds && !pred->compound)
ac1adc55 287 __filter_disable_preds(call);
7ce7e424 288
0a19e53c
TZ
289 if (call->n_preds == MAX_FILTER_PRED)
290 return -ENOSPC;
7ce7e424 291
0a19e53c
TZ
292 idx = call->n_preds;
293 filter_clear_pred(call->preds[idx]);
294 err = filter_set_pred(call->preds[idx], pred, fn);
295 if (err)
296 return err;
297
298 call->n_preds++;
7ce7e424 299
0a19e53c 300 return 0;
7ce7e424
TZ
301}
302
303static int is_string_field(const char *type)
304{
305 if (strchr(type, '[') && strstr(type, "char"))
306 return 1;
307
308 return 0;
309}
310
ac1adc55
TZ
311static int __filter_add_pred(struct ftrace_event_call *call,
312 struct filter_pred *pred)
7ce7e424
TZ
313{
314 struct ftrace_event_field *field;
0a19e53c 315 filter_pred_fn_t fn;
7ce7e424
TZ
316
317 field = find_event_field(call, pred->field_name);
318 if (!field)
319 return -EINVAL;
320
0a19e53c 321 pred->fn = filter_pred_none;
7ce7e424
TZ
322 pred->offset = field->offset;
323
324 if (is_string_field(field->type)) {
0a19e53c 325 if (!pred->str_len)
9f58a159 326 return -EINVAL;
0a19e53c 327 fn = filter_pred_string;
7ce7e424 328 pred->str_len = field->size;
ac1adc55 329 return filter_add_pred_fn(call, pred, fn);
9f58a159 330 } else {
0a19e53c 331 if (pred->str_len)
9f58a159 332 return -EINVAL;
7ce7e424
TZ
333 }
334
335 switch (field->size) {
336 case 8:
0a19e53c 337 fn = filter_pred_64;
7ce7e424
TZ
338 break;
339 case 4:
0a19e53c 340 fn = filter_pred_32;
7ce7e424
TZ
341 break;
342 case 2:
0a19e53c 343 fn = filter_pred_16;
7ce7e424
TZ
344 break;
345 case 1:
0a19e53c 346 fn = filter_pred_8;
7ce7e424
TZ
347 break;
348 default:
349 return -EINVAL;
350 }
351
ac1adc55
TZ
352 return filter_add_pred_fn(call, pred, fn);
353}
354
355int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
356{
357 int err;
358
359 mutex_lock(&filter_mutex);
360 err = __filter_add_pred(call, pred);
361 mutex_unlock(&filter_mutex);
362
363 return err;
cfb180f3
TZ
364}
365
366int filter_add_subsystem_pred(struct event_subsystem *system,
367 struct filter_pred *pred)
368{
a59fd602 369 struct ftrace_event_call *call;
cfb180f3 370
ac1adc55
TZ
371 mutex_lock(&filter_mutex);
372
0a19e53c 373 if (system->n_preds && !pred->compound)
ac1adc55 374 __filter_free_subsystem_preds(system);
cfb180f3 375
0a19e53c 376 if (!system->n_preds) {
cfb180f3
TZ
377 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
378 GFP_KERNEL);
ac1adc55
TZ
379 if (!system->preds) {
380 mutex_unlock(&filter_mutex);
cfb180f3 381 return -ENOMEM;
ac1adc55 382 }
cfb180f3
TZ
383 }
384
ac1adc55
TZ
385 if (system->n_preds == MAX_FILTER_PRED) {
386 mutex_unlock(&filter_mutex);
44e9c8b7 387 return -ENOSPC;
ac1adc55 388 }
c4cff064 389
0a19e53c 390 system->preds[system->n_preds] = pred;
ac1adc55 391 system->n_preds++;
0a19e53c 392
a59fd602 393 list_for_each_entry(call, &ftrace_events, list) {
c4cff064
TZ
394 int err;
395
e1112b4d 396 if (!call->define_fields)
cfb180f3
TZ
397 continue;
398
c4cff064
TZ
399 if (strcmp(call->system, system->name))
400 continue;
401
ac1adc55 402 err = __filter_add_pred(call, pred);
0a19e53c
TZ
403 if (err == -ENOMEM) {
404 system->preds[system->n_preds] = NULL;
ac1adc55
TZ
405 system->n_preds--;
406 mutex_unlock(&filter_mutex);
0a19e53c
TZ
407 return err;
408 }
cfb180f3
TZ
409 }
410
ac1adc55 411 mutex_unlock(&filter_mutex);
c4cff064 412
0a19e53c 413 return 0;
cfb180f3
TZ
414}
415
7ce7e424
TZ
416int filter_parse(char **pbuf, struct filter_pred *pred)
417{
418 char *tmp, *tok, *val_str = NULL;
419 int tok_n = 0;
420
421 /* field ==/!= number, or/and field ==/!= number, number */
422 while ((tok = strsep(pbuf, " \n"))) {
423 if (tok_n == 0) {
424 if (!strcmp(tok, "0")) {
425 pred->clear = 1;
426 return 0;
427 } else if (!strcmp(tok, "&&")) {
428 pred->or = 0;
429 pred->compound = 1;
430 } else if (!strcmp(tok, "||")) {
431 pred->or = 1;
432 pred->compound = 1;
433 } else
434 pred->field_name = tok;
435 tok_n = 1;
436 continue;
437 }
438 if (tok_n == 1) {
439 if (!pred->field_name)
440 pred->field_name = tok;
441 else if (!strcmp(tok, "!="))
442 pred->not = 1;
443 else if (!strcmp(tok, "=="))
444 pred->not = 0;
445 else {
446 pred->field_name = NULL;
447 return -EINVAL;
448 }
449 tok_n = 2;
450 continue;
451 }
452 if (tok_n == 2) {
453 if (pred->compound) {
454 if (!strcmp(tok, "!="))
455 pred->not = 1;
456 else if (!strcmp(tok, "=="))
457 pred->not = 0;
458 else {
459 pred->field_name = NULL;
460 return -EINVAL;
461 }
462 } else {
463 val_str = tok;
464 break; /* done */
465 }
466 tok_n = 3;
467 continue;
468 }
469 if (tok_n == 3) {
470 val_str = tok;
471 break; /* done */
472 }
473 }
474
0a19e53c
TZ
475 if (!val_str || !strlen(val_str)
476 || strlen(val_str) >= MAX_FILTER_STR_VAL) {
bcabd91c
LZ
477 pred->field_name = NULL;
478 return -EINVAL;
479 }
480
7ce7e424
TZ
481 pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
482 if (!pred->field_name)
483 return -ENOMEM;
484
0a19e53c 485 pred->str_len = 0;
a3e0ab05 486 pred->val = simple_strtoull(val_str, &tmp, 0);
7ce7e424 487 if (tmp == val_str) {
0a19e53c
TZ
488 strncpy(pred->str_val, val_str, MAX_FILTER_STR_VAL);
489 pred->str_len = strlen(val_str);
490 pred->str_val[pred->str_len] = '\0';
a3e0ab05
LZ
491 } else if (*tmp != '\0')
492 return -EINVAL;
7ce7e424
TZ
493
494 return 0;
495}
496
497