Commit b0fc494f authored by Steven Rostedt's avatar Steven Rostedt Committed by Thomas Gleixner

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: default avatarSteven Rostedt <srostedt@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 3d083395
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
#include <linux/linkage.h> #include <linux/linkage.h>
extern int ftrace_enabled;
extern int
ftrace_enable_sysctl(struct ctl_table *table, int write,
struct file *filp, void __user *buffer, size_t *lenp,
loff_t *ppos);
typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
struct ftrace_ops { struct ftrace_ops {
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/ftrace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -455,6 +456,16 @@ static struct ctl_table kern_table[] = { ...@@ -455,6 +456,16 @@ static struct ctl_table kern_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec,
}, },
#ifdef CONFIG_FTRACE
{
.ctl_name = CTL_UNNUMBERED,
.procname = "ftrace_enabled",
.data = &ftrace_enabled,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &ftrace_enable_sysctl,
},
#endif
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
{ {
.ctl_name = KERN_MODPROBE, .ctl_name = KERN_MODPROBE,
......
...@@ -20,12 +20,24 @@ ...@@ -20,12 +20,24 @@
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sysctl.h>
#include <linux/hash.h> #include <linux/hash.h>
#include <linux/list.h> #include <linux/list.h>
#include "trace.h" #include "trace.h"
#ifdef CONFIG_DYNAMIC_FTRACE
# define FTRACE_ENABLED_INIT 1
#else
# define FTRACE_ENABLED_INIT 0
#endif
int ftrace_enabled = FTRACE_ENABLED_INIT;
static int last_ftrace_enabled = FTRACE_ENABLED_INIT;
static DEFINE_SPINLOCK(ftrace_lock); static DEFINE_SPINLOCK(ftrace_lock);
static DEFINE_MUTEX(ftrace_sysctl_lock);
static struct ftrace_ops ftrace_list_end __read_mostly = static struct ftrace_ops ftrace_list_end __read_mostly =
{ {
.func = ftrace_stub, .func = ftrace_stub,
...@@ -78,6 +90,7 @@ static int notrace __register_ftrace_function(struct ftrace_ops *ops) ...@@ -78,6 +90,7 @@ static int notrace __register_ftrace_function(struct ftrace_ops *ops)
smp_wmb(); smp_wmb();
ftrace_list = ops; ftrace_list = ops;
if (ftrace_enabled) {
/* /*
* For one func, simply call it directly. * For one func, simply call it directly.
* For more than one func, call the chain. * For more than one func, call the chain.
...@@ -86,6 +99,7 @@ static int notrace __register_ftrace_function(struct ftrace_ops *ops) ...@@ -86,6 +99,7 @@ static int notrace __register_ftrace_function(struct ftrace_ops *ops)
ftrace_trace_function = ops->func; ftrace_trace_function = ops->func;
else else
ftrace_trace_function = ftrace_list_func; ftrace_trace_function = ftrace_list_func;
}
spin_unlock(&ftrace_lock); spin_unlock(&ftrace_lock);
...@@ -120,10 +134,12 @@ static int notrace __unregister_ftrace_function(struct ftrace_ops *ops) ...@@ -120,10 +134,12 @@ static int notrace __unregister_ftrace_function(struct ftrace_ops *ops)
*p = (*p)->next; *p = (*p)->next;
if (ftrace_enabled) {
/* If we only have one func left, then call that directly */ /* If we only have one func left, then call that directly */
if (ftrace_list == &ftrace_list_end || if (ftrace_list == &ftrace_list_end ||
ftrace_list->next == &ftrace_list_end) ftrace_list->next == &ftrace_list_end)
ftrace_trace_function = ftrace_list->func; ftrace_trace_function = ftrace_list->func;
}
out: out:
spin_unlock(&ftrace_lock); spin_unlock(&ftrace_lock);
...@@ -263,6 +279,7 @@ static void notrace ftrace_startup(void) ...@@ -263,6 +279,7 @@ static void notrace ftrace_startup(void)
goto out; goto out;
__unregister_ftrace_function(&ftrace_shutdown_ops); __unregister_ftrace_function(&ftrace_shutdown_ops);
if (ftrace_enabled)
ftrace_run_startup_code(); ftrace_run_startup_code();
out: out:
mutex_unlock(&ftraced_lock); mutex_unlock(&ftraced_lock);
...@@ -275,6 +292,7 @@ static void notrace ftrace_shutdown(void) ...@@ -275,6 +292,7 @@ static void notrace ftrace_shutdown(void)
if (ftraced_suspend) if (ftraced_suspend)
goto out; goto out;
if (ftrace_enabled)
ftrace_run_shutdown_code(); ftrace_run_shutdown_code();
__register_ftrace_function(&ftrace_shutdown_ops); __register_ftrace_function(&ftrace_shutdown_ops);
...@@ -282,6 +300,24 @@ static void notrace ftrace_shutdown(void) ...@@ -282,6 +300,24 @@ static void notrace ftrace_shutdown(void)
mutex_unlock(&ftraced_lock); mutex_unlock(&ftraced_lock);
} }
static void notrace ftrace_startup_sysctl(void)
{
mutex_lock(&ftraced_lock);
/* ftraced_suspend is true if we want ftrace running */
if (ftraced_suspend)
ftrace_run_startup_code();
mutex_unlock(&ftraced_lock);
}
static void notrace ftrace_shutdown_sysctl(void)
{
mutex_lock(&ftraced_lock);
/* ftraced_suspend is true if ftrace is running */
if (ftraced_suspend)
ftrace_run_shutdown_code();
mutex_unlock(&ftraced_lock);
}
static cycle_t ftrace_update_time; static cycle_t ftrace_update_time;
static unsigned long ftrace_update_cnt; static unsigned long ftrace_update_cnt;
unsigned long ftrace_update_tot_cnt; unsigned long ftrace_update_tot_cnt;
...@@ -341,8 +377,9 @@ static int notrace ftraced(void *ignore) ...@@ -341,8 +377,9 @@ static int notrace ftraced(void *ignore)
/* check once a second */ /* check once a second */
schedule_timeout(HZ); schedule_timeout(HZ);
mutex_lock(&ftrace_sysctl_lock);
mutex_lock(&ftraced_lock); mutex_lock(&ftraced_lock);
if (ftraced_trigger && !ftraced_suspend) { if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) {
ftrace_record_suspend++; ftrace_record_suspend++;
ftrace_update_code(); ftrace_update_code();
usecs = nsecs_to_usecs(ftrace_update_time); usecs = nsecs_to_usecs(ftrace_update_time);
...@@ -360,6 +397,7 @@ static int notrace ftraced(void *ignore) ...@@ -360,6 +397,7 @@ static int notrace ftraced(void *ignore)
ftrace_record_suspend--; ftrace_record_suspend--;
} }
mutex_unlock(&ftraced_lock); mutex_unlock(&ftraced_lock);
mutex_unlock(&ftrace_sysctl_lock);
ftrace_shutdown_replenish(); ftrace_shutdown_replenish();
...@@ -391,6 +429,8 @@ core_initcall(ftrace_shutdown_init); ...@@ -391,6 +429,8 @@ core_initcall(ftrace_shutdown_init);
#else #else
# define ftrace_startup() do { } while (0) # define ftrace_startup() do { } while (0)
# define ftrace_shutdown() do { } while (0) # define ftrace_shutdown() do { } while (0)
# define ftrace_startup_sysctl() do { } while (0)
# define ftrace_shutdown_sysctl() do { } while (0)
#endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_DYNAMIC_FTRACE */
/** /**
...@@ -406,9 +446,15 @@ core_initcall(ftrace_shutdown_init); ...@@ -406,9 +446,15 @@ core_initcall(ftrace_shutdown_init);
*/ */
int register_ftrace_function(struct ftrace_ops *ops) int register_ftrace_function(struct ftrace_ops *ops)
{ {
int ret;
mutex_lock(&ftrace_sysctl_lock);
ftrace_startup(); ftrace_startup();
return __register_ftrace_function(ops); ret = __register_ftrace_function(ops);
mutex_unlock(&ftrace_sysctl_lock);
return ret;
} }
/** /**
...@@ -421,10 +467,53 @@ int unregister_ftrace_function(struct ftrace_ops *ops) ...@@ -421,10 +467,53 @@ int unregister_ftrace_function(struct ftrace_ops *ops)
{ {
int ret; int ret;
mutex_lock(&ftrace_sysctl_lock);
ret = __unregister_ftrace_function(ops); ret = __unregister_ftrace_function(ops);
if (ftrace_list == &ftrace_list_end) if (ftrace_list == &ftrace_list_end)
ftrace_shutdown(); ftrace_shutdown();
mutex_unlock(&ftrace_sysctl_lock);
return ret;
}
notrace int
ftrace_enable_sysctl(struct ctl_table *table, int write,
struct file *filp, void __user *buffer, size_t *lenp,
loff_t *ppos)
{
int ret;
mutex_lock(&ftrace_sysctl_lock);
ret = proc_dointvec(table, write, filp, buffer, lenp, ppos);
if (ret || !write || (last_ftrace_enabled == ftrace_enabled))
goto out;
last_ftrace_enabled = ftrace_enabled;
if (ftrace_enabled) {
ftrace_startup_sysctl();
/* we are starting ftrace again */
if (ftrace_list != &ftrace_list_end) {
if (ftrace_list->next == &ftrace_list_end)
ftrace_trace_function = ftrace_list->func;
else
ftrace_trace_function = ftrace_list_func;
}
} else {
/* stopping ftrace calls (just send to ftrace_stub) */
ftrace_trace_function = ftrace_stub;
ftrace_shutdown_sysctl();
}
out:
mutex_unlock(&ftrace_sysctl_lock);
return ret; return ret;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment