diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
| -rw-r--r-- | kernel/trace/ftrace.c | 1133 |
1 files changed, 876 insertions, 257 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index fdf913dfc7e..f1ed080406c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -27,6 +27,9 @@ | |||
| 27 | #include <linux/sysctl.h> | 27 | #include <linux/sysctl.h> |
| 28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
| 29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
| 30 | #include <linux/hash.h> | ||
| 31 | |||
| 32 | #include <trace/sched.h> | ||
| 30 | 33 | ||
| 31 | #include <asm/ftrace.h> | 34 | #include <asm/ftrace.h> |
| 32 | 35 | ||
| @@ -44,14 +47,14 @@ | |||
| 44 | ftrace_kill(); \ | 47 | ftrace_kill(); \ |
| 45 | } while (0) | 48 | } while (0) |
| 46 | 49 | ||
| 50 | /* hash bits for specific function selection */ | ||
| 51 | #define FTRACE_HASH_BITS 7 | ||
| 52 | #define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS) | ||
| 53 | |||
| 47 | /* ftrace_enabled is a method to turn ftrace on or off */ | 54 | /* ftrace_enabled is a method to turn ftrace on or off */ |
| 48 | int ftrace_enabled __read_mostly; | 55 | int ftrace_enabled __read_mostly; |
| 49 | static int last_ftrace_enabled; | 56 | static int last_ftrace_enabled; |
| 50 | 57 | ||
| 51 | /* set when tracing only a pid */ | ||
| 52 | struct pid *ftrace_pid_trace; | ||
| 53 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; | ||
| 54 | |||
| 55 | /* Quick disabling of function tracer. */ | 58 | /* Quick disabling of function tracer. */ |
| 56 | int function_trace_stop; | 59 | int function_trace_stop; |
| 57 | 60 | ||
| @@ -61,9 +64,7 @@ int function_trace_stop; | |||
| 61 | */ | 64 | */ |
| 62 | static int ftrace_disabled __read_mostly; | 65 | static int ftrace_disabled __read_mostly; |
| 63 | 66 | ||
| 64 | static DEFINE_SPINLOCK(ftrace_lock); | 67 | static DEFINE_MUTEX(ftrace_lock); |
| 65 | static DEFINE_MUTEX(ftrace_sysctl_lock); | ||
| 66 | static DEFINE_MUTEX(ftrace_start_lock); | ||
| 67 | 68 | ||
| 68 | static struct ftrace_ops ftrace_list_end __read_mostly = | 69 | static struct ftrace_ops ftrace_list_end __read_mostly = |
| 69 | { | 70 | { |
| @@ -134,9 +135,6 @@ static void ftrace_test_stop_func(unsigned long ip, unsigned long parent_ip) | |||
| 134 | 135 | ||
| 135 | static int __register_ftrace_function(struct ftrace_ops *ops) | 136 | static int __register_ftrace_function(struct ftrace_ops *ops) |
| 136 | { | 137 | { |
| 137 | /* should not be called from interrupt context */ | ||
| 138 | spin_lock(&ftrace_lock); | ||
| 139 | |||
| 140 | ops->next = ftrace_list; | 138 | ops->next = ftrace_list; |
| 141 | /* | 139 | /* |
| 142 | * We are entering ops into the ftrace_list but another | 140 | * We are entering ops into the ftrace_list but another |
| @@ -172,18 +170,12 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
| 172 | #endif | 170 | #endif |
| 173 | } | 171 | } |
| 174 | 172 | ||
| 175 | spin_unlock(&ftrace_lock); | ||
| 176 | |||
| 177 | return 0; | 173 | return 0; |
| 178 | } | 174 | } |
| 179 | 175 | ||
| 180 | static int __unregister_ftrace_function(struct ftrace_ops *ops) | 176 | static int __unregister_ftrace_function(struct ftrace_ops *ops) |
| 181 | { | 177 | { |
| 182 | struct ftrace_ops **p; | 178 | struct ftrace_ops **p; |
| 183 | int ret = 0; | ||
| 184 | |||
| 185 | /* should not be called from interrupt context */ | ||
| 186 | spin_lock(&ftrace_lock); | ||
| 187 | 179 | ||
| 188 | /* | 180 | /* |
| 189 | * If we are removing the last function, then simply point | 181 | * If we are removing the last function, then simply point |
| @@ -192,17 +184,15 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
| 192 | if (ftrace_list == ops && ops->next == &ftrace_list_end) { | 184 | if (ftrace_list == ops && ops->next == &ftrace_list_end) { |
| 193 | ftrace_trace_function = ftrace_stub; | 185 | ftrace_trace_function = ftrace_stub; |
| 194 | ftrace_list = &ftrace_list_end; | 186 | ftrace_list = &ftrace_list_end; |
| 195 | goto out; | 187 | return 0; |
| 196 | } | 188 | } |
| 197 | 189 | ||
| 198 | for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next) | 190 | for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next) |
| 199 | if (*p == ops) | 191 | if (*p == ops) |
| 200 | break; | 192 | break; |
| 201 | 193 | ||
| 202 | if (*p != ops) { | 194 | if (*p != ops) |
| 203 | ret = -1; | 195 | return -1; |
| 204 | goto out; | ||
| 205 | } | ||
| 206 | 196 | ||
| 207 | *p = (*p)->next; | 197 | *p = (*p)->next; |
| 208 | 198 | ||
| @@ -223,21 +213,15 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
| 223 | } | 213 | } |
| 224 | } | 214 | } |
| 225 | 215 | ||
| 226 | out: | 216 | return 0; |
| 227 | spin_unlock(&ftrace_lock); | ||
| 228 | |||
| 229 | return ret; | ||
| 230 | } | 217 | } |
| 231 | 218 | ||
| 232 | static void ftrace_update_pid_func(void) | 219 | static void ftrace_update_pid_func(void) |
| 233 | { | 220 | { |
| 234 | ftrace_func_t func; | 221 | ftrace_func_t func; |
| 235 | 222 | ||
| 236 | /* should not be called from interrupt context */ | ||
| 237 | spin_lock(&ftrace_lock); | ||
| 238 | |||
| 239 | if (ftrace_trace_function == ftrace_stub) | 223 | if (ftrace_trace_function == ftrace_stub) |
| 240 | goto out; | 224 | return; |
| 241 | 225 | ||
| 242 | func = ftrace_trace_function; | 226 | func = ftrace_trace_function; |
| 243 | 227 | ||
| @@ -254,23 +238,29 @@ static void ftrace_update_pid_func(void) | |||
| 254 | #else | 238 | #else |
| 255 | __ftrace_trace_function = func; | 239 | __ftrace_trace_function = func; |
| 256 | #endif | 240 | #endif |
| 257 | |||
| 258 | out: | ||
| 259 | spin_unlock(&ftrace_lock); | ||
| 260 | } | 241 | } |
| 261 | 242 | ||
| 243 | /* set when tracing only a pid */ | ||
| 244 | struct pid *ftrace_pid_trace; | ||
| 245 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; | ||
| 246 | |||
| 262 | #ifdef CONFIG_DYNAMIC_FTRACE | 247 | #ifdef CONFIG_DYNAMIC_FTRACE |
| 248 | |||
| 263 | #ifndef CONFIG_FTRACE_MCOUNT_RECORD | 249 | #ifndef CONFIG_FTRACE_MCOUNT_RECORD |
| 264 | # error Dynamic ftrace depends on MCOUNT_RECORD | 250 | # error Dynamic ftrace depends on MCOUNT_RECORD |
| 265 | #endif | 251 | #endif |
| 266 | 252 | ||
| 267 | /* | 253 | static struct hlist_head ftrace_func_hash[FTRACE_FUNC_HASHSIZE] __read_mostly; |
| 268 | * Since MCOUNT_ADDR may point to mcount itself, we do not want | 254 | |
| 269 | * to get it confused by reading a reference in the code as we | 255 | struct ftrace_func_probe { |
| 270 | * are parsing on objcopy output of text. Use a variable for | 256 | struct hlist_node node; |
| 271 | * it instead. | 257 | struct ftrace_probe_ops *ops; |
| 272 | */ | 258 | unsigned long flags; |
| 273 | static unsigned long mcount_addr = MCOUNT_ADDR; | 259 | unsigned long ip; |
| 260 | void *data; | ||
| 261 | struct rcu_head rcu; | ||
| 262 | }; | ||
| 263 | |||
| 274 | 264 | ||
| 275 | enum { | 265 | enum { |
| 276 | FTRACE_ENABLE_CALLS = (1 << 0), | 266 | FTRACE_ENABLE_CALLS = (1 << 0), |
| @@ -284,13 +274,13 @@ enum { | |||
| 284 | 274 | ||
| 285 | static int ftrace_filtered; | 275 | static int ftrace_filtered; |
| 286 | 276 | ||
| 287 | static LIST_HEAD(ftrace_new_addrs); | 277 | static struct dyn_ftrace *ftrace_new_addrs; |
| 288 | 278 | ||
| 289 | static DEFINE_MUTEX(ftrace_regex_lock); | 279 | static DEFINE_MUTEX(ftrace_regex_lock); |
| 290 | 280 | ||
| 291 | struct ftrace_page { | 281 | struct ftrace_page { |
| 292 | struct ftrace_page *next; | 282 | struct ftrace_page *next; |
| 293 | unsigned long index; | 283 | int index; |
| 294 | struct dyn_ftrace records[]; | 284 | struct dyn_ftrace records[]; |
| 295 | }; | 285 | }; |
| 296 | 286 | ||
| @@ -305,6 +295,19 @@ static struct ftrace_page *ftrace_pages; | |||
| 305 | 295 | ||
| 306 | static struct dyn_ftrace *ftrace_free_records; | 296 | static struct dyn_ftrace *ftrace_free_records; |
| 307 | 297 | ||
| 298 | /* | ||
| 299 | * This is a double for. Do not use 'break' to break out of the loop, | ||
| 300 | * you must use a goto. | ||
| 301 | */ | ||
| 302 | #define do_for_each_ftrace_rec(pg, rec) \ | ||
| 303 | for (pg = ftrace_pages_start; pg; pg = pg->next) { \ | ||
| 304 | int _____i; \ | ||
| 305 | for (_____i = 0; _____i < pg->index; _____i++) { \ | ||
