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>
This commit is contained in:
parent
3d0833953e
commit
b0fc494fae
@ -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 @@
|
|||||||
#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[] = {
|
|||||||
.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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
*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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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);
|
|||||||
#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);
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user