diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2008-05-12 15:20:43 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2008-05-23 14:33:19 -0400 |
| commit | b0fc494fae96a7089f3651cb451f461c7291244c (patch) | |
| tree | 586412b9ecbd8e3f04e8cd90a31644f94ff3a7d8 | |
| parent | 3d0833953e1b98b79ddf491dd49229eef9baeac1 (diff) | |
ftrace: add ftrace_enabled sysctl to disable mcount function
This patch adds back the sysctl ftrace_enabled. This time it is
defaulted to on, if DYNAMIC_FTRACE is configured. When ftrace_enabled
is disabled, the ftrace function is set to the stub return.
If DYNAMIC_FTRACE is also configured, on ftrace_enabled = 0,
the registered ftrace functions will all be set to jmps, but no more
new calls to ftrace recording (used to find the ftrace calling sites)
will be called.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | include/linux/ftrace.h | 6 | ||||
| -rw-r--r-- | kernel/sysctl.c | 11 | ||||
| -rw-r--r-- | kernel/trace/ftrace.c | 125 |
3 files changed, 124 insertions, 18 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 90dbc0ee2046..ccd8537dbdb7 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
| @@ -5,6 +5,12 @@ | |||
| 5 | 5 | ||
| 6 | #include <linux/linkage.h> | 6 | #include <linux/linkage.h> |
| 7 | 7 | ||
| 8 | extern int ftrace_enabled; | ||
| 9 | extern int | ||
| 10 | ftrace_enable_sysctl(struct ctl_table *table, int write, | ||
| 11 | struct file *filp, void __user *buffer, size_t *lenp, | ||
| 12 | loff_t *ppos); | ||
| 13 | |||
| 8 | typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); | 14 | typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); |
| 9 | 15 | ||
| 10 | struct ftrace_ops { | 16 | struct ftrace_ops { |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 29116652dca8..efaf7c5500e9 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include <linux/nfs_fs.h> | 46 | #include <linux/nfs_fs.h> |
| 47 | #include <linux/acpi.h> | 47 | #include <linux/acpi.h> |
| 48 | #include <linux/reboot.h> | 48 | #include <linux/reboot.h> |
| 49 | #include <linux/ftrace.h> | ||
| 49 | 50 | ||
| 50 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
| 51 | #include <asm/processor.h> | 52 | #include <asm/processor.h> |
| @@ -455,6 +456,16 @@ static struct ctl_table kern_table[] = { | |||
| 455 | .mode = 0644, | 456 | .mode = 0644, |
| 456 | .proc_handler = &proc_dointvec, | 457 | .proc_handler = &proc_dointvec, |
| 457 | }, | 458 | }, |
| 459 | #ifdef CONFIG_FTRACE | ||
| 460 | { | ||
| 461 | .ctl_name = CTL_UNNUMBERED, | ||
| 462 | .procname = "ftrace_enabled", | ||
| 463 | .data = &ftrace_enabled, | ||
| 464 | .maxlen = sizeof(int), | ||
| 465 | .mode = 0644, | ||
| 466 | .proc_handler = &ftrace_enable_sysctl, | ||
| 467 | }, | ||
| 468 | #endif | ||
| 458 | #ifdef CONFIG_KMOD | 469 | #ifdef CONFIG_KMOD |
| 459 | { | 470 | { |
| 460 | .ctl_name = KERN_MODPROBE, | 471 | .ctl_name = KERN_MODPROBE, |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index d1ae2ba25274..d3de37299ba4 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -20,12 +20,24 @@ | |||
| 20 | #include <linux/hardirq.h> | 20 | #include <linux/hardirq.h> |
| 21 | #include <linux/ftrace.h> | 21 | #include <linux/ftrace.h> |
| 22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 23 | #include <linux/sysctl.h> | ||
| 23 | #include <linux/hash.h> | 24 | #include <linux/hash.h> |
| 24 | #include <linux/list.h> | 25 | #include <linux/list.h> |
| 25 | 26 | ||
| 26 | #include "trace.h" | 27 | #include "trace.h" |
| 27 | 28 | ||
| 29 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
| 30 | # define FTRACE_ENABLED_INIT 1 | ||
| 31 | #else | ||
| 32 | # define FTRACE_ENABLED_INIT 0 | ||
| 33 | #endif | ||
| 34 | |||
| 35 | int ftrace_enabled = FTRACE_ENABLED_INIT; | ||
| 36 | static int last_ftrace_enabled = FTRACE_ENABLED_INIT; | ||
| 37 | |||
| 28 | static DEFINE_SPINLOCK(ftrace_lock); | 38 | static DEFINE_SPINLOCK(ftrace_lock); |
| 39 | static DEFINE_MUTEX(ftrace_sysctl_lock); | ||
| 40 | |||
| 29 | static struct ftrace_ops ftrace_list_end __read_mostly = | 41 | static struct ftrace_ops ftrace_list_end __read_mostly = |
| 30 | { | 42 | { |
| 31 | .func = ftrace_stub, | 43 | .func = ftrace_stub, |
| @@ -78,14 +90,16 @@ static int notrace __register_ftrace_function(struct ftrace_ops *ops) | |||
| 78 | smp_wmb(); | 90 | smp_wmb(); |
| 79 | ftrace_list = ops; | 91 | ftrace_list = ops; |
| 80 | 92 | ||
| 81 | /* | 93 | if (ftrace_enabled) { |
| 82 | * For one func, simply call it directly. | 94 | /* |
| 83 | * For more than one func, call the chain. | 95 | * For one func, simply call it directly. |
| 84 | */ | 96 | * For more than one func, call the chain. |
| 85 | if (ops->next == &ftrace_list_end) | 97 | */ |
| 86 | ftrace_trace_function = ops->func; | 98 | if (ops->next == &ftrace_list_end) |
| 87 | else | 99 | ftrace_trace_function = ops->func; |
| 88 | ftrace_trace_function = ftrace_list_func; | 100 | else |
| 101 | ftrace_trace_function = ftrace_list_func; | ||
| 102 | } | ||
| 89 | 103 | ||
| 90 | spin_unlock(&ftrace_lock); | 104 | spin_unlock(&ftrace_lock); |
| 91 | 105 | ||
| @@ -120,10 +134,12 @@ static int notrace __unregister_ftrace_function(struct ftrace_ops *ops) | |||
| 120 | 134 | ||
| 121 | *p = (*p)->next; | 135 | *p = (*p)->next; |
| 122 | 136 | ||
| 123 | /* If we only have one func left, then call that directly */ | 137 | if (ftrace_enabled) { |
| 124 | if (ftrace_list == &ftrace_list_end || | 138 | /* If we only have one func left, then call that directly */ |
| 125 | ftrace_list->next == &ftrace_list_end) | 139 | if (ftrace_list == &ftrace_list_end || |
| 126 | ftrace_trace_function = ftrace_list->func; | 140 | ftrace_list->next == &ftrace_list_end) |
| 141 | ftrace_trace_function = ftrace_list->func; | ||
| 142 | } | ||
| 127 | 143 | ||
| 128 | out: | 144 | out: |
| 129 | spin_unlock(&ftrace_lock); | 145 | spin_unlock(&ftrace_lock); |
| @@ -263,7 +279,8 @@ static void notrace ftrace_startup(void) | |||
| 263 | goto out; | 279 | goto out; |
| 264 | __unregister_ftrace_function(&ftrace_shutdown_ops); | 280 | __unregister_ftrace_function(&ftrace_shutdown_ops); |
| 265 | 281 | ||
| 266 | ftrace_run_startup_code(); | 282 | if (ftrace_enabled) |
| 283 | ftrace_run_startup_code(); | ||
| 267 | out: | 284 | out: |
| 268 | mutex_unlock(&ftraced_lock); | 285 | mutex_unlock(&ftraced_lock); |
| 269 | } | 286 | } |
| @@ -275,13 +292,32 @@ static void notrace ftrace_shutdown(void) | |||
| 275 | if (ftraced_suspend) | 292 | if (ftraced_suspend) |
| 276 | goto out; | 293 | goto out; |
| 277 | 294 | ||
| 278 | ftrace_run_shutdown_code(); | 295 | if (ftrace_enabled) |
| 296 | ftrace_run_shutdown_code(); | ||
| 279 | 297 | ||
| 280 | __register_ftrace_function(&ftrace_shutdown_ops); | 298 | __register_ftrace_function(&ftrace_shutdown_ops); |
| 281 | out: | 299 | out: |
| 282 | mutex_unlock(&ftraced_lock); | 300 | mutex_unlock(&ftraced_lock); |
| 283 | } | 301 | } |
| 284 | 302 | ||
| 303 | static void notrace ftrace_startup_sysctl(void) | ||
| 304 | { | ||
| 305 | mutex_lock(&ftraced_lock); | ||
| 306 | /* ftraced_suspend is true if we want ftrace running */ | ||
| 307 | if (ftraced_suspend) | ||
| 308 | ftrace_run_startup_code(); | ||
| 309 | mutex_unlock(&ftraced_lock); | ||
| 310 | } | ||
| 311 | |||
| 312 | static void notrace ftrace_shutdown_sysctl(void) | ||
| 313 | { | ||
| 314 | mutex_lock(&ftraced_lock); | ||
| 315 | /* ftraced_suspend is true if ftrace is running */ | ||
| 316 | if (ftraced_suspend) | ||
| 317 | ftrace_run_shutdown_code(); | ||
| 318 | mutex_unlock(&ftraced_lock); | ||
| 319 | } | ||
| 320 | |||
| 285 | static cycle_t ftrace_update_time; | 321 | static cycle_t ftrace_update_time; |
| 286 | static unsigned long ftrace_update_cnt; | 322 | static unsigned long ftrace_update_cnt; |
| 287 | unsigned long ftrace_update_tot_cnt; | 323 | unsigned long ftrace_update_tot_cnt; |
| @@ -341,8 +377,9 @@ static int notrace ftraced(void *ignore) | |||
| 341 | /* check once a second */ | 377 | /* check once a second */ |
| 342 | schedule_timeout(HZ); | 378 | schedule_timeout(HZ); |
| 343 | 379 | ||
| 380 | mutex_lock(&ftrace_sysctl_lock); | ||
| 344 | mutex_lock(&ftraced_lock); | 381 | mutex_lock(&ftraced_lock); |
| 345 | if (ftraced_trigger && !ftraced_suspend) { | 382 | if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) { |
| 346 | ftrace_record_suspend++; | 383 | ftrace_record_suspend++; |
| 347 | ftrace_update_code(); | 384 | ftrace_update_code(); |
| 348 | usecs = nsecs_to_usecs(ftrace_update_time); | 385 | usecs = nsecs_to_usecs(ftrace_update_time); |
| @@ -360,6 +397,7 @@ static int notrace ftraced(void *ignore) | |||
| 360 | ftrace_record_suspend--; | 397 | ftrace_record_suspend--; |
| 361 | } | 398 | } |
| 362 | mutex_unlock(&ftraced_lock); | 399 | mutex_unlock(&ftraced_lock); |
| 400 | mutex_unlock(&ftrace_sysctl_lock); | ||
| 363 | 401 | ||
| 364 | ftrace_shutdown_replenish(); | 402 | ftrace_shutdown_replenish(); |
| 365 | 403 | ||
| @@ -389,8 +427,10 @@ static | |||
