ftrace: add ftrace_enabled sysctl to disable mcount function
authorSteven Rostedt <srostedt@redhat.com>
Mon, 12 May 2008 19:20:43 +0000 (21:20 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Fri, 23 May 2008 18:33:19 +0000 (20:33 +0200)
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>
include/linux/ftrace.h
kernel/sysctl.c
kernel/trace/ftrace.c

index 90dbc0e..ccd8537 100644 (file)
@@ -5,6 +5,12 @@
 
 #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);
 
 struct ftrace_ops {
index 2911665..efaf7c5 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/acpi.h>
 #include <linux/reboot.h>
+#include <linux/ftrace.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -455,6 +456,16 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .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
        {
                .ctl_name       = KERN_MODPROBE,
index d1ae2ba..d3de372 100644 (file)
 #include <linux/hardirq.h>
 #include <linux/ftrace.h>
 #include <linux/module.h>
+#include <linux/sysctl.h>
 #include <linux/hash.h>
 #include <linux/list.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_MUTEX(ftrace_sysctl_lock);
+
 static struct ftrace_ops ftrace_list_end __read_mostly =
 {
        .func = ftrace_stub,
@@ -78,14 +90,16 @@ static int notrace __register_ftrace_function(struct ftrace_ops *ops)
        smp_wmb();
        ftrace_list = ops;
 
-       /*
-        * For one func, simply call it directly.
-        * For more than one func, call the chain.
-        */
-       if (ops->next == &ftrace_list_end)
-               ftrace_trace_function = ops->func;
-       else
-               ftrace_trace_function = ftrace_list_func;
+       if (ftrace_enabled) {
+               /*
+                * For one func, simply call it directly.
+                * For more than one func, call the chain.
+                */
+               if (ops->next == &ftrace_list_end)
+                       ftrace_trace_function = ops->func;
+               else
+                       ftrace_trace_function = ftrace_list_func;
+       }
 
        spin_unlock(&ftrace_lock);
 
@@ -120,10 +134,12 @@ static int notrace __unregister_ftrace_function(struct ftrace_ops *ops)
 
        *p = (*p)->next;
 
-       /* If we only have one func left, then call that directly */
-       if (ftrace_list == &ftrace_list_end ||
-           ftrace_list->next == &ftrace_list_end)
-               ftrace_trace_function = ftrace_list->func;
+       if (ftrace_enabled) {
+               /* If we only have one func left, then call that directly */
+               if (ftrace_list == &ftrace_list_end ||
+                   ftrace_list->next == &ftrace_list_end)
+                       ftrace_trace_function = ftrace_list->func;
+       }
 
  out:
        spin_unlock(&ftrace_lock);
@@ -263,7 +279,8 @@ static void notrace ftrace_startup(void)
                goto out;
        __unregister_ftrace_function(&ftrace_shutdown_ops);
 
-       ftrace_run_startup_code();
+       if (ftrace_enabled)
+               ftrace_run_startup_code();
  out:
        mutex_unlock(&ftraced_lock);
 }
@@ -275,13 +292,32 @@ static void notrace ftrace_shutdown(void)
        if (ftraced_suspend)
                goto out;
 
-       ftrace_run_shutdown_code();
+       if (ftrace_enabled)
+               ftrace_run_shutdown_code();
 
        __register_ftrace_function(&ftrace_shutdown_ops);
  out:
        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 unsigned long   ftrace_update_cnt;
 unsigned long          ftrace_update_tot_cnt;
@@ -341,8 +377,9 @@ static int notrace ftraced(void *ignore)
                /* check once a second */
                schedule_timeout(HZ);
 
+               mutex_lock(&ftrace_sysctl_lock);
                mutex_lock(&ftraced_lock);
-               if (ftraced_trigger && !ftraced_suspend) {
+               if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) {
                        ftrace_record_suspend++;
                        ftrace_update_code();
                        usecs = nsecs_to_usecs(ftrace_update_time);
@@ -360,6 +397,7 @@ static int notrace ftraced(void *ignore)
                        ftrace_record_suspend--;
                }
                mutex_unlock(&ftraced_lock);
+               mutex_unlock(&ftrace_sysctl_lock);
 
                ftrace_shutdown_replenish();
 
@@ -389,8 +427,10 @@ static int __init notrace ftrace_shutdown_init(void)
 
 core_initcall(ftrace_shutdown_init);
 #else
-# define ftrace_startup()      do { } while (0)
-# define ftrace_shutdown()     do { } while (0)
+# define ftrace_startup()        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 */
 
 /**
@@ -406,9 +446,15 @@ core_initcall(ftrace_shutdown_init);
  */
 int register_ftrace_function(struct ftrace_ops *ops)
 {
+       int ret;
+
+       mutex_lock(&ftrace_sysctl_lock);
        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;
 
+       mutex_lock(&ftrace_sysctl_lock);
        ret = __unregister_ftrace_function(ops);
 
        if (ftrace_list == &ftrace_list_end)
                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;
 }