diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace.h | 10 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 3 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 107 |
3 files changed, 74 insertions, 46 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 7d55bcf50e49..1fb7d6ccadf4 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -731,12 +731,16 @@ struct ftrace_event_field { | |||
731 | int size; | 731 | int size; |
732 | }; | 732 | }; |
733 | 733 | ||
734 | struct event_filter { | ||
735 | int n_preds; | ||
736 | struct filter_pred **preds; | ||
737 | }; | ||
738 | |||
734 | struct event_subsystem { | 739 | struct event_subsystem { |
735 | struct list_head list; | 740 | struct list_head list; |
736 | const char *name; | 741 | const char *name; |
737 | struct dentry *entry; | 742 | struct dentry *entry; |
738 | int n_preds; | 743 | void *filter; |
739 | struct filter_pred **preds; | ||
740 | }; | 744 | }; |
741 | 745 | ||
742 | struct filter_pred; | 746 | struct filter_pred; |
@@ -774,7 +778,7 @@ filter_check_discard(struct ftrace_event_call *call, void *rec, | |||
774 | struct ring_buffer *buffer, | 778 | struct ring_buffer *buffer, |
775 | struct ring_buffer_event *event) | 779 | struct ring_buffer_event *event) |
776 | { | 780 | { |
777 | if (unlikely(call->n_preds) && !filter_match_preds(call, rec)) { | 781 | if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) { |
778 | ring_buffer_discard_commit(buffer, event); | 782 | ring_buffer_discard_commit(buffer, event); |
779 | return 1; | 783 | return 1; |
780 | } | 784 | } |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index be4d3a437c17..1cd1f37373dd 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -757,8 +757,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
757 | 757 | ||
758 | list_add(&system->list, &event_subsystems); | 758 | list_add(&system->list, &event_subsystems); |
759 | 759 | ||
760 | system->preds = NULL; | 760 | system->filter = NULL; |
761 | system->n_preds = 0; | ||
762 | 761 | ||
763 | entry = debugfs_create_file("filter", 0644, system->entry, system, | 762 | entry = debugfs_create_file("filter", 0644, system->entry, system, |
764 | &ftrace_subsystem_filter_fops); | 763 | &ftrace_subsystem_filter_fops); |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 65418288f957..1e861eca3d02 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -93,11 +93,12 @@ static int filter_pred_none(struct filter_pred *pred, void *event) | |||
93 | /* return 1 if event matches, 0 otherwise (discard) */ | 93 | /* return 1 if event matches, 0 otherwise (discard) */ |
94 | int filter_match_preds(struct ftrace_event_call *call, void *rec) | 94 | int filter_match_preds(struct ftrace_event_call *call, void *rec) |
95 | { | 95 | { |
96 | struct event_filter *filter = call->filter; | ||
96 | int i, matched, and_failed = 0; | 97 | int i, matched, and_failed = 0; |
97 | struct filter_pred *pred; | 98 | struct filter_pred *pred; |
98 | 99 | ||
99 | for (i = 0; i < call->n_preds; i++) { | 100 | for (i = 0; i < filter->n_preds; i++) { |
100 | pred = call->preds[i]; | 101 | pred = filter->preds[i]; |
101 | if (and_failed && !pred->or) | 102 | if (and_failed && !pred->or) |
102 | continue; | 103 | continue; |
103 | matched = pred->fn(pred, rec); | 104 | matched = pred->fn(pred, rec); |
@@ -115,20 +116,20 @@ int filter_match_preds(struct ftrace_event_call *call, void *rec) | |||
115 | } | 116 | } |
116 | EXPORT_SYMBOL_GPL(filter_match_preds); | 117 | EXPORT_SYMBOL_GPL(filter_match_preds); |
117 | 118 | ||
118 | static void __filter_print_preds(struct filter_pred **preds, int n_preds, | 119 | static void __filter_print_preds(struct event_filter *filter, |
119 | struct trace_seq *s) | 120 | struct trace_seq *s) |
120 | { | 121 | { |
121 | char *field_name; | ||
122 | struct filter_pred *pred; | 122 | struct filter_pred *pred; |
123 | char *field_name; | ||
123 | int i; | 124 | int i; |
124 | 125 | ||
125 | if (!n_preds) { | 126 | if (!filter || !filter->n_preds) { |
126 | trace_seq_printf(s, "none\n"); | 127 | trace_seq_printf(s, "none\n"); |
127 | return; | 128 | return; |
128 | } | 129 | } |
129 | 130 | ||
130 | for (i = 0; i < n_preds; i++) { | 131 | for (i = 0; i < filter->n_preds; i++) { |
131 | pred = preds[i]; | 132 | pred = filter->preds[i]; |
132 | field_name = pred->field_name; | 133 | field_name = pred->field_name; |
133 | if (i) | 134 | if (i) |
134 | trace_seq_printf(s, pred->or ? "|| " : "&& "); | 135 | trace_seq_printf(s, pred->or ? "|| " : "&& "); |
@@ -144,7 +145,7 @@ static void __filter_print_preds(struct filter_pred **preds, int n_preds, | |||
144 | void filter_print_preds(struct ftrace_event_call *call, struct trace_seq *s) | 145 | void filter_print_preds(struct ftrace_event_call *call, struct trace_seq *s) |
145 | { | 146 | { |
146 | mutex_lock(&filter_mutex); | 147 | mutex_lock(&filter_mutex); |
147 | __filter_print_preds(call->preds, call->n_preds, s); | 148 | __filter_print_preds(call->filter, s); |
148 | mutex_unlock(&filter_mutex); | 149 | mutex_unlock(&filter_mutex); |
149 | } | 150 | } |
150 | 151 | ||
@@ -152,7 +153,7 @@ void filter_print_subsystem_preds(struct event_subsystem *system, | |||
152 | struct trace_seq *s) | 153 | struct trace_seq *s) |
153 | { | 154 | { |
154 | mutex_lock(&filter_mutex); | 155 | mutex_lock(&filter_mutex); |
155 | __filter_print_preds(system->preds, system->n_preds, s); | 156 | __filter_print_preds(system->filter, s); |
156 | mutex_unlock(&filter_mutex); | 157 | mutex_unlock(&filter_mutex); |
157 | } | 158 | } |
158 | 159 | ||
@@ -200,12 +201,14 @@ static int filter_set_pred(struct filter_pred *dest, | |||
200 | 201 | ||
201 | static void __filter_disable_preds(struct ftrace_event_call *call) | 202 | static void __filter_disable_preds(struct ftrace_event_call *call) |
202 | { | 203 | { |
204 | struct event_filter *filter = call->filter; | ||
203 | int i; | 205 | int i; |
204 | 206 | ||
205 | call->n_preds = 0; | 207 | call->filter_active = 0; |
208 | filter->n_preds = 0; | ||
206 | 209 | ||
207 | for (i = 0; i < MAX_FILTER_PRED; i++) | 210 | for (i = 0; i < MAX_FILTER_PRED; i++) |
208 | call->preds[i]->fn = filter_pred_none; | 211 | filter->preds[i]->fn = filter_pred_none; |
209 | } | 212 | } |
210 | 213 | ||
211 | void filter_disable_preds(struct ftrace_event_call *call) | 214 | void filter_disable_preds(struct ftrace_event_call *call) |
@@ -217,32 +220,39 @@ void filter_disable_preds(struct ftrace_event_call *call) | |||
217 | 220 | ||
218 | int init_preds(struct ftrace_event_call *call) | 221 | int init_preds(struct ftrace_event_call *call) |
219 | { | 222 | { |
223 | struct event_filter *filter; | ||
220 | struct filter_pred *pred; | 224 | struct filter_pred *pred; |
221 | int i; | 225 | int i; |
222 | 226 | ||
223 | call->n_preds = 0; | 227 | filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL); |
224 | 228 | if (!call->filter) | |
225 | call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL); | ||
226 | if (!call->preds) | ||
227 | return -ENOMEM; | 229 | return -ENOMEM; |
228 | 230 | ||
231 | call->filter_active = 0; | ||
232 | filter->n_preds = 0; | ||
233 | |||
234 | filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL); | ||
235 | if (!filter->preds) | ||
236 | goto oom; | ||
237 | |||
229 | for (i = 0; i < MAX_FILTER_PRED; i++) { | 238 | for (i = 0; i < MAX_FILTER_PRED; i++) { |
230 | pred = kzalloc(sizeof(*pred), GFP_KERNEL); | 239 | pred = kzalloc(sizeof(*pred), GFP_KERNEL); |
231 | if (!pred) | 240 | if (!pred) |
232 | goto oom; | 241 | goto oom; |
233 | pred->fn = filter_pred_none; | 242 | pred->fn = filter_pred_none; |
234 | call->preds[i] = pred; | 243 | filter->preds[i] = pred; |
235 | } | 244 | } |
236 | 245 | ||
237 | return 0; | 246 | return 0; |
238 | 247 | ||
239 | oom: | 248 | oom: |
240 | for (i = 0; i < MAX_FILTER_PRED; i++) { | 249 | for (i = 0; i < MAX_FILTER_PRED; i++) { |
241 | if (call->preds[i]) | 250 | if (filter->preds[i]) |
242 | filter_free_pred(call->preds[i]); | 251 | filter_free_pred(filter->preds[i]); |
243 | } | 252 | } |
244 | kfree(call->preds); | 253 | kfree(filter->preds); |
245 | call->preds = NULL; | 254 | kfree(call->filter); |
255 | call->filter = NULL; | ||
246 | 256 | ||
247 | return -ENOMEM; | 257 | return -ENOMEM; |
248 | } | 258 | } |
@@ -250,15 +260,16 @@ EXPORT_SYMBOL_GPL(init_preds); | |||
250 | 260 | ||
251 | static void __filter_free_subsystem_preds(struct event_subsystem *system) | 261 | static void __filter_free_subsystem_preds(struct event_subsystem *system) |
252 | { | 262 | { |
263 | struct event_filter *filter = system->filter; | ||
253 | struct ftrace_event_call *call; | 264 | struct ftrace_event_call *call; |
254 | int i; | 265 | int i; |
255 | 266 | ||
256 | if (system->n_preds) { | 267 | if (filter && filter->n_preds) { |
257 | for (i = 0; i < system->n_preds; i++) | 268 | for (i = 0; i < filter->n_preds; i++) |
258 | filter_free_pred(system->preds[i]); | 269 | filter_free_pred(filter->preds[i]); |
259 | kfree(system->preds); | 270 | kfree(filter->preds); |
260 | system->preds = NULL; | 271 | kfree(filter); |
261 | system->n_preds = 0; | 272 | system->filter = NULL; |
262 | } | 273 | } |
263 | 274 | ||
264 | list_for_each_entry(call, &ftrace_events, list) { | 275 | list_for_each_entry(call, &ftrace_events, list) { |
@@ -281,21 +292,23 @@ static int filter_add_pred_fn(struct ftrace_event_call *call, | |||
281 | struct filter_pred *pred, | 292 | struct filter_pred *pred, |
282 | filter_pred_fn_t fn) | 293 | filter_pred_fn_t fn) |
283 | { | 294 | { |
295 | struct event_filter *filter = call->filter; | ||
284 | int idx, err; | 296 | int idx, err; |
285 | 297 | ||
286 | if (call->n_preds && !pred->compound) | 298 | if (filter->n_preds && !pred->compound) |
287 | __filter_disable_preds(call); | 299 | __filter_disable_preds(call); |
288 | 300 | ||
289 | if (call->n_preds == MAX_FILTER_PRED) | 301 | if (filter->n_preds == MAX_FILTER_PRED) |
290 | return -ENOSPC; | 302 | return -ENOSPC; |
291 | 303 | ||
292 | idx = call->n_preds; | 304 | idx = filter->n_preds; |
293 | filter_clear_pred(call->preds[idx]); | 305 | filter_clear_pred(filter->preds[idx]); |
294 | err = filter_set_pred(call->preds[idx], pred, fn); | 306 | err = filter_set_pred(filter->preds[idx], pred, fn); |
295 | if (err) | 307 | if (err) |
296 | return err; | 308 | return err; |
297 | 309 | ||
298 | call->n_preds++; | 310 | filter->n_preds++; |
311 | call->filter_active = 1; | ||
299 | 312 | ||
300 | return 0; | 313 | return 0; |
301 | } | 314 | } |
@@ -366,29 +379,41 @@ int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred) | |||
366 | int filter_add_subsystem_pred(struct event_subsystem *system, | 379 | int filter_add_subsystem_pred(struct event_subsystem *system, |
367 | struct filter_pred *pred) | 380 | struct filter_pred *pred) |
368 | { | 381 | { |
382 | struct event_filter *filter = system->filter; | ||
369 | struct ftrace_event_call *call; | 383 | struct ftrace_event_call *call; |
370 | 384 | ||
371 | mutex_lock(&filter_mutex); | 385 | mutex_lock(&filter_mutex); |
372 | 386 | ||
373 | if (system->n_preds && !pred->compound) | 387 | if (filter && filter->n_preds && !pred->compound) { |
374 | __filter_free_subsystem_preds(system); | 388 | __filter_free_subsystem_preds(system); |
389 | filter = NULL; | ||
390 | } | ||
375 | 391 | ||
376 | if (!system->n_preds) { | 392 | if (!filter) { |
377 | system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), | 393 | system->filter = kzalloc(sizeof(*filter), GFP_KERNEL); |
394 | if (!system->filter) { | ||
395 | mutex_unlock(&filter_mutex); | ||
396 | return -ENOMEM; | ||
397 | } | ||
398 | filter = system->filter; | ||
399 | filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), | ||
378 | GFP_KERNEL); | 400 | GFP_KERNEL); |
379 | if (!system->preds) { | 401 | |
402 | if (!filter->preds) { | ||
403 | kfree(system->filter); | ||
404 | system->filter = NULL; | ||
380 | mutex_unlock(&filter_mutex); | 405 | mutex_unlock(&filter_mutex); |
381 | return -ENOMEM; | 406 | return -ENOMEM; |
382 | } | 407 | } |
383 | } | 408 | } |
384 | 409 | ||
385 | if (system->n_preds == MAX_FILTER_PRED) { | 410 | if (filter->n_preds == MAX_FILTER_PRED) { |
386 | mutex_unlock(&filter_mutex); | 411 | mutex_unlock(&filter_mutex); |
387 | return -ENOSPC; | 412 | return -ENOSPC; |
388 | } | 413 | } |
389 | 414 | ||
390 | system->preds[system->n_preds] = pred; | 415 | filter->preds[filter->n_preds] = pred; |
391 | system->n_preds++; | 416 | filter->n_preds++; |
392 | 417 | ||
393 | list_for_each_entry(call, &ftrace_events, list) { | 418 | list_for_each_entry(call, &ftrace_events, list) { |
394 | int err; | 419 | int err; |
@@ -401,8 +426,8 @@ int filter_add_subsystem_pred(struct event_subsystem *system, | |||
401 | 426 | ||
402 | err = __filter_add_pred(call, pred); | 427 | err = __filter_add_pred(call, pred); |
403 | if (err == -ENOMEM) { | 428 | if (err == -ENOMEM) { |
404 | system->preds[system->n_preds] = NULL; | 429 | filter->preds[filter->n_preds] = NULL; |
405 | system->n_preds--; | 430 | filter->n_preds--; |
406 | mutex_unlock(&filter_mutex); | 431 | mutex_unlock(&filter_mutex); |
407 | return err; | 432 | return err; |
408 | } | 433 | } |