#include "trace.h"
 
-int ftrace_enabled;
+/* ftrace_enabled is a method to turn ftrace on or off */
+int ftrace_enabled __read_mostly;
 static int last_ftrace_enabled;
 
+/*
+ * ftrace_disabled is set when an anomaly is discovered.
+ * ftrace_disabled is much stronger than ftrace_enabled.
+ */
+static int ftrace_disabled __read_mostly;
+
 static DEFINE_SPINLOCK(ftrace_lock);
 static DEFINE_MUTEX(ftrace_sysctl_lock);
 
        if (ftrace_free_records) {
                rec = ftrace_free_records;
 
-               /* todo, disable tracing altogether on this warning */
                if (unlikely(!(rec->flags & FTRACE_FL_FREE))) {
                        WARN_ON_ONCE(1);
                        ftrace_free_records = NULL;
+                       ftrace_disabled = 1;
+                       ftrace_enabled = 0;
                        return NULL;
                }
 
        int resched;
        int atomic;
 
-       if (!ftrace_enabled)
+       if (!ftrace_enabled || ftrace_disabled)
                return;
 
        resched = need_resched();
 {
        int command = 0;
 
+       if (unlikely(ftrace_disabled))
+               return;
+
        mutex_lock(&ftraced_lock);
        ftraced_suspend++;
        if (ftraced_suspend == 1)
 {
        int command = 0;
 
+       if (unlikely(ftrace_disabled))
+               return;
+
        mutex_lock(&ftraced_lock);
        ftraced_suspend--;
        if (!ftraced_suspend)
 {
        int command = FTRACE_ENABLE_MCOUNT;
 
+       if (unlikely(ftrace_disabled))
+               return;
+
        mutex_lock(&ftraced_lock);
        /* Force update next time */
        saved_ftrace_func = NULL;
 {
        int command = FTRACE_DISABLE_MCOUNT;
 
+       if (unlikely(ftrace_disabled))
+               return;
+
        mutex_lock(&ftraced_lock);
        /* ftraced_suspend is true if ftrace is running */
        if (ftraced_suspend)
 
 static void notrace ftrace_update_code(void)
 {
+       if (unlikely(ftrace_disabled))
+               return;
+
        stop_machine_run(__ftrace_update_code, NULL, NR_CPUS);
 }
 
                /* check once a second */
                schedule_timeout(HZ);
 
+               if (unlikely(ftrace_disabled))
+                       continue;
+
                mutex_lock(&ftrace_sysctl_lock);
                mutex_lock(&ftraced_lock);
                if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) {
                                        ftrace_update_cnt != 1 ? "s" : "",
                                        ftrace_update_tot_cnt,
                                        usecs, usecs != 1 ? "s" : "");
+                               ftrace_disabled = 1;
                                WARN_ON_ONCE(1);
                        }
                        ftraced_trigger = 0;
        struct ftrace_iterator *iter;
        int ret;
 
+       if (unlikely(ftrace_disabled))
+               return -ENODEV;
+
        iter = kzalloc(sizeof(*iter), GFP_KERNEL);
        if (!iter)
                return -ENOMEM;
        struct ftrace_iterator *iter;
        int ret = 0;
 
+       if (unlikely(ftrace_disabled))
+               return -ENODEV;
+
        iter = kzalloc(sizeof(*iter), GFP_KERNEL);
        if (!iter)
                return -ENOMEM;
  */
 notrace void ftrace_set_filter(unsigned char *buf, int len, int reset)
 {
+       if (unlikely(ftrace_disabled))
+               return;
+
        mutex_lock(&ftrace_filter_lock);
        if (reset)
                ftrace_filter_reset();
        DECLARE_WAITQUEUE(wait, current);
        int ret = 0;
 
-       if (!ftraced_task)
+       if (unlikely(ftrace_disabled))
                return -ENODEV;
 
        mutex_lock(&ftraced_lock);
        set_current_state(TASK_INTERRUPTIBLE);
        add_wait_queue(&ftraced_waiters, &wait);
 
+       if (unlikely(!ftraced_task)) {
+               ret = -ENODEV;
+               goto out;
+       }
+
        do {
                mutex_unlock(&ftraced_lock);
                wake_up_process(ftraced_task);
                set_current_state(TASK_INTERRUPTIBLE);
        } while (last_counter == ftraced_iteration_counter);
 
+ out:
        mutex_unlock(&ftraced_lock);
        remove_wait_queue(&ftraced_waiters, &wait);
        set_current_state(TASK_RUNNING);
        return ret;
 }
 
+static void ftrace_force_shutdown(void)
+{
+       struct task_struct *task;
+       int command = FTRACE_DISABLE_CALLS | FTRACE_UPDATE_TRACE_FUNC;
+
+       mutex_lock(&ftraced_lock);
+       task = ftraced_task;
+       ftraced_task = NULL;
+       ftraced_suspend = -1;
+       ftrace_run_update_code(command);
+       mutex_unlock(&ftraced_lock);
+
+       if (task)
+               kthread_stop(task);
+}
+
 static __init int ftrace_init_debugfs(void)
 {
        struct dentry *d_tracer;
        stop_machine_run(ftrace_dyn_arch_init, &addr, NR_CPUS);
 
        /* ftrace_dyn_arch_init places the return code in addr */
-       if (addr)
-               return addr;
+       if (addr) {
+               ret = (int)addr;
+               goto failed;
+       }
 
        ret = ftrace_dyn_table_alloc();
        if (ret)
-               return ret;
+               goto failed;
 
        p = kthread_run(ftraced, NULL, "ftraced");
-       if (IS_ERR(p))
-               return -1;
+       if (IS_ERR(p)) {
+               ret = -1;
+               goto failed;
+       }
 
        last_ftrace_enabled = ftrace_enabled = 1;
        ftraced_task = p;
 
        return 0;
+
+ failed:
+       ftrace_disabled = 1;
+       return ret;
 }
 
 core_initcall(ftrace_dynamic_init);
 # define ftrace_shutdown()             do { } while (0)
 # define ftrace_startup_sysctl()       do { } while (0)
 # define ftrace_shutdown_sysctl()      do { } while (0)
+# define ftrace_force_shutdown()       do { } while (0)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
+/**
+ * ftrace_kill - totally shutdown ftrace
+ *
+ * This is a safety measure. If something was detected that seems
+ * wrong, calling this function will keep ftrace from doing
+ * any more modifications, and updates.
+ * used when something went wrong.
+ */
+void ftrace_kill(void)
+{
+       mutex_lock(&ftrace_sysctl_lock);
+       ftrace_disabled = 1;
+       ftrace_enabled = 0;
+
+       clear_ftrace_function();
+       mutex_unlock(&ftrace_sysctl_lock);
+
+       /* Try to totally disable ftrace */
+       ftrace_force_shutdown();
+}
+
 /**
  * register_ftrace_function - register a function for profiling
  * @ops - ops structure that holds the function for profiling.
 {
        int ret;
 
+       if (unlikely(ftrace_disabled))
+               return -1;
+
        mutex_lock(&ftrace_sysctl_lock);
        ret = __register_ftrace_function(ops);
        ftrace_startup();
 {
        int ret;
 
+       if (unlikely(ftrace_disabled))
+               return -ENODEV;
+
        mutex_lock(&ftrace_sysctl_lock);
 
        ret  = proc_dointvec(table, write, file, buffer, lenp, ppos);