diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace.h | 5 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 12 | ||||
-rw-r--r-- | kernel/trace/trace_events_trigger.c | 170 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 46 |
4 files changed, 219 insertions, 14 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index ccbd8104cf99..433bfc5dd576 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -1,3 +1,4 @@ | |||
1 | |||
1 | #ifndef _LINUX_KERNEL_TRACE_H | 2 | #ifndef _LINUX_KERNEL_TRACE_H |
2 | #define _LINUX_KERNEL_TRACE_H | 3 | #define _LINUX_KERNEL_TRACE_H |
3 | 4 | ||
@@ -1020,6 +1021,10 @@ extern int apply_subsystem_event_filter(struct ftrace_subsystem_dir *dir, | |||
1020 | extern void print_subsystem_event_filter(struct event_subsystem *system, | 1021 | extern void print_subsystem_event_filter(struct event_subsystem *system, |
1021 | struct trace_seq *s); | 1022 | struct trace_seq *s); |
1022 | extern int filter_assign_type(const char *type); | 1023 | extern int filter_assign_type(const char *type); |
1024 | extern int create_event_filter(struct ftrace_event_call *call, | ||
1025 | char *filter_str, bool set_str, | ||
1026 | struct event_filter **filterp); | ||
1027 | extern void free_event_filter(struct event_filter *filter); | ||
1023 | 1028 | ||
1024 | struct ftrace_event_field * | 1029 | struct ftrace_event_field * |
1025 | trace_find_event_field(struct ftrace_event_call *call, char *name); | 1030 | trace_find_event_field(struct ftrace_event_call *call, char *name); |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 2468f56dc5db..8a8631926a07 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -799,6 +799,11 @@ static void __free_filter(struct event_filter *filter) | |||
799 | kfree(filter); | 799 | kfree(filter); |
800 | } | 800 | } |
801 | 801 | ||
802 | void free_event_filter(struct event_filter *filter) | ||
803 | { | ||
804 | __free_filter(filter); | ||
805 | } | ||
806 | |||
802 | void destroy_call_preds(struct ftrace_event_call *call) | 807 | void destroy_call_preds(struct ftrace_event_call *call) |
803 | { | 808 | { |
804 | __free_filter(call->filter); | 809 | __free_filter(call->filter); |
@@ -1938,6 +1943,13 @@ static int create_filter(struct ftrace_event_call *call, | |||
1938 | return err; | 1943 | return err; |
1939 | } | 1944 | } |
1940 | 1945 | ||
1946 | int create_event_filter(struct ftrace_event_call *call, | ||
1947 | char *filter_str, bool set_str, | ||
1948 | struct event_filter **filterp) | ||
1949 | { | ||
1950 | return create_filter(call, filter_str, set_str, filterp); | ||
1951 | } | ||
1952 | |||
1941 | /** | 1953 | /** |
1942 | * create_system_filter - create a filter for an event_subsystem | 1954 | * create_system_filter - create a filter for an event_subsystem |
1943 | * @system: event_subsystem to create a filter for | 1955 | * @system: event_subsystem to create a filter for |
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index 45e48b109d51..f5b3f780fda4 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c | |||
@@ -31,6 +31,9 @@ static DEFINE_MUTEX(trigger_cmd_mutex); | |||
31 | static void | 31 | static void |
32 | trigger_data_free(struct event_trigger_data *data) | 32 | trigger_data_free(struct event_trigger_data *data) |
33 | { | 33 | { |
34 | if (data->cmd_ops->set_filter) | ||
35 | data->cmd_ops->set_filter(NULL, data, NULL); | ||
36 | |||
34 | synchronize_sched(); /* make sure current triggers exit before free */ | 37 | synchronize_sched(); /* make sure current triggers exit before free */ |
35 | kfree(data); | 38 | kfree(data); |
36 | } | 39 | } |
@@ -38,27 +41,78 @@ trigger_data_free(struct event_trigger_data *data) | |||
38 | /** | 41 | /** |
39 | * event_triggers_call - Call triggers associated with a trace event | 42 | * event_triggers_call - Call triggers associated with a trace event |
40 | * @file: The ftrace_event_file associated with the event | 43 | * @file: The ftrace_event_file associated with the event |
44 | * @rec: The trace entry for the event, NULL for unconditional invocation | ||
41 | * | 45 | * |
42 | * For each trigger associated with an event, invoke the trigger | 46 | * For each trigger associated with an event, invoke the trigger |
43 | * function registered with the associated trigger command. | 47 | * function registered with the associated trigger command. If rec is |
48 | * non-NULL, it means that the trigger requires further processing and | ||
49 | * shouldn't be unconditionally invoked. If rec is non-NULL and the | ||
50 | * trigger has a filter associated with it, rec will checked against | ||
51 | * the filter and if the record matches the trigger will be invoked. | ||
52 | * If the trigger is a 'post_trigger', meaning it shouldn't be invoked | ||
53 | * in any case until the current event is written, the trigger | ||
54 | * function isn't invoked but the bit associated with the deferred | ||
55 | * trigger is set in the return value. | ||
56 | * | ||
57 | * Returns an enum event_trigger_type value containing a set bit for | ||
58 | * any trigger that should be deferred, ETT_NONE if nothing to defer. | ||
44 | * | 59 | * |
45 | * Called from tracepoint handlers (with rcu_read_lock_sched() held). | 60 | * Called from tracepoint handlers (with rcu_read_lock_sched() held). |
46 | * | 61 | * |
47 | * Return: an enum event_trigger_type value containing a set bit for | 62 | * Return: an enum event_trigger_type value containing a set bit for |
48 | * any trigger that should be deferred, ETT_NONE if nothing to defer. | 63 | * any trigger that should be deferred, ETT_NONE if nothing to defer. |
49 | */ | 64 | */ |
50 | void event_triggers_call(struct ftrace_event_file *file) | 65 | enum event_trigger_type |
66 | event_triggers_call(struct ftrace_event_file *file, void *rec) | ||
51 | { | 67 | { |
52 | struct event_trigger_data *data; | 68 | struct event_trigger_data *data; |
69 | enum event_trigger_type tt = ETT_NONE; | ||
53 | 70 | ||
54 | if (list_empty(&file->triggers)) | 71 | if (list_empty(&file->triggers)) |
55 | return; | 72 | return tt; |
56 | 73 | ||
57 | list_for_each_entry_rcu(data, &file->triggers, list) | 74 | list_for_each_entry_rcu(data, &file->triggers, list) { |
75 | if (!rec) { | ||
76 | data->ops->func(data); | ||
77 | continue; | ||
78 | } | ||
79 | if (data->filter && !filter_match_preds(data->filter, rec)) | ||
80 | continue; | ||
81 | if (data->cmd_ops->post_trigger) { | ||
82 | tt |= data->cmd_ops->trigger_type; | ||
83 | continue; | ||
84 | } | ||
58 | data->ops->func(data); | 85 | data->ops->func(data); |
86 | } | ||
87 | return tt; | ||
59 | } | 88 | } |
60 | EXPORT_SYMBOL_GPL(event_triggers_call); | 89 | EXPORT_SYMBOL_GPL(event_triggers_call); |
61 | 90 | ||
91 | /** | ||
92 | * event_triggers_post_call - Call 'post_triggers' for a trace event | ||
93 | * @file: The ftrace_event_file associated with the event | ||
94 | * @tt: enum event_trigger_type containing a set bit for each trigger to invoke | ||
95 | * | ||
96 | * For each trigger associated with an event, invoke the trigger | ||
97 | * function registered with the associated trigger command, if the | ||
98 | * corresponding bit is set in the tt enum passed into this function. | ||
99 | * See @event_triggers_call for details on how those bits are set. | ||
100 | * | ||
101 | * Called from tracepoint handlers (with rcu_read_lock_sched() held). | ||
102 | */ | ||
103 | void | ||
104 | event_triggers_post_call(struct ftrace_event_file *file, | ||
105 | enum event_trigger_type tt) | ||
106 | { | ||
107 | struct event_trigger_data *data; | ||
108 | |||
109 | list_for_each_entry_rcu(data, &file->triggers, list) { | ||
110 | if (data->cmd_ops->trigger_type & tt) | ||
111 | data->ops->func(data); | ||
112 | } | ||
113 | } | ||
114 | EXPORT_SYMBOL_GPL(event_triggers_post_call); | ||
115 | |||
62 | static void *trigger_next(struct seq_file *m, void *t, loff_t *pos) | 116 | static void *trigger_next(struct seq_file *m, void *t, loff_t *pos) |
63 | { | 117 | { |
64 | struct ftrace_event_file *event_file = event_file_data(m->private); | 118 | struct ftrace_event_file *event_file = event_file_data(m->private); |
@@ -403,6 +457,34 @@ clear_event_triggers(struct trace_array *tr) | |||
403 | } | 457 | } |
404 | 458 | ||
405 | /** | 459 | /** |
460 | * update_cond_flag - Set or reset the TRIGGER_COND bit | ||
461 | * @file: The ftrace_event_file associated with the event | ||
462 | * | ||
463 | * If an event has triggers and any of those triggers has a filter or | ||
464 | * a post_trigger, trigger invocation needs to be deferred until after | ||
465 | * the current event has logged its data, and the event should have | ||
466 | * its TRIGGER_COND bit set, otherwise the TRIGGER_COND bit should be | ||
467 | * cleared. | ||
468 | */ | ||
469 | static void update_cond_flag(struct ftrace_event_file *file) | ||
470 | { | ||
471 | struct event_trigger_data *data; | ||
472 | bool set_cond = false; | ||
473 | |||
474 | list_for_each_entry_rcu(data, &file->triggers, list) { | ||
475 | if (data->filter || data->cmd_ops->post_trigger) { | ||
476 | set_cond = true; | ||
477 | break; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | if (set_cond) | ||
482 | set_bit(FTRACE_EVENT_FL_TRIGGER_COND_BIT, &file->flags); | ||
483 | else | ||
484 | clear_bit(FTRACE_EVENT_FL_TRIGGER_COND_BIT, &file->flags); | ||
485 | } | ||
486 | |||
487 | /** | ||
406 | * register_trigger - Generic event_command @reg implementation | 488 | * register_trigger - Generic event_command @reg implementation |
407 | * @glob: The raw string used to register the trigger | 489 | * @glob: The raw string used to register the trigger |
408 | * @ops: The trigger ops associated with the trigger | 490 | * @ops: The trigger ops associated with the trigger |
@@ -443,6 +525,7 @@ static int register_trigger(char *glob, struct event_trigger_ops *ops, | |||
443 | list_del_rcu(&data->list); | 525 | list_del_rcu(&data->list); |
444 | ret--; | 526 | ret--; |
445 | } | 527 | } |
528 | update_cond_flag(file); | ||
446 | out: | 529 | out: |
447 | return ret; | 530 | return ret; |
448 | } | 531 | } |
@@ -470,6 +553,7 @@ static void unregister_trigger(char *glob, struct event_trigger_ops *ops, | |||
470 | if (data->cmd_ops->trigger_type == test->cmd_ops->trigger_type) { | 553 | if (data->cmd_ops->trigger_type == test->cmd_ops->trigger_type) { |
471 | unregistered = true; | 554 | unregistered = true; |
472 | list_del_rcu(&data->list); | 555 | list_del_rcu(&data->list); |
556 | update_cond_flag(file); | ||
473 | trace_event_trigger_enable_disable(file, 0); | 557 | trace_event_trigger_enable_disable(file, 0); |
474 | break; | 558 | break; |
475 | } | 559 | } |
@@ -572,10 +656,78 @@ event_trigger_callback(struct event_command *cmd_ops, | |||
572 | return ret; | 656 | return ret; |
573 | 657 | ||
574 | out_free: | 658 | out_free: |
659 | if (cmd_ops->set_filter) | ||
660 | cmd_ops->set_filter(NULL, trigger_data, NULL); | ||
575 | kfree(trigger_data); | 661 | kfree(trigger_data); |
576 | goto out; | 662 | goto out; |
577 | } | 663 | } |
578 | 664 | ||
665 | /** | ||
666 | * set_trigger_filter - Generic event_command @set_filter implementation | ||
667 | * @filter_str: The filter string for the trigger, NULL to remove filter | ||
668 | * @trigger_data: Trigger-specific data | ||
669 | * @file: The ftrace_event_file associated with the event | ||
670 | * | ||
671 | * Common implementation for event command filter parsing and filter | ||
672 | * instantiation. | ||
673 | * | ||
674 | * Usually used directly as the @set_filter method in event command | ||
675 | * implementations. | ||
676 | * | ||
677 | * Also used to remove a filter (if filter_str = NULL). | ||
678 | * | ||
679 | * Return: 0 on success, errno otherwise | ||
680 | */ | ||
681 | static int set_trigger_filter(char *filter_str, | ||
682 | struct event_trigger_data *trigger_data, | ||
683 | struct ftrace_event_file *file) | ||
684 | { | ||
685 | struct event_trigger_data *data = trigger_data; | ||
686 | struct event_filter *filter = NULL, *tmp; | ||
687 | int ret = -EINVAL; | ||
688 | char *s; | ||
689 | |||
690 | if (!filter_str) /* clear the current filter */ | ||
691 | goto assign; | ||
692 | |||
693 | s = strsep(&filter_str, " \t"); | ||
694 | |||
695 | if (!strlen(s) || strcmp(s, "if") != 0) | ||
696 | goto out; | ||
697 | |||
698 | if (!filter_str) | ||
699 | goto out; | ||
700 | |||
701 | /* The filter is for the 'trigger' event, not the triggered event */ | ||
702 | ret = create_event_filter(file->event_call, filter_str, false, &filter); | ||
703 | if (ret) | ||
704 | goto out; | ||
705 | assign: | ||
706 | tmp = data->filter; | ||
707 | |||
708 | rcu_assign_pointer(data->filter, filter); | ||
709 | |||
710 | if (tmp) { | ||
711 | /* Make sure the call is done with the filter */ | ||
712 | synchronize_sched(); | ||
713 | free_event_filter(tmp); | ||
714 | } | ||
715 | |||
716 | kfree(data->filter_str); | ||
717 | data->filter_str = NULL; | ||
718 | |||
719 | if (filter_str) { | ||
720 | data->filter_str = kstrdup(filter_str, GFP_KERNEL); | ||
721 | if (!data->filter_str) { | ||
722 | free_event_filter(data->filter); | ||
723 | data->filter = NULL; | ||
724 | ret = -ENOMEM; | ||
725 | } | ||
726 | } | ||
727 | out: | ||
728 | return ret; | ||
729 | } | ||
730 | |||
579 | static void | 731 | static void |
580 | traceon_trigger(struct event_trigger_data *data) | 732 | traceon_trigger(struct event_trigger_data *data) |
581 | { | 733 | { |
@@ -685,6 +837,7 @@ static struct event_command trigger_traceon_cmd = { | |||
685 | .reg = register_trigger, | 837 | .reg = register_trigger, |
686 | .unreg = unregister_trigger, | 838 | .unreg = unregister_trigger, |
687 | .get_trigger_ops = onoff_get_trigger_ops, | 839 | .get_trigger_ops = onoff_get_trigger_ops, |
840 | .set_filter = set_trigger_filter, | ||
688 | }; | 841 | }; |
689 | 842 | ||
690 | static struct event_command trigger_traceoff_cmd = { | 843 | static struct event_command trigger_traceoff_cmd = { |
@@ -694,6 +847,7 @@ static struct event_command trigger_traceoff_cmd = { | |||
694 | .reg = register_trigger, | 847 | .reg = register_trigger, |
695 | .unreg = unregister_trigger, | 848 | .unreg = unregister_trigger, |
696 | .get_trigger_ops = onoff_get_trigger_ops, | 849 | .get_trigger_ops = onoff_get_trigger_ops, |
850 | .set_filter = set_trigger_filter, | ||
697 | }; | 851 | }; |
698 | 852 | ||
699 | #ifdef CONFIG_TRACER_SNAPSHOT | 853 | #ifdef CONFIG_TRACER_SNAPSHOT |
@@ -765,6 +919,7 @@ static struct event_command trigger_snapshot_cmd = { | |||
765 | .reg = register_snapshot_trigger, | 919 | .reg = register_snapshot_trigger, |
766 | .unreg = unregister_trigger, | 920 | .unreg = unregister_trigger, |
767 | .get_trigger_ops = snapshot_get_trigger_ops, | 921 | .get_trigger_ops = snapshot_get_trigger_ops, |
922 | .set_filter = set_trigger_filter, | ||
768 | }; | 923 | }; |
769 | 924 | ||
770 | static __init int register_trigger_snapshot_cmd(void) | 925 | static __init int register_trigger_snapshot_cmd(void) |
@@ -843,6 +998,7 @@ static struct event_command trigger_stacktrace_cmd = { | |||
843 | .reg = register_trigger, | 998 | .reg = register_trigger, |
844 | .unreg = unregister_trigger, | 999 | .unreg = unregister_trigger, |
845 | .get_trigger_ops = stacktrace_get_trigger_ops, | 1000 | .get_trigger_ops = stacktrace_get_trigger_ops, |
1001 | .set_filter = set_trigger_filter, | ||
846 | }; | 1002 | }; |
847 | 1003 | ||
848 | static __init int register_trigger_stacktrace_cmd(void) | 1004 | static __init int register_trigger_stacktrace_cmd(void) |
@@ -1100,6 +1256,8 @@ event_enable_trigger_func(struct event_command *cmd_ops, | |||
1100 | out_put: | 1256 | out_put: |
1101 | module_put(event_enable_file->event_call->mod); | 1257 | module_put(event_enable_file->event_call->mod); |
1102 | out_free: | 1258 | out_free: |
1259 | if (cmd_ops->set_filter) | ||
1260 | cmd_ops->set_filter(NULL, trigger_data, NULL); | ||
1103 | kfree(trigger_data); | 1261 | kfree(trigger_data); |
1104 | kfree(enable_data); | 1262 | kfree(enable_data); |
1105 | goto out; | 1263 | goto out; |
@@ -1137,6 +1295,7 @@ static int event_enable_register_trigger(char *glob, | |||
1137 | list_del_rcu(&data->list); | 1295 | list_del_rcu(&data->list); |
1138 | ret--; | 1296 | ret--; |
1139 | } | 1297 | } |
1298 | update_cond_flag(file); | ||
1140 | out: | 1299 | out: |
1141 | return ret; | 1300 | return ret; |
1142 | } | 1301 | } |
@@ -1157,6 +1316,7 @@ static void event_enable_unregister_trigger(char *glob, | |||
1157 | (enable_data->file == test_enable_data->file)) { | 1316 | (enable_data->file == test_enable_data->file)) { |
1158 | unregistered = true; | 1317 | unregistered = true; |
1159 | list_del_rcu(&data->list); | 1318 | list_del_rcu(&data->list); |
1319 | update_cond_flag(file); | ||
1160 | trace_event_trigger_enable_disable(file, 0); | 1320 | trace_event_trigger_enable_disable(file, 0); |
1161 | break; | 1321 | break; |
1162 | } | 1322 | } |
@@ -1191,6 +1351,7 @@ static struct event_command trigger_enable_cmd = { | |||
1191 | .reg = event_enable_register_trigger, | 1351 | .reg = event_enable_register_trigger, |
1192 | .unreg = event_enable_unregister_trigger, | 1352 | .unreg = event_enable_unregister_trigger, |
1193 | .get_trigger_ops = event_enable_get_trigger_ops, | 1353 | .get_trigger_ops = event_enable_get_trigger_ops, |
1354 | .set_filter = set_trigger_filter, | ||
1194 | }; | 1355 | }; |
1195 | 1356 | ||
1196 | static struct event_command trigger_disable_cmd = { | 1357 | static struct event_command trigger_disable_cmd = { |
@@ -1200,6 +1361,7 @@ static struct event_command trigger_disable_cmd = { | |||
1200 | .reg = event_enable_register_trigger, | 1361 | .reg = event_enable_register_trigger, |
1201 | .unreg = event_enable_unregister_trigger, | 1362 | .unreg = event_enable_unregister_trigger, |
1202 | .get_trigger_ops = event_enable_get_trigger_ops, | 1363 | .get_trigger_ops = event_enable_get_trigger_ops, |
1364 | .set_filter = set_trigger_filter, | ||
1203 | }; | 1365 | }; |
1204 | 1366 | ||
1205 | static __init void unregister_trigger_enable_disable_cmds(void) | 1367 | static __init void unregister_trigger_enable_disable_cmds(void) |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 936ec3960335..fdd955f2f1aa 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -306,8 +306,10 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
306 | struct syscall_trace_enter *entry; | 306 | struct syscall_trace_enter *entry; |
307 | struct syscall_metadata *sys_data; | 307 | struct syscall_metadata *sys_data; |
308 | struct ring_buffer_event *event; | 308 | struct ring_buffer_event *event; |
309 | enum event_trigger_type __tt = ETT_NONE; | ||
309 | struct ring_buffer *buffer; | 310 | struct ring_buffer *buffer; |
310 | unsigned long irq_flags; | 311 | unsigned long irq_flags; |
312 | unsigned long eflags; | ||
311 | int pc; | 313 | int pc; |
312 | int syscall_nr; | 314 | int syscall_nr; |
313 | int size; | 315 | int size; |
@@ -321,10 +323,14 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
321 | if (!ftrace_file) | 323 | if (!ftrace_file) |
322 | return; | 324 | return; |
323 | 325 | ||
324 | if (test_bit(FTRACE_EVENT_FL_TRIGGER_MODE_BIT, &ftrace_file->flags)) | 326 | eflags = ftrace_file->flags; |
325 | event_triggers_call(ftrace_file); | 327 | |
326 | if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) | 328 | if (!(eflags & FTRACE_EVENT_FL_TRIGGER_COND)) { |
327 | return; | 329 | if (eflags & FTRACE_EVENT_FL_TRIGGER_MODE) |
330 | event_triggers_call(ftrace_file, NULL); | ||
331 | if (eflags & FTRACE_EVENT_FL_SOFT_DISABLED) | ||
332 | return; | ||
333 | } | ||
328 | 334 | ||
329 | sys_data = syscall_nr_to_meta(syscall_nr); | 335 | sys_data = syscall_nr_to_meta(syscall_nr); |
330 | if (!sys_data) | 336 | if (!sys_data) |
@@ -345,9 +351,16 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
345 | entry->nr = syscall_nr; | 351 | entry->nr = syscall_nr; |
346 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); | 352 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); |
347 | 353 | ||
348 | if (!filter_check_discard(ftrace_file, entry, buffer, event)) | 354 | if (eflags & FTRACE_EVENT_FL_TRIGGER_COND) |
355 | __tt = event_triggers_call(ftrace_file, entry); | ||
356 | |||
357 | if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) | ||
358 | ring_buffer_discard_commit(buffer, event); | ||
359 | else if (!filter_check_discard(ftrace_file, entry, buffer, event)) | ||
349 | trace_current_buffer_unlock_commit(buffer, event, | 360 | trace_current_buffer_unlock_commit(buffer, event, |
350 | irq_flags, pc); | 361 | irq_flags, pc); |
362 | if (__tt) | ||
363 | event_triggers_post_call(ftrace_file, __tt); | ||
351 | } | 364 | } |
352 | 365 | ||
353 | static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | 366 | static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) |
@@ -357,8 +370,10 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | |||
357 | struct syscall_trace_exit *entry; | 370 | struct syscall_trace_exit *entry; |
358 | struct syscall_metadata *sys_data; | 371 | struct syscall_metadata *sys_data; |
359 | struct ring_buffer_event *event; | 372 | struct ring_buffer_event *event; |
373 | enum event_trigger_type __tt = ETT_NONE; | ||
360 | struct ring_buffer *buffer; | 374 | struct ring_buffer *buffer; |
361 | unsigned long irq_flags; | 375 | unsigned long irq_flags; |
376 | unsigned long eflags; | ||
362 | int pc; | 377 | int pc; |
363 | int syscall_nr; | 378 | int syscall_nr; |
364 | 379 | ||
@@ -371,10 +386,14 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | |||
371 | if (!ftrace_file) | 386 | if (!ftrace_file) |
372 | return; | 387 | return; |
373 | 388 | ||
374 | if (test_bit(FTRACE_EVENT_FL_TRIGGER_MODE_BIT, &ftrace_file->flags)) | 389 | eflags = ftrace_file->flags; |
375 | event_triggers_call(ftrace_file); | 390 | |
376 | if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) | 391 | if (!(eflags & FTRACE_EVENT_FL_TRIGGER_COND)) { |
377 | return; | 392 | if (eflags & FTRACE_EVENT_FL_TRIGGER_MODE) |
393 | event_triggers_call(ftrace_file, NULL); | ||
394 | if (eflags & FTRACE_EVENT_FL_SOFT_DISABLED) | ||
395 | return; | ||
396 | } | ||
378 | 397 | ||
379 | sys_data = syscall_nr_to_meta(syscall_nr); | 398 | sys_data = syscall_nr_to_meta(syscall_nr); |
380 | if (!sys_data) | 399 | if (!sys_data) |
@@ -394,9 +413,16 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | |||
394 | entry->nr = syscall_nr; | 413 | entry->nr = syscall_nr; |
395 | entry->ret = syscall_get_return_value(current, regs); | 414 | entry->ret = syscall_get_return_value(current, regs); |
396 | 415 | ||
397 | if (!filter_check_discard(ftrace_file, entry, buffer, event)) | 416 | if (eflags & FTRACE_EVENT_FL_TRIGGER_COND) |
417 | __tt = event_triggers_call(ftrace_file, entry); | ||
418 | |||
419 | if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) | ||
420 | ring_buffer_discard_commit(buffer, event); | ||
421 | else if (!filter_check_discard(ftrace_file, entry, buffer, event)) | ||
398 | trace_current_buffer_unlock_commit(buffer, event, | 422 | trace_current_buffer_unlock_commit(buffer, event, |
399 | irq_flags, pc); | 423 | irq_flags, pc); |
424 | if (__tt) | ||
425 | event_triggers_post_call(ftrace_file, __tt); | ||
400 | } | 426 | } |
401 | 427 | ||
402 | static int reg_event_syscall_enter(struct ftrace_event_file *file, | 428 | static int reg_event_syscall_enter(struct ftrace_event_file *file, |