diff options
-rw-r--r-- | include/linux/ftrace.h | 2 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 39 | ||||
-rw-r--r-- | kernel/trace/trace.c | 4 | ||||
-rw-r--r-- | kernel/trace/trace.h | 25 | ||||
-rw-r--r-- | kernel/trace/trace_functions.c | 40 |
5 files changed, 96 insertions, 14 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index ef1607ed7044..e6141be2fad5 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -92,6 +92,7 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip, | |||
92 | * STUB - The ftrace_ops is just a place holder. | 92 | * STUB - The ftrace_ops is just a place holder. |
93 | * INITIALIZED - The ftrace_ops has already been initialized (first use time | 93 | * INITIALIZED - The ftrace_ops has already been initialized (first use time |
94 | * register_ftrace_function() is called, it will initialized the ops) | 94 | * register_ftrace_function() is called, it will initialized the ops) |
95 | * DELETED - The ops are being deleted, do not let them be registered again. | ||
95 | */ | 96 | */ |
96 | enum { | 97 | enum { |
97 | FTRACE_OPS_FL_ENABLED = 1 << 0, | 98 | FTRACE_OPS_FL_ENABLED = 1 << 0, |
@@ -103,6 +104,7 @@ enum { | |||
103 | FTRACE_OPS_FL_RECURSION_SAFE = 1 << 6, | 104 | FTRACE_OPS_FL_RECURSION_SAFE = 1 << 6, |
104 | FTRACE_OPS_FL_STUB = 1 << 7, | 105 | FTRACE_OPS_FL_STUB = 1 << 7, |
105 | FTRACE_OPS_FL_INITIALIZED = 1 << 8, | 106 | FTRACE_OPS_FL_INITIALIZED = 1 << 8, |
107 | FTRACE_OPS_FL_DELETED = 1 << 9, | ||
106 | }; | 108 | }; |
107 | 109 | ||
108 | /* | 110 | /* |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 2b3e23991c8a..dcee546f21bc 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -436,6 +436,9 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list, | |||
436 | 436 | ||
437 | static int __register_ftrace_function(struct ftrace_ops *ops) | 437 | static int __register_ftrace_function(struct ftrace_ops *ops) |
438 | { | 438 | { |
439 | if (ops->flags & FTRACE_OPS_FL_DELETED) | ||
440 | return -EINVAL; | ||
441 | |||
439 | if (FTRACE_WARN_ON(ops == &global_ops)) | 442 | if (FTRACE_WARN_ON(ops == &global_ops)) |
440 | return -EINVAL; | 443 | return -EINVAL; |
441 | 444 | ||
@@ -4112,6 +4115,36 @@ static const struct file_operations ftrace_graph_notrace_fops = { | |||
4112 | }; | 4115 | }; |
4113 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 4116 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
4114 | 4117 | ||
4118 | void ftrace_create_filter_files(struct ftrace_ops *ops, | ||
4119 | struct dentry *parent) | ||
4120 | { | ||
4121 | |||
4122 | trace_create_file("set_ftrace_filter", 0644, parent, | ||
4123 | ops, &ftrace_filter_fops); | ||
4124 | |||
4125 | trace_create_file("set_ftrace_notrace", 0644, parent, | ||
4126 | ops, &ftrace_notrace_fops); | ||
4127 | } | ||
4128 | |||
4129 | /* | ||
4130 | * The name "destroy_filter_files" is really a misnomer. Although | ||
4131 | * in the future, it may actualy delete the files, but this is | ||
4132 | * really intended to make sure the ops passed in are disabled | ||
4133 | * and that when this function returns, the caller is free to | ||
4134 | * free the ops. | ||
4135 | * | ||
4136 | * The "destroy" name is only to match the "create" name that this | ||
4137 | * should be paired with. | ||
4138 | */ | ||
4139 | void ftrace_destroy_filter_files(struct ftrace_ops *ops) | ||
4140 | { | ||
4141 | mutex_lock(&ftrace_lock); | ||
4142 | if (ops->flags & FTRACE_OPS_FL_ENABLED) | ||
4143 | ftrace_shutdown(ops, 0); | ||
4144 | ops->flags |= FTRACE_OPS_FL_DELETED; | ||
4145 | mutex_unlock(&ftrace_lock); | ||
4146 | } | ||
4147 | |||
4115 | static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) | 4148 | static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) |
4116 | { | 4149 | { |
4117 | 4150 | ||
@@ -4121,11 +4154,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) | |||
4121 | trace_create_file("enabled_functions", 0444, | 4154 | trace_create_file("enabled_functions", 0444, |
4122 | d_tracer, NULL, &ftrace_enabled_fops); | 4155 | d_tracer, NULL, &ftrace_enabled_fops); |
4123 | 4156 | ||
4124 | trace_create_file("set_ftrace_filter", 0644, d_tracer, | 4157 | ftrace_create_filter_files(&global_ops, d_tracer); |
4125 | &global_ops, &ftrace_filter_fops); | ||
4126 | |||
4127 | trace_create_file("set_ftrace_notrace", 0644, d_tracer, | ||
4128 | &global_ops, &ftrace_notrace_fops); | ||
4129 | 4158 | ||
4130 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 4159 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
4131 | trace_create_file("set_graph_function", 0444, d_tracer, | 4160 | trace_create_file("set_graph_function", 0444, d_tracer, |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index f9f22c435036..d95ec2876bbb 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -6161,6 +6161,7 @@ static int instance_delete(const char *name) | |||
6161 | 6161 | ||
6162 | tracing_set_nop(tr); | 6162 | tracing_set_nop(tr); |
6163 | event_trace_del_tracer(tr); | 6163 | event_trace_del_tracer(tr); |
6164 | ftrace_destroy_function_files(tr); | ||
6164 | debugfs_remove_recursive(tr->dir); | 6165 | debugfs_remove_recursive(tr->dir); |
6165 | free_percpu(tr->trace_buffer.data); | 6166 | free_percpu(tr->trace_buffer.data); |
6166 | ring_buffer_free(tr->trace_buffer.buffer); | 6167 | ring_buffer_free(tr->trace_buffer.buffer); |
@@ -6291,6 +6292,9 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) | |||
6291 | trace_create_file("tracing_on", 0644, d_tracer, | 6292 | trace_create_file("tracing_on", 0644, d_tracer, |
6292 | tr, &rb_simple_fops); | 6293 | tr, &rb_simple_fops); |
6293 | 6294 | ||
6295 | if (ftrace_create_function_files(tr, d_tracer)) | ||
6296 | WARN(1, "Could not allocate function filter files"); | ||
6297 | |||
6294 | #ifdef CONFIG_TRACER_SNAPSHOT | 6298 | #ifdef CONFIG_TRACER_SNAPSHOT |
6295 | trace_create_file("snapshot", 0644, d_tracer, | 6299 | trace_create_file("snapshot", 0644, d_tracer, |
6296 | tr, &snapshot_fops); | 6300 | tr, &snapshot_fops); |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 35cca055da0f..ffc314b7e92b 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -819,13 +819,36 @@ static inline int ftrace_trace_task(struct task_struct *task) | |||
819 | return test_tsk_trace_trace(task); | 819 | return test_tsk_trace_trace(task); |
820 | } | 820 | } |
821 | extern int ftrace_is_dead(void); | 821 | extern int ftrace_is_dead(void); |
822 | int ftrace_create_function_files(struct trace_array *tr, | ||
823 | struct dentry *parent); | ||
824 | void ftrace_destroy_function_files(struct trace_array *tr); | ||
822 | #else | 825 | #else |
823 | static inline int ftrace_trace_task(struct task_struct *task) | 826 | static inline int ftrace_trace_task(struct task_struct *task) |
824 | { | 827 | { |
825 | return 1; | 828 | return 1; |
826 | } | 829 | } |
827 | static inline int ftrace_is_dead(void) { return 0; } | 830 | static inline int ftrace_is_dead(void) { return 0; } |
828 | #endif | 831 | static inline int |
832 | ftrace_create_function_files(struct trace_array *tr, | ||
833 | struct dentry *parent) | ||
834 | { | ||
835 | return 0; | ||
836 | } | ||
837 | static inline void ftrace_destroy_function_files(struct trace_array *tr) { } | ||
838 | #endif /* CONFIG_FUNCTION_TRACER */ | ||
839 | |||
840 | #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE) | ||
841 | void ftrace_create_filter_files(struct ftrace_ops *ops, | ||
842 | struct dentry *parent); | ||
843 | void ftrace_destroy_filter_files(struct ftrace_ops *ops); | ||
844 | #else | ||
845 | /* | ||
846 | * The ops parameter passed in is usually undefined. | ||
847 | * This must be a macro. | ||
848 | */ | ||
849 | #define ftrace_create_filter_files(ops, parent) do { } while (0) | ||
850 | #define ftrace_destroy_filter_files(ops) do { } while (0) | ||
851 | #endif /* CONFIG_FUNCTION_TRACER && CONFIG_DYNAMIC_FTRACE */ | ||
829 | 852 | ||
830 | int ftrace_event_is_function(struct ftrace_event_call *call); | 853 | int ftrace_event_is_function(struct ftrace_event_call *call); |
831 | 854 | ||
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index 3f8dc1ce8b9c..5b781d2be383 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c | |||
@@ -52,10 +52,34 @@ static int allocate_ftrace_ops(struct trace_array *tr) | |||
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
55 | |||
56 | int ftrace_create_function_files(struct trace_array *tr, | ||
57 | struct dentry *parent) | ||
58 | { | ||
59 | int ret; | ||
60 | |||
61 | /* The top level array uses the "global_ops". */ | ||
62 | if (!(tr->flags & TRACE_ARRAY_FL_GLOBAL)) { | ||
63 | ret = allocate_ftrace_ops(tr); | ||
64 | if (ret) | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | ftrace_create_filter_files(tr->ops, parent); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | void ftrace_destroy_function_files(struct trace_array *tr) | ||
74 | { | ||
75 | ftrace_destroy_filter_files(tr->ops); | ||
76 | kfree(tr->ops); | ||
77 | tr->ops = NULL; | ||
78 | } | ||
79 | |||
55 | static int function_trace_init(struct trace_array *tr) | 80 | static int function_trace_init(struct trace_array *tr) |
56 | { | 81 | { |
57 | struct ftrace_ops *ops; | 82 | struct ftrace_ops *ops; |
58 | int ret; | ||
59 | 83 | ||
60 | if (tr->flags & TRACE_ARRAY_FL_GLOBAL) { | 84 | if (tr->flags & TRACE_ARRAY_FL_GLOBAL) { |
61 | /* There's only one global tr */ | 85 | /* There's only one global tr */ |
@@ -69,10 +93,13 @@ static int function_trace_init(struct trace_array *tr) | |||
69 | else | 93 | else |
70 | ops = &trace_ops; | 94 | ops = &trace_ops; |
71 | tr->ops = ops; | 95 | tr->ops = ops; |
72 | } else { | 96 | } else if (!tr->ops) { |
73 | ret = allocate_ftrace_ops(tr); | 97 | /* |
74 | if (ret) | 98 | * Instance trace_arrays get their ops allocated |
75 | return ret; | 99 | * at instance creation. Unless it failed |
100 | * the allocation. | ||
101 | */ | ||
102 | return -ENOMEM; | ||
76 | } | 103 | } |
77 | 104 | ||
78 | tr->trace_buffer.cpu = get_cpu(); | 105 | tr->trace_buffer.cpu = get_cpu(); |
@@ -87,9 +114,6 @@ static void function_trace_reset(struct trace_array *tr) | |||
87 | { | 114 | { |
88 | tracing_stop_function_trace(tr); | 115 | tracing_stop_function_trace(tr); |
89 | tracing_stop_cmdline_record(); | 116 | tracing_stop_cmdline_record(); |
90 | if (!(tr->flags & TRACE_ARRAY_FL_GLOBAL)) | ||
91 | kfree(tr->ops); | ||
92 | tr->ops = NULL; | ||
93 | } | 117 | } |
94 | 118 | ||
95 | static void function_trace_start(struct trace_array *tr) | 119 | static void function_trace_start(struct trace_array *tr) |