#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);