xref: /linux-6.15/kernel/trace/ftrace.c (revision e1c08bdd)
116444a8aSArnaldo Carvalho de Melo /*
216444a8aSArnaldo Carvalho de Melo  * Infrastructure for profiling code inserted by 'gcc -pg'.
316444a8aSArnaldo Carvalho de Melo  *
416444a8aSArnaldo Carvalho de Melo  * Copyright (C) 2007-2008 Steven Rostedt <[email protected]>
516444a8aSArnaldo Carvalho de Melo  * Copyright (C) 2004-2008 Ingo Molnar <[email protected]>
616444a8aSArnaldo Carvalho de Melo  *
716444a8aSArnaldo Carvalho de Melo  * Originally ported from the -rt patch by:
816444a8aSArnaldo Carvalho de Melo  *   Copyright (C) 2007 Arnaldo Carvalho de Melo <[email protected]>
916444a8aSArnaldo Carvalho de Melo  *
1016444a8aSArnaldo Carvalho de Melo  * Based on code in the latency_tracer, that is:
1116444a8aSArnaldo Carvalho de Melo  *
1216444a8aSArnaldo Carvalho de Melo  *  Copyright (C) 2004-2006 Ingo Molnar
1316444a8aSArnaldo Carvalho de Melo  *  Copyright (C) 2004 William Lee Irwin III
1416444a8aSArnaldo Carvalho de Melo  */
1516444a8aSArnaldo Carvalho de Melo 
163d083395SSteven Rostedt #include <linux/stop_machine.h>
173d083395SSteven Rostedt #include <linux/clocksource.h>
183d083395SSteven Rostedt #include <linux/kallsyms.h>
195072c59fSSteven Rostedt #include <linux/seq_file.h>
205072c59fSSteven Rostedt #include <linux/debugfs.h>
213d083395SSteven Rostedt #include <linux/kthread.h>
223d083395SSteven Rostedt #include <linux/hardirq.h>
2316444a8aSArnaldo Carvalho de Melo #include <linux/ftrace.h>
245072c59fSSteven Rostedt #include <linux/uaccess.h>
25b0fc494fSSteven Rostedt #include <linux/sysctl.h>
263d083395SSteven Rostedt #include <linux/hash.h>
275072c59fSSteven Rostedt #include <linux/ctype.h>
283d083395SSteven Rostedt #include <linux/list.h>
2916444a8aSArnaldo Carvalho de Melo 
303d083395SSteven Rostedt #include "trace.h"
313d083395SSteven Rostedt 
32d61f82d0SSteven Rostedt int ftrace_enabled;
33d61f82d0SSteven Rostedt static int last_ftrace_enabled;
34b0fc494fSSteven Rostedt 
353d083395SSteven Rostedt static DEFINE_SPINLOCK(ftrace_lock);
36b0fc494fSSteven Rostedt static DEFINE_MUTEX(ftrace_sysctl_lock);
37b0fc494fSSteven Rostedt 
3816444a8aSArnaldo Carvalho de Melo static struct ftrace_ops ftrace_list_end __read_mostly =
3916444a8aSArnaldo Carvalho de Melo {
4016444a8aSArnaldo Carvalho de Melo 	.func = ftrace_stub,
4116444a8aSArnaldo Carvalho de Melo };
4216444a8aSArnaldo Carvalho de Melo 
4316444a8aSArnaldo Carvalho de Melo static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end;
4416444a8aSArnaldo Carvalho de Melo ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
4516444a8aSArnaldo Carvalho de Melo 
4616444a8aSArnaldo Carvalho de Melo /* mcount is defined per arch in assembly */
4716444a8aSArnaldo Carvalho de Melo EXPORT_SYMBOL(mcount);
4816444a8aSArnaldo Carvalho de Melo 
4916444a8aSArnaldo Carvalho de Melo notrace void ftrace_list_func(unsigned long ip, unsigned long parent_ip)
5016444a8aSArnaldo Carvalho de Melo {
5116444a8aSArnaldo Carvalho de Melo 	struct ftrace_ops *op = ftrace_list;
5216444a8aSArnaldo Carvalho de Melo 
5316444a8aSArnaldo Carvalho de Melo 	/* in case someone actually ports this to alpha! */
5416444a8aSArnaldo Carvalho de Melo 	read_barrier_depends();
5516444a8aSArnaldo Carvalho de Melo 
5616444a8aSArnaldo Carvalho de Melo 	while (op != &ftrace_list_end) {
5716444a8aSArnaldo Carvalho de Melo 		/* silly alpha */
5816444a8aSArnaldo Carvalho de Melo 		read_barrier_depends();
5916444a8aSArnaldo Carvalho de Melo 		op->func(ip, parent_ip);
6016444a8aSArnaldo Carvalho de Melo 		op = op->next;
6116444a8aSArnaldo Carvalho de Melo 	};
6216444a8aSArnaldo Carvalho de Melo }
6316444a8aSArnaldo Carvalho de Melo 
6416444a8aSArnaldo Carvalho de Melo /**
653d083395SSteven Rostedt  * clear_ftrace_function - reset the ftrace function
6616444a8aSArnaldo Carvalho de Melo  *
673d083395SSteven Rostedt  * This NULLs the ftrace function and in essence stops
683d083395SSteven Rostedt  * tracing.  There may be lag
6916444a8aSArnaldo Carvalho de Melo  */
703d083395SSteven Rostedt void clear_ftrace_function(void)
7116444a8aSArnaldo Carvalho de Melo {
723d083395SSteven Rostedt 	ftrace_trace_function = ftrace_stub;
733d083395SSteven Rostedt }
7416444a8aSArnaldo Carvalho de Melo 
753d083395SSteven Rostedt static int notrace __register_ftrace_function(struct ftrace_ops *ops)
763d083395SSteven Rostedt {
773d083395SSteven Rostedt 	/* Should never be called by interrupts */
783d083395SSteven Rostedt 	spin_lock(&ftrace_lock);
793d083395SSteven Rostedt 
8016444a8aSArnaldo Carvalho de Melo 	ops->next = ftrace_list;
8116444a8aSArnaldo Carvalho de Melo 	/*
8216444a8aSArnaldo Carvalho de Melo 	 * We are entering ops into the ftrace_list but another
8316444a8aSArnaldo Carvalho de Melo 	 * CPU might be walking that list. We need to make sure
8416444a8aSArnaldo Carvalho de Melo 	 * the ops->next pointer is valid before another CPU sees
8516444a8aSArnaldo Carvalho de Melo 	 * the ops pointer included into the ftrace_list.
8616444a8aSArnaldo Carvalho de Melo 	 */
8716444a8aSArnaldo Carvalho de Melo 	smp_wmb();
8816444a8aSArnaldo Carvalho de Melo 	ftrace_list = ops;
893d083395SSteven Rostedt 
90b0fc494fSSteven Rostedt 	if (ftrace_enabled) {
9116444a8aSArnaldo Carvalho de Melo 		/*
9216444a8aSArnaldo Carvalho de Melo 		 * For one func, simply call it directly.
9316444a8aSArnaldo Carvalho de Melo 		 * For more than one func, call the chain.
9416444a8aSArnaldo Carvalho de Melo 		 */
9516444a8aSArnaldo Carvalho de Melo 		if (ops->next == &ftrace_list_end)
9616444a8aSArnaldo Carvalho de Melo 			ftrace_trace_function = ops->func;
9716444a8aSArnaldo Carvalho de Melo 		else
9816444a8aSArnaldo Carvalho de Melo 			ftrace_trace_function = ftrace_list_func;
99b0fc494fSSteven Rostedt 	}
1003d083395SSteven Rostedt 
1013d083395SSteven Rostedt 	spin_unlock(&ftrace_lock);
10216444a8aSArnaldo Carvalho de Melo 
10316444a8aSArnaldo Carvalho de Melo 	return 0;
10416444a8aSArnaldo Carvalho de Melo }
10516444a8aSArnaldo Carvalho de Melo 
1063d083395SSteven Rostedt static int notrace __unregister_ftrace_function(struct ftrace_ops *ops)
10716444a8aSArnaldo Carvalho de Melo {
10816444a8aSArnaldo Carvalho de Melo 	struct ftrace_ops **p;
10916444a8aSArnaldo Carvalho de Melo 	int ret = 0;
11016444a8aSArnaldo Carvalho de Melo 
1113d083395SSteven Rostedt 	spin_lock(&ftrace_lock);
11216444a8aSArnaldo Carvalho de Melo 
11316444a8aSArnaldo Carvalho de Melo 	/*
1143d083395SSteven Rostedt 	 * If we are removing the last function, then simply point
1153d083395SSteven Rostedt 	 * to the ftrace_stub.
11616444a8aSArnaldo Carvalho de Melo 	 */
11716444a8aSArnaldo Carvalho de Melo 	if (ftrace_list == ops && ops->next == &ftrace_list_end) {
11816444a8aSArnaldo Carvalho de Melo 		ftrace_trace_function = ftrace_stub;
11916444a8aSArnaldo Carvalho de Melo 		ftrace_list = &ftrace_list_end;
12016444a8aSArnaldo Carvalho de Melo 		goto out;
12116444a8aSArnaldo Carvalho de Melo 	}
12216444a8aSArnaldo Carvalho de Melo 
12316444a8aSArnaldo Carvalho de Melo 	for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next)
12416444a8aSArnaldo Carvalho de Melo 		if (*p == ops)
12516444a8aSArnaldo Carvalho de Melo 			break;
12616444a8aSArnaldo Carvalho de Melo 
12716444a8aSArnaldo Carvalho de Melo 	if (*p != ops) {
12816444a8aSArnaldo Carvalho de Melo 		ret = -1;
12916444a8aSArnaldo Carvalho de Melo 		goto out;
13016444a8aSArnaldo Carvalho de Melo 	}
13116444a8aSArnaldo Carvalho de Melo 
13216444a8aSArnaldo Carvalho de Melo 	*p = (*p)->next;
13316444a8aSArnaldo Carvalho de Melo 
134b0fc494fSSteven Rostedt 	if (ftrace_enabled) {
13516444a8aSArnaldo Carvalho de Melo 		/* If we only have one func left, then call that directly */
1363d083395SSteven Rostedt 		if (ftrace_list == &ftrace_list_end ||
1373d083395SSteven Rostedt 		    ftrace_list->next == &ftrace_list_end)
13816444a8aSArnaldo Carvalho de Melo 			ftrace_trace_function = ftrace_list->func;
139b0fc494fSSteven Rostedt 	}
14016444a8aSArnaldo Carvalho de Melo 
14116444a8aSArnaldo Carvalho de Melo  out:
1423d083395SSteven Rostedt 	spin_unlock(&ftrace_lock);
1433d083395SSteven Rostedt 
1443d083395SSteven Rostedt 	return ret;
1453d083395SSteven Rostedt }
1463d083395SSteven Rostedt 
1473d083395SSteven Rostedt #ifdef CONFIG_DYNAMIC_FTRACE
1483d083395SSteven Rostedt 
149*e1c08bddSSteven Rostedt static struct task_struct *ftraced_task;
150*e1c08bddSSteven Rostedt static DECLARE_WAIT_QUEUE_HEAD(ftraced_waiters);
151*e1c08bddSSteven Rostedt static unsigned long ftraced_iteration_counter;
152*e1c08bddSSteven Rostedt 
153d61f82d0SSteven Rostedt enum {
154d61f82d0SSteven Rostedt 	FTRACE_ENABLE_CALLS		= (1 << 0),
155d61f82d0SSteven Rostedt 	FTRACE_DISABLE_CALLS		= (1 << 1),
156d61f82d0SSteven Rostedt 	FTRACE_UPDATE_TRACE_FUNC	= (1 << 2),
157d61f82d0SSteven Rostedt 	FTRACE_ENABLE_MCOUNT		= (1 << 3),
158d61f82d0SSteven Rostedt 	FTRACE_DISABLE_MCOUNT		= (1 << 4),
159d61f82d0SSteven Rostedt };
160d61f82d0SSteven Rostedt 
1615072c59fSSteven Rostedt static int ftrace_filtered;
1625072c59fSSteven Rostedt 
1633d083395SSteven Rostedt static struct hlist_head ftrace_hash[FTRACE_HASHSIZE];
1643d083395SSteven Rostedt 
1653d083395SSteven Rostedt static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu);
1663d083395SSteven Rostedt 
1673d083395SSteven Rostedt static DEFINE_SPINLOCK(ftrace_shutdown_lock);
1683d083395SSteven Rostedt static DEFINE_MUTEX(ftraced_lock);
1695072c59fSSteven Rostedt static DEFINE_MUTEX(ftrace_filter_lock);
1703d083395SSteven Rostedt 
1713c1720f0SSteven Rostedt struct ftrace_page {
1723c1720f0SSteven Rostedt 	struct ftrace_page	*next;
1733c1720f0SSteven Rostedt 	int			index;
1743c1720f0SSteven Rostedt 	struct dyn_ftrace	records[];
1753c1720f0SSteven Rostedt } __attribute__((packed));
1763c1720f0SSteven Rostedt 
1773c1720f0SSteven Rostedt #define ENTRIES_PER_PAGE \
1783c1720f0SSteven Rostedt   ((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct dyn_ftrace))
1793c1720f0SSteven Rostedt 
1803c1720f0SSteven Rostedt /* estimate from running different kernels */
1813c1720f0SSteven Rostedt #define NR_TO_INIT		10000
1823c1720f0SSteven Rostedt 
1833c1720f0SSteven Rostedt static struct ftrace_page	*ftrace_pages_start;
1843c1720f0SSteven Rostedt static struct ftrace_page	*ftrace_pages;
1853c1720f0SSteven Rostedt 
1863d083395SSteven Rostedt static int ftraced_trigger;
1873d083395SSteven Rostedt static int ftraced_suspend;
1883d083395SSteven Rostedt 
1893d083395SSteven Rostedt static int ftrace_record_suspend;
1903d083395SSteven Rostedt 
1913d083395SSteven Rostedt static inline int
1923d083395SSteven Rostedt notrace ftrace_ip_in_hash(unsigned long ip, unsigned long key)
1933d083395SSteven Rostedt {
1943d083395SSteven Rostedt 	struct dyn_ftrace *p;
1953d083395SSteven Rostedt 	struct hlist_node *t;
1963d083395SSteven Rostedt 	int found = 0;
1973d083395SSteven Rostedt 
1983d083395SSteven Rostedt 	hlist_for_each_entry(p, t, &ftrace_hash[key], node) {
1993d083395SSteven Rostedt 		if (p->ip == ip) {
2003d083395SSteven Rostedt 			found = 1;
2013d083395SSteven Rostedt 			break;
2023d083395SSteven Rostedt 		}
2033d083395SSteven Rostedt 	}
2043d083395SSteven Rostedt 
2053d083395SSteven Rostedt 	return found;
2063d083395SSteven Rostedt }
2073d083395SSteven Rostedt 
2083d083395SSteven Rostedt static inline void notrace
2093d083395SSteven Rostedt ftrace_add_hash(struct dyn_ftrace *node, unsigned long key)
2103d083395SSteven Rostedt {
2113d083395SSteven Rostedt 	hlist_add_head(&node->node, &ftrace_hash[key]);
2123d083395SSteven Rostedt }
2133d083395SSteven Rostedt 
214d61f82d0SSteven Rostedt static notrace struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
2153c1720f0SSteven Rostedt {
2163c1720f0SSteven Rostedt 	if (ftrace_pages->index == ENTRIES_PER_PAGE) {
2173c1720f0SSteven Rostedt 		if (!ftrace_pages->next)
2183c1720f0SSteven Rostedt 			return NULL;
2193c1720f0SSteven Rostedt 		ftrace_pages = ftrace_pages->next;
2203c1720f0SSteven Rostedt 	}
2213c1720f0SSteven Rostedt 
2223c1720f0SSteven Rostedt 	return &ftrace_pages->records[ftrace_pages->index++];
2233c1720f0SSteven Rostedt }
2243c1720f0SSteven Rostedt 
2253d083395SSteven Rostedt static void notrace
226d61f82d0SSteven Rostedt ftrace_record_ip(unsigned long ip)
2273d083395SSteven Rostedt {
2283d083395SSteven Rostedt 	struct dyn_ftrace *node;
2293d083395SSteven Rostedt 	unsigned long flags;
2303d083395SSteven Rostedt 	unsigned long key;
2313d083395SSteven Rostedt 	int resched;
2323d083395SSteven Rostedt 	int atomic;
2333d083395SSteven Rostedt 
234d61f82d0SSteven Rostedt 	if (!ftrace_enabled)
235d61f82d0SSteven Rostedt 		return;
236d61f82d0SSteven Rostedt 
2373d083395SSteven Rostedt 	resched = need_resched();
2383d083395SSteven Rostedt 	preempt_disable_notrace();
2393d083395SSteven Rostedt 
2403d083395SSteven Rostedt 	/* We simply need to protect against recursion */
2413d083395SSteven Rostedt 	__get_cpu_var(ftrace_shutdown_disable_cpu)++;
2423d083395SSteven Rostedt 	if (__get_cpu_var(ftrace_shutdown_disable_cpu) != 1)
2433d083395SSteven Rostedt 		goto out;
2443d083395SSteven Rostedt 
2453d083395SSteven Rostedt 	if (unlikely(ftrace_record_suspend))
2463d083395SSteven Rostedt 		goto out;
2473d083395SSteven Rostedt 
2483d083395SSteven Rostedt 	key = hash_long(ip, FTRACE_HASHBITS);
2493d083395SSteven Rostedt 
2503d083395SSteven Rostedt 	WARN_ON_ONCE(key >= FTRACE_HASHSIZE);
2513d083395SSteven Rostedt 
2523d083395SSteven Rostedt 	if (ftrace_ip_in_hash(ip, key))
2533d083395SSteven Rostedt 		goto out;
2543d083395SSteven Rostedt 
2553d083395SSteven Rostedt 	atomic = irqs_disabled();
2563d083395SSteven Rostedt 
2573d083395SSteven Rostedt 	spin_lock_irqsave(&ftrace_shutdown_lock, flags);
2583d083395SSteven Rostedt 
2593d083395SSteven Rostedt 	/* This ip may have hit the hash before the lock */
2603d083395SSteven Rostedt 	if (ftrace_ip_in_hash(ip, key))
2613d083395SSteven Rostedt 		goto out_unlock;
2623d083395SSteven Rostedt 
2633d083395SSteven Rostedt 	/*
2643d083395SSteven Rostedt 	 * There's a slight race that the ftraced will update the
265d61f82d0SSteven Rostedt 	 * hash and reset here. If it is already converted, skip it.
2663d083395SSteven Rostedt 	 */
267d61f82d0SSteven Rostedt 	if (ftrace_ip_converted(ip))
268d61f82d0SSteven Rostedt 		goto out_unlock;
269d61f82d0SSteven Rostedt 
270d61f82d0SSteven Rostedt 	node = ftrace_alloc_dyn_node(ip);
2713d083395SSteven Rostedt 	if (!node)
2723d083395SSteven Rostedt 		goto out_unlock;
2733d083395SSteven Rostedt 
2743d083395SSteven Rostedt 	node->ip = ip;
2753d083395SSteven Rostedt 
2763d083395SSteven Rostedt 	ftrace_add_hash(node, key);
2773d083395SSteven Rostedt 
2783d083395SSteven Rostedt 	ftraced_trigger = 1;
2793d083395SSteven Rostedt 
2803d083395SSteven Rostedt  out_unlock:
2813d083395SSteven Rostedt 	spin_unlock_irqrestore(&ftrace_shutdown_lock, flags);
2823d083395SSteven Rostedt  out:
2833d083395SSteven Rostedt 	__get_cpu_var(ftrace_shutdown_disable_cpu)--;
2843d083395SSteven Rostedt 
2853d083395SSteven Rostedt 	/* prevent recursion with scheduler */
2863d083395SSteven Rostedt 	if (resched)
2873d083395SSteven Rostedt 		preempt_enable_no_resched_notrace();
2883d083395SSteven Rostedt 	else
2893d083395SSteven Rostedt 		preempt_enable_notrace();
2903d083395SSteven Rostedt }
2913d083395SSteven Rostedt 
292d61f82d0SSteven Rostedt #define FTRACE_ADDR ((long)(&ftrace_caller))
2933c1720f0SSteven Rostedt #define MCOUNT_ADDR ((long)(&mcount))
2943c1720f0SSteven Rostedt 
2955072c59fSSteven Rostedt static void notrace
2965072c59fSSteven Rostedt __ftrace_replace_code(struct dyn_ftrace *rec,
2975072c59fSSteven Rostedt 		      unsigned char *old, unsigned char *new, int enable)
2985072c59fSSteven Rostedt {
2995072c59fSSteven Rostedt 	unsigned long ip;
3005072c59fSSteven Rostedt 	int failed;
3015072c59fSSteven Rostedt 
3025072c59fSSteven Rostedt 	ip = rec->ip;
3035072c59fSSteven Rostedt 
3045072c59fSSteven Rostedt 	if (ftrace_filtered && enable) {
3055072c59fSSteven Rostedt 		unsigned long fl;
3065072c59fSSteven Rostedt 		/*
3075072c59fSSteven Rostedt 		 * If filtering is on:
3085072c59fSSteven Rostedt 		 *
3095072c59fSSteven Rostedt 		 * If this record is set to be filtered and
3105072c59fSSteven Rostedt 		 * is enabled then do nothing.
3115072c59fSSteven Rostedt 		 *
3125072c59fSSteven Rostedt 		 * If this record is set to be filtered and
3135072c59fSSteven Rostedt 		 * it is not enabled, enable it.
3145072c59fSSteven Rostedt 		 *
3155072c59fSSteven Rostedt 		 * If this record is not set to be filtered
3165072c59fSSteven Rostedt 		 * and it is not enabled do nothing.
3175072c59fSSteven Rostedt 		 *
3185072c59fSSteven Rostedt 		 * If this record is not set to be filtered and
3195072c59fSSteven Rostedt 		 * it is enabled, disable it.
3205072c59fSSteven Rostedt 		 */
3215072c59fSSteven Rostedt 		fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED);
3225072c59fSSteven Rostedt 
3235072c59fSSteven Rostedt 		if ((fl ==  (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) ||
3245072c59fSSteven Rostedt 		    (fl == 0))
3255072c59fSSteven Rostedt 			return;
3265072c59fSSteven Rostedt 
3275072c59fSSteven Rostedt 		/*
3285072c59fSSteven Rostedt 		 * If it is enabled disable it,
3295072c59fSSteven Rostedt 		 * otherwise enable it!
3305072c59fSSteven Rostedt 		 */
3315072c59fSSteven Rostedt 		if (fl == FTRACE_FL_ENABLED) {
3325072c59fSSteven Rostedt 			/* swap new and old */
3335072c59fSSteven Rostedt 			new = old;
3345072c59fSSteven Rostedt 			old = ftrace_call_replace(ip, FTRACE_ADDR);
3355072c59fSSteven Rostedt 			rec->flags &= ~FTRACE_FL_ENABLED;
3365072c59fSSteven Rostedt 		} else {
3375072c59fSSteven Rostedt 			new = ftrace_call_replace(ip, FTRACE_ADDR);
3385072c59fSSteven Rostedt 			rec->flags |= FTRACE_FL_ENABLED;
3395072c59fSSteven Rostedt 		}
3405072c59fSSteven Rostedt 	} else {
3415072c59fSSteven Rostedt 
3425072c59fSSteven Rostedt 		if (enable)
3435072c59fSSteven Rostedt 			new = ftrace_call_replace(ip, FTRACE_ADDR);
3445072c59fSSteven Rostedt 		else
3455072c59fSSteven Rostedt 			old = ftrace_call_replace(ip, FTRACE_ADDR);
3465072c59fSSteven Rostedt 
3475072c59fSSteven Rostedt 		if (enable) {
3485072c59fSSteven Rostedt 			if (rec->flags & FTRACE_FL_ENABLED)
3495072c59fSSteven Rostedt 				return;
3505072c59fSSteven Rostedt 			rec->flags |= FTRACE_FL_ENABLED;
3515072c59fSSteven Rostedt 		} else {
3525072c59fSSteven Rostedt 			if (!(rec->flags & FTRACE_FL_ENABLED))
3535072c59fSSteven Rostedt 				return;
3545072c59fSSteven Rostedt 			rec->flags &= ~FTRACE_FL_ENABLED;
3555072c59fSSteven Rostedt 		}
3565072c59fSSteven Rostedt 	}
3575072c59fSSteven Rostedt 
3585072c59fSSteven Rostedt 	failed = ftrace_modify_code(ip, old, new);
3595072c59fSSteven Rostedt 	if (failed)
3605072c59fSSteven Rostedt 		rec->flags |= FTRACE_FL_FAILED;
3615072c59fSSteven Rostedt }
3625072c59fSSteven Rostedt 
3635072c59fSSteven Rostedt static void notrace ftrace_replace_code(int enable)
3643c1720f0SSteven Rostedt {
3653c1720f0SSteven Rostedt 	unsigned char *new = NULL, *old = NULL;
3663c1720f0SSteven Rostedt 	struct dyn_ftrace *rec;
3673c1720f0SSteven Rostedt 	struct ftrace_page *pg;
3683c1720f0SSteven Rostedt 	int i;
3693c1720f0SSteven Rostedt 
3705072c59fSSteven Rostedt 	if (enable)
3713c1720f0SSteven Rostedt 		old = ftrace_nop_replace();
3723c1720f0SSteven Rostedt 	else
3733c1720f0SSteven Rostedt 		new = ftrace_nop_replace();
3743c1720f0SSteven Rostedt 
3753c1720f0SSteven Rostedt 	for (pg = ftrace_pages_start; pg; pg = pg->next) {
3763c1720f0SSteven Rostedt 		for (i = 0; i < pg->index; i++) {
3773c1720f0SSteven Rostedt 			rec = &pg->records[i];
3783c1720f0SSteven Rostedt 
3793c1720f0SSteven Rostedt 			/* don't modify code that has already faulted */
3803c1720f0SSteven Rostedt 			if (rec->flags & FTRACE_FL_FAILED)
3813c1720f0SSteven Rostedt 				continue;
3823c1720f0SSteven Rostedt 
3835072c59fSSteven Rostedt 			__ftrace_replace_code(rec, old, new, enable);
3843c1720f0SSteven Rostedt 		}
3853c1720f0SSteven Rostedt 	}
3863c1720f0SSteven Rostedt }
3873c1720f0SSteven Rostedt 
3883c1720f0SSteven Rostedt static notrace void ftrace_shutdown_replenish(void)
3893c1720f0SSteven Rostedt {
3903c1720f0SSteven Rostedt 	if (ftrace_pages->next)
3913c1720f0SSteven Rostedt 		return;
3923c1720f0SSteven Rostedt 
3933c1720f0SSteven Rostedt 	/* allocate another page */
3943c1720f0SSteven Rostedt 	ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
3953c1720f0SSteven Rostedt }
3963d083395SSteven Rostedt 
3973c1720f0SSteven Rostedt static notrace void
398d61f82d0SSteven Rostedt ftrace_code_disable(struct dyn_ftrace *rec)
3993c1720f0SSteven Rostedt {
4003c1720f0SSteven Rostedt 	unsigned long ip;
4013c1720f0SSteven Rostedt 	unsigned char *nop, *call;
4023c1720f0SSteven Rostedt 	int failed;
4033c1720f0SSteven Rostedt 
4043c1720f0SSteven Rostedt 	ip = rec->ip;
4053c1720f0SSteven Rostedt 
4063c1720f0SSteven Rostedt 	nop = ftrace_nop_replace();
407d61f82d0SSteven Rostedt 	call = ftrace_call_replace(ip, MCOUNT_ADDR);
4083c1720f0SSteven Rostedt 
4093c1720f0SSteven Rostedt 	failed = ftrace_modify_code(ip, call, nop);
4103c1720f0SSteven Rostedt 	if (failed)
4113c1720f0SSteven Rostedt 		rec->flags |= FTRACE_FL_FAILED;
4123c1720f0SSteven Rostedt }
4133c1720f0SSteven Rostedt 
414d61f82d0SSteven Rostedt static int notrace __ftrace_modify_code(void *data)
4153d083395SSteven Rostedt {
416d61f82d0SSteven Rostedt 	unsigned long addr;
417d61f82d0SSteven Rostedt 	int *command = data;
418d61f82d0SSteven Rostedt 
419d61f82d0SSteven Rostedt 	if (*command & FTRACE_ENABLE_CALLS)
420d61f82d0SSteven Rostedt 		ftrace_replace_code(1);
421d61f82d0SSteven Rostedt 	else if (*command & FTRACE_DISABLE_CALLS)
422d61f82d0SSteven Rostedt 		ftrace_replace_code(0);
423d61f82d0SSteven Rostedt 
424d61f82d0SSteven Rostedt 	if (*command & FTRACE_UPDATE_TRACE_FUNC)
425d61f82d0SSteven Rostedt 		ftrace_update_ftrace_func(ftrace_trace_function);
426d61f82d0SSteven Rostedt 
427d61f82d0SSteven Rostedt 	if (*command & FTRACE_ENABLE_MCOUNT) {
428d61f82d0SSteven Rostedt 		addr = (unsigned long)ftrace_record_ip;
429d61f82d0SSteven Rostedt 		ftrace_mcount_set(&addr);
430d61f82d0SSteven Rostedt 	} else if (*command & FTRACE_DISABLE_MCOUNT) {
431d61f82d0SSteven Rostedt 		addr = (unsigned long)ftrace_stub;
432d61f82d0SSteven Rostedt 		ftrace_mcount_set(&addr);
4333d083395SSteven Rostedt 	}
4343d083395SSteven Rostedt 
435d61f82d0SSteven Rostedt 	return 0;
4363d083395SSteven Rostedt }
4373d083395SSteven Rostedt 
438d61f82d0SSteven Rostedt static void notrace ftrace_run_update_code(int command)
439d61f82d0SSteven Rostedt {
440d61f82d0SSteven Rostedt 	stop_machine_run(__ftrace_modify_code, &command, NR_CPUS);
441d61f82d0SSteven Rostedt }
442d61f82d0SSteven Rostedt 
443d61f82d0SSteven Rostedt static ftrace_func_t saved_ftrace_func;
444d61f82d0SSteven Rostedt 
4453d083395SSteven Rostedt static void notrace ftrace_startup(void)
4463d083395SSteven Rostedt {
447d61f82d0SSteven Rostedt 	int command = 0;
448d61f82d0SSteven Rostedt 
4493d083395SSteven Rostedt 	mutex_lock(&ftraced_lock);
4503d083395SSteven Rostedt 	ftraced_suspend++;
451d61f82d0SSteven Rostedt 	if (ftraced_suspend == 1)
452d61f82d0SSteven Rostedt 		command |= FTRACE_ENABLE_CALLS;
4533d083395SSteven Rostedt 
454d61f82d0SSteven Rostedt 	if (saved_ftrace_func != ftrace_trace_function) {
455d61f82d0SSteven Rostedt 		saved_ftrace_func = ftrace_trace_function;
456d61f82d0SSteven Rostedt 		command |= FTRACE_UPDATE_TRACE_FUNC;
457d61f82d0SSteven Rostedt 	}
458d61f82d0SSteven Rostedt 
459d61f82d0SSteven Rostedt 	if (!command || !ftrace_enabled)
460d61f82d0SSteven Rostedt 		goto out;
461d61f82d0SSteven Rostedt 
462d61f82d0SSteven Rostedt 	ftrace_run_update_code(command);
4633d083395SSteven Rostedt  out:
4643d083395SSteven Rostedt 	mutex_unlock(&ftraced_lock);
4653d083395SSteven Rostedt }
4663d083395SSteven Rostedt 
4673d083395SSteven Rostedt static void notrace ftrace_shutdown(void)
4683d083395SSteven Rostedt {
469d61f82d0SSteven Rostedt 	int command = 0;
470d61f82d0SSteven Rostedt 
4713d083395SSteven Rostedt 	mutex_lock(&ftraced_lock);
4723d083395SSteven Rostedt 	ftraced_suspend--;
473d61f82d0SSteven Rostedt 	if (!ftraced_suspend)
474d61f82d0SSteven Rostedt 		command |= FTRACE_DISABLE_CALLS;
475d61f82d0SSteven Rostedt 
476d61f82d0SSteven Rostedt 	if (saved_ftrace_func != ftrace_trace_function) {
477d61f82d0SSteven Rostedt 		saved_ftrace_func = ftrace_trace_function;
478d61f82d0SSteven Rostedt 		command |= FTRACE_UPDATE_TRACE_FUNC;
479d61f82d0SSteven Rostedt 	}
480d61f82d0SSteven Rostedt 
481d61f82d0SSteven Rostedt 	if (!command || !ftrace_enabled)
4823d083395SSteven Rostedt 		goto out;
4833d083395SSteven Rostedt 
484d61f82d0SSteven Rostedt 	ftrace_run_update_code(command);
4853d083395SSteven Rostedt  out:
4863d083395SSteven Rostedt 	mutex_unlock(&ftraced_lock);
4873d083395SSteven Rostedt }
4883d083395SSteven Rostedt 
489b0fc494fSSteven Rostedt static void notrace ftrace_startup_sysctl(void)
490b0fc494fSSteven Rostedt {
491d61f82d0SSteven Rostedt 	int command = FTRACE_ENABLE_MCOUNT;
492d61f82d0SSteven Rostedt 
493b0fc494fSSteven Rostedt 	mutex_lock(&ftraced_lock);
494d61f82d0SSteven Rostedt 	/* Force update next time */
495d61f82d0SSteven Rostedt 	saved_ftrace_func = NULL;
496b0fc494fSSteven Rostedt 	/* ftraced_suspend is true if we want ftrace running */
497b0fc494fSSteven Rostedt 	if (ftraced_suspend)
498d61f82d0SSteven Rostedt 		command |= FTRACE_ENABLE_CALLS;
499d61f82d0SSteven Rostedt 
500d61f82d0SSteven Rostedt 	ftrace_run_update_code(command);
501b0fc494fSSteven Rostedt 	mutex_unlock(&ftraced_lock);
502b0fc494fSSteven Rostedt }
503b0fc494fSSteven Rostedt 
504b0fc494fSSteven Rostedt static void notrace ftrace_shutdown_sysctl(void)
505b0fc494fSSteven Rostedt {
506d61f82d0SSteven Rostedt 	int command = FTRACE_DISABLE_MCOUNT;
507d61f82d0SSteven Rostedt 
508b0fc494fSSteven Rostedt 	mutex_lock(&ftraced_lock);
509b0fc494fSSteven Rostedt 	/* ftraced_suspend is true if ftrace is running */
510b0fc494fSSteven Rostedt 	if (ftraced_suspend)
511d61f82d0SSteven Rostedt 		command |= FTRACE_DISABLE_CALLS;
512d61f82d0SSteven Rostedt 
513d61f82d0SSteven Rostedt 	ftrace_run_update_code(command);
514b0fc494fSSteven Rostedt 	mutex_unlock(&ftraced_lock);
515b0fc494fSSteven Rostedt }
516b0fc494fSSteven Rostedt 
5173d083395SSteven Rostedt static cycle_t		ftrace_update_time;
5183d083395SSteven Rostedt static unsigned long	ftrace_update_cnt;
5193d083395SSteven Rostedt unsigned long		ftrace_update_tot_cnt;
5203d083395SSteven Rostedt 
5213d083395SSteven Rostedt static int notrace __ftrace_update_code(void *ignore)
5223d083395SSteven Rostedt {
5233d083395SSteven Rostedt 	struct dyn_ftrace *p;
5243d083395SSteven Rostedt 	struct hlist_head head;
5253d083395SSteven Rostedt 	struct hlist_node *t;
526d61f82d0SSteven Rostedt 	int save_ftrace_enabled;
5273d083395SSteven Rostedt 	cycle_t start, stop;
5283d083395SSteven Rostedt 	int i;
5293d083395SSteven Rostedt 
530d61f82d0SSteven Rostedt 	/* Don't be recording funcs now */
531d61f82d0SSteven Rostedt 	save_ftrace_enabled = ftrace_enabled;
532d61f82d0SSteven Rostedt 	ftrace_enabled = 0;
5333d083395SSteven Rostedt 
5343d083395SSteven Rostedt 	start = now(raw_smp_processor_id());
5353d083395SSteven Rostedt 	ftrace_update_cnt = 0;
5363d083395SSteven Rostedt 
5373d083395SSteven Rostedt 	/* No locks needed, the machine is stopped! */
5383d083395SSteven Rostedt 	for (i = 0; i < FTRACE_HASHSIZE; i++) {
5393d083395SSteven Rostedt 		if (hlist_empty(&ftrace_hash[i]))
5403d083395SSteven Rostedt 			continue;
5413d083395SSteven Rostedt 
5423d083395SSteven Rostedt 		head = ftrace_hash[i];
5433d083395SSteven Rostedt 		INIT_HLIST_HEAD(&ftrace_hash[i]);
5443d083395SSteven Rostedt 
5453d083395SSteven Rostedt 		/* all CPUS are stopped, we are safe to modify code */
5463d083395SSteven Rostedt 		hlist_for_each_entry(p, t, &head, node) {
547d61f82d0SSteven Rostedt 			ftrace_code_disable(p);
5483d083395SSteven Rostedt 			ftrace_update_cnt++;
5493d083395SSteven Rostedt 		}
5503d083395SSteven Rostedt 
5513d083395SSteven Rostedt 	}
5523d083395SSteven Rostedt 
5533d083395SSteven Rostedt 	stop = now(raw_smp_processor_id());
5543d083395SSteven Rostedt 	ftrace_update_time = stop - start;
5553d083395SSteven Rostedt 	ftrace_update_tot_cnt += ftrace_update_cnt;
5563d083395SSteven Rostedt 
557d61f82d0SSteven Rostedt 	ftrace_enabled = save_ftrace_enabled;
55816444a8aSArnaldo Carvalho de Melo 
55916444a8aSArnaldo Carvalho de Melo 	return 0;
56016444a8aSArnaldo Carvalho de Melo }
56116444a8aSArnaldo Carvalho de Melo 
5623d083395SSteven Rostedt static void notrace ftrace_update_code(void)
56316444a8aSArnaldo Carvalho de Melo {
5643d083395SSteven Rostedt 	stop_machine_run(__ftrace_update_code, NULL, NR_CPUS);
5653d083395SSteven Rostedt }
5663d083395SSteven Rostedt 
5673d083395SSteven Rostedt static int notrace ftraced(void *ignore)
5683d083395SSteven Rostedt {
5693d083395SSteven Rostedt 	unsigned long usecs;
5703d083395SSteven Rostedt 
5713d083395SSteven Rostedt 	set_current_state(TASK_INTERRUPTIBLE);
5723d083395SSteven Rostedt 
5733d083395SSteven Rostedt 	while (!kthread_should_stop()) {
5743d083395SSteven Rostedt 
5753d083395SSteven Rostedt 		/* check once a second */
5763d083395SSteven Rostedt 		schedule_timeout(HZ);
5773d083395SSteven Rostedt 
578b0fc494fSSteven Rostedt 		mutex_lock(&ftrace_sysctl_lock);
5793d083395SSteven Rostedt 		mutex_lock(&ftraced_lock);
580b0fc494fSSteven Rostedt 		if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) {
5813d083395SSteven Rostedt 			ftrace_record_suspend++;
5823d083395SSteven Rostedt 			ftrace_update_code();
5833d083395SSteven Rostedt 			usecs = nsecs_to_usecs(ftrace_update_time);
5843d083395SSteven Rostedt 			if (ftrace_update_tot_cnt > 100000) {
5853d083395SSteven Rostedt 				ftrace_update_tot_cnt = 0;
5863d083395SSteven Rostedt 				pr_info("hm, dftrace overflow: %lu change%s"
5873d083395SSteven Rostedt 					 " (%lu total) in %lu usec%s\n",
5883d083395SSteven Rostedt 					ftrace_update_cnt,
5893d083395SSteven Rostedt 					ftrace_update_cnt != 1 ? "s" : "",
5903d083395SSteven Rostedt 					ftrace_update_tot_cnt,
5913d083395SSteven Rostedt 					usecs, usecs != 1 ? "s" : "");
5923d083395SSteven Rostedt 				WARN_ON_ONCE(1);
5933d083395SSteven Rostedt 			}
5943d083395SSteven Rostedt 			ftraced_trigger = 0;
5953d083395SSteven Rostedt 			ftrace_record_suspend--;
5963d083395SSteven Rostedt 		}
597*e1c08bddSSteven Rostedt 		ftraced_iteration_counter++;
5983d083395SSteven Rostedt 		mutex_unlock(&ftraced_lock);
599b0fc494fSSteven Rostedt 		mutex_unlock(&ftrace_sysctl_lock);
6003d083395SSteven Rostedt 
601*e1c08bddSSteven Rostedt 		wake_up_interruptible(&ftraced_waiters);
602*e1c08bddSSteven Rostedt 
6033d083395SSteven Rostedt 		ftrace_shutdown_replenish();
6043d083395SSteven Rostedt 
6053d083395SSteven Rostedt 		set_current_state(TASK_INTERRUPTIBLE);
6063d083395SSteven Rostedt 	}
6073d083395SSteven Rostedt 	__set_current_state(TASK_RUNNING);
6083d083395SSteven Rostedt 	return 0;
6093d083395SSteven Rostedt }
6103d083395SSteven Rostedt 
6113c1720f0SSteven Rostedt static int __init ftrace_dyn_table_alloc(void)
6123c1720f0SSteven Rostedt {
6133c1720f0SSteven Rostedt 	struct ftrace_page *pg;
6143c1720f0SSteven Rostedt 	int cnt;
6153c1720f0SSteven Rostedt 	int i;
6163c1720f0SSteven Rostedt 
6173c1720f0SSteven Rostedt 	/* allocate a few pages */
6183c1720f0SSteven Rostedt 	ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
6193c1720f0SSteven Rostedt 	if (!ftrace_pages_start)
6203c1720f0SSteven Rostedt 		return -1;
6213c1720f0SSteven Rostedt 
6223c1720f0SSteven Rostedt 	/*
6233c1720f0SSteven Rostedt 	 * Allocate a few more pages.
6243c1720f0SSteven Rostedt 	 *
6253c1720f0SSteven Rostedt 	 * TODO: have some parser search vmlinux before
6263c1720f0SSteven Rostedt 	 *   final linking to find all calls to ftrace.
6273c1720f0SSteven Rostedt 	 *   Then we can:
6283c1720f0SSteven Rostedt 	 *    a) know how many pages to allocate.
6293c1720f0SSteven Rostedt 	 *     and/or
6303c1720f0SSteven Rostedt 	 *    b) set up the table then.
6313c1720f0SSteven Rostedt 	 *
6323c1720f0SSteven Rostedt 	 *  The dynamic code is still necessary for
6333c1720f0SSteven Rostedt 	 *  modules.
6343c1720f0SSteven Rostedt 	 */
6353c1720f0SSteven Rostedt 
6363c1720f0SSteven Rostedt 	pg = ftrace_pages = ftrace_pages_start;
6373c1720f0SSteven Rostedt 
6383c1720f0SSteven Rostedt 	cnt = NR_TO_INIT / ENTRIES_PER_PAGE;
6393c1720f0SSteven Rostedt 
6403c1720f0SSteven Rostedt 	for (i = 0; i < cnt; i++) {
6413c1720f0SSteven Rostedt 		pg->next = (void *)get_zeroed_page(GFP_KERNEL);
6423c1720f0SSteven Rostedt 
6433c1720f0SSteven Rostedt 		/* If we fail, we'll try later anyway */
6443c1720f0SSteven Rostedt 		if (!pg->next)
6453c1720f0SSteven Rostedt 			break;
6463c1720f0SSteven Rostedt 
6473c1720f0SSteven Rostedt 		pg = pg->next;
6483c1720f0SSteven Rostedt 	}
6493c1720f0SSteven Rostedt 
6503c1720f0SSteven Rostedt 	return 0;
6513c1720f0SSteven Rostedt }
6523c1720f0SSteven Rostedt 
6535072c59fSSteven Rostedt enum {
6545072c59fSSteven Rostedt 	FTRACE_ITER_FILTER	= (1 << 0),
6555072c59fSSteven Rostedt 	FTRACE_ITER_CONT	= (1 << 1),
6565072c59fSSteven Rostedt };
6575072c59fSSteven Rostedt 
6585072c59fSSteven Rostedt #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */
6595072c59fSSteven Rostedt 
6605072c59fSSteven Rostedt struct ftrace_iterator {
6615072c59fSSteven Rostedt 	loff_t			pos;
6625072c59fSSteven Rostedt 	struct ftrace_page	*pg;
6635072c59fSSteven Rostedt 	unsigned		idx;
6645072c59fSSteven Rostedt 	unsigned		flags;
6655072c59fSSteven Rostedt 	unsigned char		buffer[FTRACE_BUFF_MAX+1];
6665072c59fSSteven Rostedt 	unsigned		buffer_idx;
6675072c59fSSteven Rostedt 	unsigned		filtered;
6685072c59fSSteven Rostedt };
6695072c59fSSteven Rostedt 
6705072c59fSSteven Rostedt static void notrace *
6715072c59fSSteven Rostedt t_next(struct seq_file *m, void *v, loff_t *pos)
6725072c59fSSteven Rostedt {
6735072c59fSSteven Rostedt 	struct ftrace_iterator *iter = m->private;
6745072c59fSSteven Rostedt 	struct dyn_ftrace *rec = NULL;
6755072c59fSSteven Rostedt 
6765072c59fSSteven Rostedt 	(*pos)++;
6775072c59fSSteven Rostedt 
6785072c59fSSteven Rostedt  retry:
6795072c59fSSteven Rostedt 	if (iter->idx >= iter->pg->index) {
6805072c59fSSteven Rostedt 		if (iter->pg->next) {
6815072c59fSSteven Rostedt 			iter->pg = iter->pg->next;
6825072c59fSSteven Rostedt 			iter->idx = 0;
6835072c59fSSteven Rostedt 			goto retry;
6845072c59fSSteven Rostedt 		}
6855072c59fSSteven Rostedt 	} else {
6865072c59fSSteven Rostedt 		rec = &iter->pg->records[iter->idx++];
6875072c59fSSteven Rostedt 		if ((rec->flags & FTRACE_FL_FAILED) ||
6885072c59fSSteven Rostedt 		    ((iter->flags & FTRACE_ITER_FILTER) &&
6895072c59fSSteven Rostedt 		     !(rec->flags & FTRACE_FL_FILTER))) {
6905072c59fSSteven Rostedt 			rec = NULL;
6915072c59fSSteven Rostedt 			goto retry;
6925072c59fSSteven Rostedt 		}
6935072c59fSSteven Rostedt 	}
6945072c59fSSteven Rostedt 
6955072c59fSSteven Rostedt 	iter->pos = *pos;
6965072c59fSSteven Rostedt 
6975072c59fSSteven Rostedt 	return rec;
6985072c59fSSteven Rostedt }
6995072c59fSSteven Rostedt 
7005072c59fSSteven Rostedt static void *t_start(struct seq_file *m, loff_t *pos)
7015072c59fSSteven Rostedt {
7025072c59fSSteven Rostedt 	struct ftrace_iterator *iter = m->private;
7035072c59fSSteven Rostedt 	void *p = NULL;
7045072c59fSSteven Rostedt 	loff_t l = -1;
7055072c59fSSteven Rostedt 
7065072c59fSSteven Rostedt 	if (*pos != iter->pos) {
7075072c59fSSteven Rostedt 		for (p = t_next(m, p, &l); p && l < *pos; p = t_next(m, p, &l))
7085072c59fSSteven Rostedt 			;
7095072c59fSSteven Rostedt 	} else {
7105072c59fSSteven Rostedt 		l = *pos;
7115072c59fSSteven Rostedt 		p = t_next(m, p, &l);
7125072c59fSSteven Rostedt 	}
7135072c59fSSteven Rostedt 
7145072c59fSSteven Rostedt 	return p;
7155072c59fSSteven Rostedt }
7165072c59fSSteven Rostedt 
7175072c59fSSteven Rostedt static void t_stop(struct seq_file *m, void *p)
7185072c59fSSteven Rostedt {
7195072c59fSSteven Rostedt }
7205072c59fSSteven Rostedt 
7215072c59fSSteven Rostedt static int t_show(struct seq_file *m, void *v)
7225072c59fSSteven Rostedt {
7235072c59fSSteven Rostedt 	struct dyn_ftrace *rec = v;
7245072c59fSSteven Rostedt 	char str[KSYM_SYMBOL_LEN];
7255072c59fSSteven Rostedt 
7265072c59fSSteven Rostedt 	if (!rec)
7275072c59fSSteven Rostedt 		return 0;
7285072c59fSSteven Rostedt 
7295072c59fSSteven Rostedt 	kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
7305072c59fSSteven Rostedt 
7315072c59fSSteven Rostedt 	seq_printf(m, "%s\n", str);
7325072c59fSSteven Rostedt 
7335072c59fSSteven Rostedt 	return 0;
7345072c59fSSteven Rostedt }
7355072c59fSSteven Rostedt 
7365072c59fSSteven Rostedt static struct seq_operations show_ftrace_seq_ops = {
7375072c59fSSteven Rostedt 	.start = t_start,
7385072c59fSSteven Rostedt 	.next = t_next,
7395072c59fSSteven Rostedt 	.stop = t_stop,
7405072c59fSSteven Rostedt 	.show = t_show,
7415072c59fSSteven Rostedt };
7425072c59fSSteven Rostedt 
7435072c59fSSteven Rostedt static int notrace
7445072c59fSSteven Rostedt ftrace_avail_open(struct inode *inode, struct file *file)
7455072c59fSSteven Rostedt {
7465072c59fSSteven Rostedt 	struct ftrace_iterator *iter;
7475072c59fSSteven Rostedt 	int ret;
7485072c59fSSteven Rostedt 
7495072c59fSSteven Rostedt 	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
7505072c59fSSteven Rostedt 	if (!iter)
7515072c59fSSteven Rostedt 		return -ENOMEM;
7525072c59fSSteven Rostedt 
7535072c59fSSteven Rostedt 	iter->pg = ftrace_pages_start;
7545072c59fSSteven Rostedt 	iter->pos = -1;
7555072c59fSSteven Rostedt 
7565072c59fSSteven Rostedt 	ret = seq_open(file, &show_ftrace_seq_ops);
7575072c59fSSteven Rostedt 	if (!ret) {
7585072c59fSSteven Rostedt 		struct seq_file *m = file->private_data;
7595072c59fSSteven Rostedt 		m->private = iter;
7605072c59fSSteven Rostedt 	} else
7615072c59fSSteven Rostedt 		kfree(iter);
7625072c59fSSteven Rostedt 
7635072c59fSSteven Rostedt 	return ret;
7645072c59fSSteven Rostedt }
7655072c59fSSteven Rostedt 
7665072c59fSSteven Rostedt int ftrace_avail_release(struct inode *inode, struct file *file)
7675072c59fSSteven Rostedt {
7685072c59fSSteven Rostedt 	struct seq_file *m = (struct seq_file *)file->private_data;
7695072c59fSSteven Rostedt 	struct ftrace_iterator *iter = m->private;
7705072c59fSSteven Rostedt 
7715072c59fSSteven Rostedt 	seq_release(inode, file);
7725072c59fSSteven Rostedt 	kfree(iter);
7735072c59fSSteven Rostedt 	return 0;
7745072c59fSSteven Rostedt }
7755072c59fSSteven Rostedt 
7765072c59fSSteven Rostedt static void notrace ftrace_filter_reset(void)
7775072c59fSSteven Rostedt {
7785072c59fSSteven Rostedt 	struct ftrace_page *pg;
7795072c59fSSteven Rostedt 	struct dyn_ftrace *rec;
7805072c59fSSteven Rostedt 	unsigned i;
7815072c59fSSteven Rostedt 
7825072c59fSSteven Rostedt 	/* keep kstop machine from running */
7835072c59fSSteven Rostedt 	preempt_disable();
7845072c59fSSteven Rostedt 	ftrace_filtered = 0;
7855072c59fSSteven Rostedt 	pg = ftrace_pages_start;
7865072c59fSSteven Rostedt 	while (pg) {
7875072c59fSSteven Rostedt 		for (i = 0; i < pg->index; i++) {
7885072c59fSSteven Rostedt 			rec = &pg->records[i];
7895072c59fSSteven Rostedt 			if (rec->flags & FTRACE_FL_FAILED)
7905072c59fSSteven Rostedt 				continue;
7915072c59fSSteven Rostedt 			rec->flags &= ~FTRACE_FL_FILTER;
7925072c59fSSteven Rostedt 		}
7935072c59fSSteven Rostedt 		pg = pg->next;
7945072c59fSSteven Rostedt 	}
7955072c59fSSteven Rostedt 	preempt_enable();
7965072c59fSSteven Rostedt }
7975072c59fSSteven Rostedt 
7985072c59fSSteven Rostedt static int notrace
7995072c59fSSteven Rostedt ftrace_filter_open(struct inode *inode, struct file *file)
8005072c59fSSteven Rostedt {
8015072c59fSSteven Rostedt 	struct ftrace_iterator *iter;
8025072c59fSSteven Rostedt 	int ret = 0;
8035072c59fSSteven Rostedt 
8045072c59fSSteven Rostedt 	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
8055072c59fSSteven Rostedt 	if (!iter)
8065072c59fSSteven Rostedt 		return -ENOMEM;
8075072c59fSSteven Rostedt 
8085072c59fSSteven Rostedt 	mutex_lock(&ftrace_filter_lock);
8095072c59fSSteven Rostedt 	if ((file->f_mode & FMODE_WRITE) &&
8105072c59fSSteven Rostedt 	    !(file->f_flags & O_APPEND))
8115072c59fSSteven Rostedt 		ftrace_filter_reset();
8125072c59fSSteven Rostedt 
8135072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ) {
8145072c59fSSteven Rostedt 		iter->pg = ftrace_pages_start;
8155072c59fSSteven Rostedt 		iter->pos = -1;
8165072c59fSSteven Rostedt 		iter->flags = FTRACE_ITER_FILTER;
8175072c59fSSteven Rostedt 
8185072c59fSSteven Rostedt 		ret = seq_open(file, &show_ftrace_seq_ops);
8195072c59fSSteven Rostedt 		if (!ret) {
8205072c59fSSteven Rostedt 			struct seq_file *m = file->private_data;
8215072c59fSSteven Rostedt 			m->private = iter;
8225072c59fSSteven Rostedt 		} else
8235072c59fSSteven Rostedt 			kfree(iter);
8245072c59fSSteven Rostedt 	} else
8255072c59fSSteven Rostedt 		file->private_data = iter;
8265072c59fSSteven Rostedt 	mutex_unlock(&ftrace_filter_lock);
8275072c59fSSteven Rostedt 
8285072c59fSSteven Rostedt 	return ret;
8295072c59fSSteven Rostedt }
8305072c59fSSteven Rostedt 
8315072c59fSSteven Rostedt static ssize_t notrace
8325072c59fSSteven Rostedt ftrace_filter_read(struct file *file, char __user *ubuf,
8335072c59fSSteven Rostedt 		       size_t cnt, loff_t *ppos)
8345072c59fSSteven Rostedt {
8355072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ)
8365072c59fSSteven Rostedt 		return seq_read(file, ubuf, cnt, ppos);
8375072c59fSSteven Rostedt 	else
8385072c59fSSteven Rostedt 		return -EPERM;
8395072c59fSSteven Rostedt }
8405072c59fSSteven Rostedt 
8415072c59fSSteven Rostedt static loff_t notrace
8425072c59fSSteven Rostedt ftrace_filter_lseek(struct file *file, loff_t offset, int origin)
8435072c59fSSteven Rostedt {
8445072c59fSSteven Rostedt 	loff_t ret;
8455072c59fSSteven Rostedt 
8465072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ)
8475072c59fSSteven Rostedt 		ret = seq_lseek(file, offset, origin);
8485072c59fSSteven Rostedt 	else
8495072c59fSSteven Rostedt 		file->f_pos = ret = 1;
8505072c59fSSteven Rostedt 
8515072c59fSSteven Rostedt 	return ret;
8525072c59fSSteven Rostedt }
8535072c59fSSteven Rostedt 
8545072c59fSSteven Rostedt enum {
8555072c59fSSteven Rostedt 	MATCH_FULL,
8565072c59fSSteven Rostedt 	MATCH_FRONT_ONLY,
8575072c59fSSteven Rostedt 	MATCH_MIDDLE_ONLY,
8585072c59fSSteven Rostedt 	MATCH_END_ONLY,
8595072c59fSSteven Rostedt };
8605072c59fSSteven Rostedt 
8615072c59fSSteven Rostedt static void notrace
8625072c59fSSteven Rostedt ftrace_match(unsigned char *buff, int len)
8635072c59fSSteven Rostedt {
8645072c59fSSteven Rostedt 	char str[KSYM_SYMBOL_LEN];
8655072c59fSSteven Rostedt 	char *search = NULL;
8665072c59fSSteven Rostedt 	struct ftrace_page *pg;
8675072c59fSSteven Rostedt 	struct dyn_ftrace *rec;
8685072c59fSSteven Rostedt 	int type = MATCH_FULL;
8695072c59fSSteven Rostedt 	unsigned i, match = 0, search_len = 0;
8705072c59fSSteven Rostedt 
8715072c59fSSteven Rostedt 	for (i = 0; i < len; i++) {
8725072c59fSSteven Rostedt 		if (buff[i] == '*') {
8735072c59fSSteven Rostedt 			if (!i) {
8745072c59fSSteven Rostedt 				search = buff + i + 1;
8755072c59fSSteven Rostedt 				type = MATCH_END_ONLY;
8765072c59fSSteven Rostedt 				search_len = len - (i + 1);
8775072c59fSSteven Rostedt 			} else {
8785072c59fSSteven Rostedt 				if (type == MATCH_END_ONLY) {
8795072c59fSSteven Rostedt 					type = MATCH_MIDDLE_ONLY;
8805072c59fSSteven Rostedt 				} else {
8815072c59fSSteven Rostedt 					match = i;
8825072c59fSSteven Rostedt 					type = MATCH_FRONT_ONLY;
8835072c59fSSteven Rostedt 				}
8845072c59fSSteven Rostedt 				buff[i] = 0;
8855072c59fSSteven Rostedt 				break;
8865072c59fSSteven Rostedt 			}
8875072c59fSSteven Rostedt 		}
8885072c59fSSteven Rostedt 	}
8895072c59fSSteven Rostedt 
8905072c59fSSteven Rostedt 	/* keep kstop machine from running */
8915072c59fSSteven Rostedt 	preempt_disable();
8925072c59fSSteven Rostedt 	ftrace_filtered = 1;
8935072c59fSSteven Rostedt 	pg = ftrace_pages_start;
8945072c59fSSteven Rostedt 	while (pg) {
8955072c59fSSteven Rostedt 		for (i = 0; i < pg->index; i++) {
8965072c59fSSteven Rostedt 			int matched = 0;
8975072c59fSSteven Rostedt 			char *ptr;
8985072c59fSSteven Rostedt 
8995072c59fSSteven Rostedt 			rec = &pg->records[i];
9005072c59fSSteven Rostedt 			if (rec->flags & FTRACE_FL_FAILED)
9015072c59fSSteven Rostedt 				continue;
9025072c59fSSteven Rostedt 			kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
9035072c59fSSteven Rostedt 			switch (type) {
9045072c59fSSteven Rostedt 			case MATCH_FULL:
9055072c59fSSteven Rostedt 				if (strcmp(str, buff) == 0)
9065072c59fSSteven Rostedt 					matched = 1;
9075072c59fSSteven Rostedt 				break;
9085072c59fSSteven Rostedt 			case MATCH_FRONT_ONLY:
9095072c59fSSteven Rostedt 				if (memcmp(str, buff, match) == 0)
9105072c59fSSteven Rostedt 					matched = 1;
9115072c59fSSteven Rostedt 				break;
9125072c59fSSteven Rostedt 			case MATCH_MIDDLE_ONLY:
9135072c59fSSteven Rostedt 				if (strstr(str, search))
9145072c59fSSteven Rostedt 					matched = 1;
9155072c59fSSteven Rostedt 				break;
9165072c59fSSteven Rostedt 			case MATCH_END_ONLY:
9175072c59fSSteven Rostedt 				ptr = strstr(str, search);
9185072c59fSSteven Rostedt 				if (ptr && (ptr[search_len] == 0))
9195072c59fSSteven Rostedt 					matched = 1;
9205072c59fSSteven Rostedt 				break;
9215072c59fSSteven Rostedt 			}
9225072c59fSSteven Rostedt 			if (matched)
9235072c59fSSteven Rostedt 				rec->flags |= FTRACE_FL_FILTER;
9245072c59fSSteven Rostedt 		}
9255072c59fSSteven Rostedt 		pg = pg->next;
9265072c59fSSteven Rostedt 	}
9275072c59fSSteven Rostedt 	preempt_enable();
9285072c59fSSteven Rostedt }
9295072c59fSSteven Rostedt 
9305072c59fSSteven Rostedt static ssize_t notrace
9315072c59fSSteven Rostedt ftrace_filter_write(struct file *file, const char __user *ubuf,
9325072c59fSSteven Rostedt 		    size_t cnt, loff_t *ppos)
9335072c59fSSteven Rostedt {
9345072c59fSSteven Rostedt 	struct ftrace_iterator *iter;
9355072c59fSSteven Rostedt 	char ch;
9365072c59fSSteven Rostedt 	size_t read = 0;
9375072c59fSSteven Rostedt 	ssize_t ret;
9385072c59fSSteven Rostedt 
9395072c59fSSteven Rostedt 	if (!cnt || cnt < 0)
9405072c59fSSteven Rostedt 		return 0;
9415072c59fSSteven Rostedt 
9425072c59fSSteven Rostedt 	mutex_lock(&ftrace_filter_lock);
9435072c59fSSteven Rostedt 
9445072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ) {
9455072c59fSSteven Rostedt 		struct seq_file *m = file->private_data;
9465072c59fSSteven Rostedt 		iter = m->private;
9475072c59fSSteven Rostedt 	} else
9485072c59fSSteven Rostedt 		iter = file->private_data;
9495072c59fSSteven Rostedt 
9505072c59fSSteven Rostedt 	if (!*ppos) {
9515072c59fSSteven Rostedt 		iter->flags &= ~FTRACE_ITER_CONT;
9525072c59fSSteven Rostedt 		iter->buffer_idx = 0;
9535072c59fSSteven Rostedt 	}
9545072c59fSSteven Rostedt 
9555072c59fSSteven Rostedt 	ret = get_user(ch, ubuf++);
9565072c59fSSteven Rostedt 	if (ret)
9575072c59fSSteven Rostedt 		goto out;
9585072c59fSSteven Rostedt 	read++;
9595072c59fSSteven Rostedt 	cnt--;
9605072c59fSSteven Rostedt 
9615072c59fSSteven Rostedt 	if (!(iter->flags & ~FTRACE_ITER_CONT)) {
9625072c59fSSteven Rostedt 		/* skip white space */
9635072c59fSSteven Rostedt 		while (cnt && isspace(ch)) {
9645072c59fSSteven Rostedt 			ret = get_user(ch, ubuf++);
9655072c59fSSteven Rostedt 			if (ret)
9665072c59fSSteven Rostedt 				goto out;
9675072c59fSSteven Rostedt 			read++;
9685072c59fSSteven Rostedt 			cnt--;
9695072c59fSSteven Rostedt 		}
9705072c59fSSteven Rostedt 
9715072c59fSSteven Rostedt 
9725072c59fSSteven Rostedt 		if (isspace(ch)) {
9735072c59fSSteven Rostedt 			file->f_pos += read;
9745072c59fSSteven Rostedt 			ret = read;
9755072c59fSSteven Rostedt 			goto out;
9765072c59fSSteven Rostedt 		}
9775072c59fSSteven Rostedt 
9785072c59fSSteven Rostedt 		iter->buffer_idx = 0;
9795072c59fSSteven Rostedt 	}
9805072c59fSSteven Rostedt 
9815072c59fSSteven Rostedt 	while (cnt && !isspace(ch)) {
9825072c59fSSteven Rostedt 		if (iter->buffer_idx < FTRACE_BUFF_MAX)
9835072c59fSSteven Rostedt 			iter->buffer[iter->buffer_idx++] = ch;
9845072c59fSSteven Rostedt 		else {
9855072c59fSSteven Rostedt 			ret = -EINVAL;
9865072c59fSSteven Rostedt 			goto out;
9875072c59fSSteven Rostedt 		}
9885072c59fSSteven Rostedt 		ret = get_user(ch, ubuf++);
9895072c59fSSteven Rostedt 		if (ret)
9905072c59fSSteven Rostedt 			goto out;
9915072c59fSSteven Rostedt 		read++;
9925072c59fSSteven Rostedt 		cnt--;
9935072c59fSSteven Rostedt 	}
9945072c59fSSteven Rostedt 
9955072c59fSSteven Rostedt 	if (isspace(ch)) {
9965072c59fSSteven Rostedt 		iter->filtered++;
9975072c59fSSteven Rostedt 		iter->buffer[iter->buffer_idx] = 0;
9985072c59fSSteven Rostedt 		ftrace_match(iter->buffer, iter->buffer_idx);
9995072c59fSSteven Rostedt 		iter->buffer_idx = 0;
10005072c59fSSteven Rostedt 	} else
10015072c59fSSteven Rostedt 		iter->flags |= FTRACE_ITER_CONT;
10025072c59fSSteven Rostedt 
10035072c59fSSteven Rostedt 
10045072c59fSSteven Rostedt 	file->f_pos += read;
10055072c59fSSteven Rostedt 
10065072c59fSSteven Rostedt 	ret = read;
10075072c59fSSteven Rostedt  out:
10085072c59fSSteven Rostedt 	mutex_unlock(&ftrace_filter_lock);
10095072c59fSSteven Rostedt 
10105072c59fSSteven Rostedt 	return ret;
10115072c59fSSteven Rostedt }
10125072c59fSSteven Rostedt 
10135072c59fSSteven Rostedt static int notrace
10145072c59fSSteven Rostedt ftrace_filter_release(struct inode *inode, struct file *file)
10155072c59fSSteven Rostedt {
10165072c59fSSteven Rostedt 	struct seq_file *m = (struct seq_file *)file->private_data;
10175072c59fSSteven Rostedt 	struct ftrace_iterator *iter;
10185072c59fSSteven Rostedt 
10195072c59fSSteven Rostedt 	mutex_lock(&ftrace_filter_lock);
10205072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ) {
10215072c59fSSteven Rostedt 		iter = m->private;
10225072c59fSSteven Rostedt 
10235072c59fSSteven Rostedt 		seq_release(inode, file);
10245072c59fSSteven Rostedt 	} else
10255072c59fSSteven Rostedt 		iter = file->private_data;
10265072c59fSSteven Rostedt 
10275072c59fSSteven Rostedt 	if (iter->buffer_idx) {
10285072c59fSSteven Rostedt 		iter->filtered++;
10295072c59fSSteven Rostedt 		iter->buffer[iter->buffer_idx] = 0;
10305072c59fSSteven Rostedt 		ftrace_match(iter->buffer, iter->buffer_idx);
10315072c59fSSteven Rostedt 	}
10325072c59fSSteven Rostedt 
10335072c59fSSteven Rostedt 	mutex_lock(&ftrace_sysctl_lock);
10345072c59fSSteven Rostedt 	mutex_lock(&ftraced_lock);
10355072c59fSSteven Rostedt 	if (iter->filtered && ftraced_suspend && ftrace_enabled)
10365072c59fSSteven Rostedt 		ftrace_run_update_code(FTRACE_ENABLE_CALLS);
10375072c59fSSteven Rostedt 	mutex_unlock(&ftraced_lock);
10385072c59fSSteven Rostedt 	mutex_unlock(&ftrace_sysctl_lock);
10395072c59fSSteven Rostedt 
10405072c59fSSteven Rostedt 	kfree(iter);
10415072c59fSSteven Rostedt 	mutex_unlock(&ftrace_filter_lock);
10425072c59fSSteven Rostedt 	return 0;
10435072c59fSSteven Rostedt }
10445072c59fSSteven Rostedt 
10455072c59fSSteven Rostedt static struct file_operations ftrace_avail_fops = {
10465072c59fSSteven Rostedt 	.open = ftrace_avail_open,
10475072c59fSSteven Rostedt 	.read = seq_read,
10485072c59fSSteven Rostedt 	.llseek = seq_lseek,
10495072c59fSSteven Rostedt 	.release = ftrace_avail_release,
10505072c59fSSteven Rostedt };
10515072c59fSSteven Rostedt 
10525072c59fSSteven Rostedt static struct file_operations ftrace_filter_fops = {
10535072c59fSSteven Rostedt 	.open = ftrace_filter_open,
10545072c59fSSteven Rostedt 	.read = ftrace_filter_read,
10555072c59fSSteven Rostedt 	.write = ftrace_filter_write,
10565072c59fSSteven Rostedt 	.llseek = ftrace_filter_lseek,
10575072c59fSSteven Rostedt 	.release = ftrace_filter_release,
10585072c59fSSteven Rostedt };
10595072c59fSSteven Rostedt 
1060*e1c08bddSSteven Rostedt /**
1061*e1c08bddSSteven Rostedt  * ftrace_force_update - force an update to all recording ftrace functions
1062*e1c08bddSSteven Rostedt  *
1063*e1c08bddSSteven Rostedt  * The ftrace dynamic update daemon only wakes up once a second.
1064*e1c08bddSSteven Rostedt  * There may be cases where an update needs to be done immediately
1065*e1c08bddSSteven Rostedt  * for tests or internal kernel tracing to begin. This function
1066*e1c08bddSSteven Rostedt  * wakes the daemon to do an update and will not return until the
1067*e1c08bddSSteven Rostedt  * update is complete.
1068*e1c08bddSSteven Rostedt  */
1069*e1c08bddSSteven Rostedt int ftrace_force_update(void)
1070*e1c08bddSSteven Rostedt {
1071*e1c08bddSSteven Rostedt 	unsigned long last_counter;
1072*e1c08bddSSteven Rostedt 	DECLARE_WAITQUEUE(wait, current);
1073*e1c08bddSSteven Rostedt 	int ret = 0;
1074*e1c08bddSSteven Rostedt 
1075*e1c08bddSSteven Rostedt 	if (!ftraced_task)
1076*e1c08bddSSteven Rostedt 		return -ENODEV;
1077*e1c08bddSSteven Rostedt 
1078*e1c08bddSSteven Rostedt 	mutex_lock(&ftraced_lock);
1079*e1c08bddSSteven Rostedt 	last_counter = ftraced_iteration_counter;
1080*e1c08bddSSteven Rostedt 
1081*e1c08bddSSteven Rostedt 	set_current_state(TASK_INTERRUPTIBLE);
1082*e1c08bddSSteven Rostedt 	add_wait_queue(&ftraced_waiters, &wait);
1083*e1c08bddSSteven Rostedt 
1084*e1c08bddSSteven Rostedt 	do {
1085*e1c08bddSSteven Rostedt 		mutex_unlock(&ftraced_lock);
1086*e1c08bddSSteven Rostedt 		wake_up_process(ftraced_task);
1087*e1c08bddSSteven Rostedt 		schedule();
1088*e1c08bddSSteven Rostedt 		mutex_lock(&ftraced_lock);
1089*e1c08bddSSteven Rostedt 		if (signal_pending(current)) {
1090*e1c08bddSSteven Rostedt 			ret = -EINTR;
1091*e1c08bddSSteven Rostedt 			break;
1092*e1c08bddSSteven Rostedt 		}
1093*e1c08bddSSteven Rostedt 		set_current_state(TASK_INTERRUPTIBLE);
1094*e1c08bddSSteven Rostedt 	} while (last_counter == ftraced_iteration_counter);
1095*e1c08bddSSteven Rostedt 
1096*e1c08bddSSteven Rostedt 	mutex_unlock(&ftraced_lock);
1097*e1c08bddSSteven Rostedt 	remove_wait_queue(&ftraced_waiters, &wait);
1098*e1c08bddSSteven Rostedt 	set_current_state(TASK_RUNNING);
1099*e1c08bddSSteven Rostedt 
1100*e1c08bddSSteven Rostedt 	return ret;
1101*e1c08bddSSteven Rostedt }
1102*e1c08bddSSteven Rostedt 
11035072c59fSSteven Rostedt static __init int ftrace_init_debugfs(void)
11045072c59fSSteven Rostedt {
11055072c59fSSteven Rostedt 	struct dentry *d_tracer;
11065072c59fSSteven Rostedt 	struct dentry *entry;
11075072c59fSSteven Rostedt 
11085072c59fSSteven Rostedt 	d_tracer = tracing_init_dentry();
11095072c59fSSteven Rostedt 
11105072c59fSSteven Rostedt 	entry = debugfs_create_file("available_filter_functions", 0444,
11115072c59fSSteven Rostedt 				    d_tracer, NULL, &ftrace_avail_fops);
11125072c59fSSteven Rostedt 	if (!entry)
11135072c59fSSteven Rostedt 		pr_warning("Could not create debugfs "
11145072c59fSSteven Rostedt 			   "'available_filter_functions' entry\n");
11155072c59fSSteven Rostedt 
11165072c59fSSteven Rostedt 	entry = debugfs_create_file("set_ftrace_filter", 0644, d_tracer,
11175072c59fSSteven Rostedt 				    NULL, &ftrace_filter_fops);
11185072c59fSSteven Rostedt 	if (!entry)
11195072c59fSSteven Rostedt 		pr_warning("Could not create debugfs "
11205072c59fSSteven Rostedt 			   "'set_ftrace_filter' entry\n");
11215072c59fSSteven Rostedt 	return 0;
11225072c59fSSteven Rostedt }
11235072c59fSSteven Rostedt 
11245072c59fSSteven Rostedt fs_initcall(ftrace_init_debugfs);
11255072c59fSSteven Rostedt 
1126d61f82d0SSteven Rostedt static int __init notrace ftrace_dynamic_init(void)
11273d083395SSteven Rostedt {
11283d083395SSteven Rostedt 	struct task_struct *p;
1129d61f82d0SSteven Rostedt 	unsigned long addr;
11303d083395SSteven Rostedt 	int ret;
11313d083395SSteven Rostedt 
1132d61f82d0SSteven Rostedt 	addr = (unsigned long)ftrace_record_ip;
1133d61f82d0SSteven Rostedt 	stop_machine_run(ftrace_dyn_arch_init, &addr, NR_CPUS);
1134d61f82d0SSteven Rostedt 
1135d61f82d0SSteven Rostedt 	/* ftrace_dyn_arch_init places the return code in addr */
1136d61f82d0SSteven Rostedt 	if (addr)
1137d61f82d0SSteven Rostedt 		return addr;
1138d61f82d0SSteven Rostedt 
11393c1720f0SSteven Rostedt 	ret = ftrace_dyn_table_alloc();
11403d083395SSteven Rostedt 	if (ret)
11413d083395SSteven Rostedt 		return ret;
11423d083395SSteven Rostedt 
11433d083395SSteven Rostedt 	p = kthread_run(ftraced, NULL, "ftraced");
11443d083395SSteven Rostedt 	if (IS_ERR(p))
11453d083395SSteven Rostedt 		return -1;
11463d083395SSteven Rostedt 
1147d61f82d0SSteven Rostedt 	last_ftrace_enabled = ftrace_enabled = 1;
1148*e1c08bddSSteven Rostedt 	ftraced_task = p;
11493d083395SSteven Rostedt 
11503d083395SSteven Rostedt 	return 0;
11513d083395SSteven Rostedt }
11523d083395SSteven Rostedt 
1153d61f82d0SSteven Rostedt core_initcall(ftrace_dynamic_init);
11543d083395SSteven Rostedt #else
11553d083395SSteven Rostedt # define ftrace_startup()	  do { } while (0)
11563d083395SSteven Rostedt # define ftrace_shutdown()	  do { } while (0)
1157b0fc494fSSteven Rostedt # define ftrace_startup_sysctl()  do { } while (0)
1158b0fc494fSSteven Rostedt # define ftrace_shutdown_sysctl() do { } while (0)
11593d083395SSteven Rostedt #endif /* CONFIG_DYNAMIC_FTRACE */
11603d083395SSteven Rostedt 
11613d083395SSteven Rostedt /**
11623d083395SSteven Rostedt  * register_ftrace_function - register a function for profiling
11633d083395SSteven Rostedt  * @ops - ops structure that holds the function for profiling.
11643d083395SSteven Rostedt  *
11653d083395SSteven Rostedt  * Register a function to be called by all functions in the
11663d083395SSteven Rostedt  * kernel.
11673d083395SSteven Rostedt  *
11683d083395SSteven Rostedt  * Note: @ops->func and all the functions it calls must be labeled
11693d083395SSteven Rostedt  *       with "notrace", otherwise it will go into a
11703d083395SSteven Rostedt  *       recursive loop.
11713d083395SSteven Rostedt  */
11723d083395SSteven Rostedt int register_ftrace_function(struct ftrace_ops *ops)
11733d083395SSteven Rostedt {
1174b0fc494fSSteven Rostedt 	int ret;
1175b0fc494fSSteven Rostedt 
1176b0fc494fSSteven Rostedt 	mutex_lock(&ftrace_sysctl_lock);
1177b0fc494fSSteven Rostedt 	ret = __register_ftrace_function(ops);
1178d61f82d0SSteven Rostedt 	ftrace_startup();
1179b0fc494fSSteven Rostedt 	mutex_unlock(&ftrace_sysctl_lock);
1180b0fc494fSSteven Rostedt 
1181b0fc494fSSteven Rostedt 	return ret;
11823d083395SSteven Rostedt }
11833d083395SSteven Rostedt 
11843d083395SSteven Rostedt /**
11853d083395SSteven Rostedt  * unregister_ftrace_function - unresgister a function for profiling.
11863d083395SSteven Rostedt  * @ops - ops structure that holds the function to unregister
11873d083395SSteven Rostedt  *
11883d083395SSteven Rostedt  * Unregister a function that was added to be called by ftrace profiling.
11893d083395SSteven Rostedt  */
11903d083395SSteven Rostedt int unregister_ftrace_function(struct ftrace_ops *ops)
11913d083395SSteven Rostedt {
11923d083395SSteven Rostedt 	int ret;
11933d083395SSteven Rostedt 
1194b0fc494fSSteven Rostedt 	mutex_lock(&ftrace_sysctl_lock);
11953d083395SSteven Rostedt 	ret = __unregister_ftrace_function(ops);
11963d083395SSteven Rostedt 	ftrace_shutdown();
1197b0fc494fSSteven Rostedt 	mutex_unlock(&ftrace_sysctl_lock);
1198b0fc494fSSteven Rostedt 
1199b0fc494fSSteven Rostedt 	return ret;
1200b0fc494fSSteven Rostedt }
1201b0fc494fSSteven Rostedt 
1202b0fc494fSSteven Rostedt notrace int
1203b0fc494fSSteven Rostedt ftrace_enable_sysctl(struct ctl_table *table, int write,
12045072c59fSSteven Rostedt 		     struct file *file, void __user *buffer, size_t *lenp,
1205b0fc494fSSteven Rostedt 		     loff_t *ppos)
1206b0fc494fSSteven Rostedt {
1207b0fc494fSSteven Rostedt 	int ret;
1208b0fc494fSSteven Rostedt 
1209b0fc494fSSteven Rostedt 	mutex_lock(&ftrace_sysctl_lock);
1210b0fc494fSSteven Rostedt 
12115072c59fSSteven Rostedt 	ret  = proc_dointvec(table, write, file, buffer, lenp, ppos);
1212b0fc494fSSteven Rostedt 
1213b0fc494fSSteven Rostedt 	if (ret || !write || (last_ftrace_enabled == ftrace_enabled))
1214b0fc494fSSteven Rostedt 		goto out;
1215b0fc494fSSteven Rostedt 
1216b0fc494fSSteven Rostedt 	last_ftrace_enabled = ftrace_enabled;
1217b0fc494fSSteven Rostedt 
1218b0fc494fSSteven Rostedt 	if (ftrace_enabled) {
1219b0fc494fSSteven Rostedt 
1220b0fc494fSSteven Rostedt 		ftrace_startup_sysctl();
1221b0fc494fSSteven Rostedt 
1222b0fc494fSSteven Rostedt 		/* we are starting ftrace again */
1223b0fc494fSSteven Rostedt 		if (ftrace_list != &ftrace_list_end) {
1224b0fc494fSSteven Rostedt 			if (ftrace_list->next == &ftrace_list_end)
1225b0fc494fSSteven Rostedt 				ftrace_trace_function = ftrace_list->func;
1226b0fc494fSSteven Rostedt 			else
1227b0fc494fSSteven Rostedt 				ftrace_trace_function = ftrace_list_func;
1228b0fc494fSSteven Rostedt 		}
1229b0fc494fSSteven Rostedt 
1230b0fc494fSSteven Rostedt 	} else {
1231b0fc494fSSteven Rostedt 		/* stopping ftrace calls (just send to ftrace_stub) */
1232b0fc494fSSteven Rostedt 		ftrace_trace_function = ftrace_stub;
1233b0fc494fSSteven Rostedt 
1234b0fc494fSSteven Rostedt 		ftrace_shutdown_sysctl();
1235b0fc494fSSteven Rostedt 	}
1236b0fc494fSSteven Rostedt 
1237b0fc494fSSteven Rostedt  out:
1238b0fc494fSSteven Rostedt 	mutex_unlock(&ftrace_sysctl_lock);
12393d083395SSteven Rostedt 	return ret;
124016444a8aSArnaldo Carvalho de Melo }
1241