xref: /linux-6.15/kernel/trace/ftrace.c (revision 5072c59f)
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>
19*5072c59fSSteven Rostedt #include <linux/seq_file.h>
20*5072c59fSSteven 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>
24*5072c59fSSteven Rostedt #include <linux/uaccess.h>
25b0fc494fSSteven Rostedt #include <linux/sysctl.h>
263d083395SSteven Rostedt #include <linux/hash.h>
27*5072c59fSSteven 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 
149d61f82d0SSteven Rostedt enum {
150d61f82d0SSteven Rostedt 	FTRACE_ENABLE_CALLS		= (1 << 0),
151d61f82d0SSteven Rostedt 	FTRACE_DISABLE_CALLS		= (1 << 1),
152d61f82d0SSteven Rostedt 	FTRACE_UPDATE_TRACE_FUNC	= (1 << 2),
153d61f82d0SSteven Rostedt 	FTRACE_ENABLE_MCOUNT		= (1 << 3),
154d61f82d0SSteven Rostedt 	FTRACE_DISABLE_MCOUNT		= (1 << 4),
155d61f82d0SSteven Rostedt };
156d61f82d0SSteven Rostedt 
157*5072c59fSSteven Rostedt static int ftrace_filtered;
158*5072c59fSSteven Rostedt 
1593d083395SSteven Rostedt static struct hlist_head ftrace_hash[FTRACE_HASHSIZE];
1603d083395SSteven Rostedt 
1613d083395SSteven Rostedt static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu);
1623d083395SSteven Rostedt 
1633d083395SSteven Rostedt static DEFINE_SPINLOCK(ftrace_shutdown_lock);
1643d083395SSteven Rostedt static DEFINE_MUTEX(ftraced_lock);
165*5072c59fSSteven Rostedt static DEFINE_MUTEX(ftrace_filter_lock);
1663d083395SSteven Rostedt 
1673c1720f0SSteven Rostedt struct ftrace_page {
1683c1720f0SSteven Rostedt 	struct ftrace_page	*next;
1693c1720f0SSteven Rostedt 	int			index;
1703c1720f0SSteven Rostedt 	struct dyn_ftrace	records[];
1713c1720f0SSteven Rostedt } __attribute__((packed));
1723c1720f0SSteven Rostedt 
1733c1720f0SSteven Rostedt #define ENTRIES_PER_PAGE \
1743c1720f0SSteven Rostedt   ((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct dyn_ftrace))
1753c1720f0SSteven Rostedt 
1763c1720f0SSteven Rostedt /* estimate from running different kernels */
1773c1720f0SSteven Rostedt #define NR_TO_INIT		10000
1783c1720f0SSteven Rostedt 
1793c1720f0SSteven Rostedt static struct ftrace_page	*ftrace_pages_start;
1803c1720f0SSteven Rostedt static struct ftrace_page	*ftrace_pages;
1813c1720f0SSteven Rostedt 
1823d083395SSteven Rostedt static int ftraced_trigger;
1833d083395SSteven Rostedt static int ftraced_suspend;
1843d083395SSteven Rostedt 
1853d083395SSteven Rostedt static int ftrace_record_suspend;
1863d083395SSteven Rostedt 
1873d083395SSteven Rostedt static inline int
1883d083395SSteven Rostedt notrace ftrace_ip_in_hash(unsigned long ip, unsigned long key)
1893d083395SSteven Rostedt {
1903d083395SSteven Rostedt 	struct dyn_ftrace *p;
1913d083395SSteven Rostedt 	struct hlist_node *t;
1923d083395SSteven Rostedt 	int found = 0;
1933d083395SSteven Rostedt 
1943d083395SSteven Rostedt 	hlist_for_each_entry(p, t, &ftrace_hash[key], node) {
1953d083395SSteven Rostedt 		if (p->ip == ip) {
1963d083395SSteven Rostedt 			found = 1;
1973d083395SSteven Rostedt 			break;
1983d083395SSteven Rostedt 		}
1993d083395SSteven Rostedt 	}
2003d083395SSteven Rostedt 
2013d083395SSteven Rostedt 	return found;
2023d083395SSteven Rostedt }
2033d083395SSteven Rostedt 
2043d083395SSteven Rostedt static inline void notrace
2053d083395SSteven Rostedt ftrace_add_hash(struct dyn_ftrace *node, unsigned long key)
2063d083395SSteven Rostedt {
2073d083395SSteven Rostedt 	hlist_add_head(&node->node, &ftrace_hash[key]);
2083d083395SSteven Rostedt }
2093d083395SSteven Rostedt 
210d61f82d0SSteven Rostedt static notrace struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
2113c1720f0SSteven Rostedt {
2123c1720f0SSteven Rostedt 	if (ftrace_pages->index == ENTRIES_PER_PAGE) {
2133c1720f0SSteven Rostedt 		if (!ftrace_pages->next)
2143c1720f0SSteven Rostedt 			return NULL;
2153c1720f0SSteven Rostedt 		ftrace_pages = ftrace_pages->next;
2163c1720f0SSteven Rostedt 	}
2173c1720f0SSteven Rostedt 
2183c1720f0SSteven Rostedt 	return &ftrace_pages->records[ftrace_pages->index++];
2193c1720f0SSteven Rostedt }
2203c1720f0SSteven Rostedt 
2213d083395SSteven Rostedt static void notrace
222d61f82d0SSteven Rostedt ftrace_record_ip(unsigned long ip)
2233d083395SSteven Rostedt {
2243d083395SSteven Rostedt 	struct dyn_ftrace *node;
2253d083395SSteven Rostedt 	unsigned long flags;
2263d083395SSteven Rostedt 	unsigned long key;
2273d083395SSteven Rostedt 	int resched;
2283d083395SSteven Rostedt 	int atomic;
2293d083395SSteven Rostedt 
230d61f82d0SSteven Rostedt 	if (!ftrace_enabled)
231d61f82d0SSteven Rostedt 		return;
232d61f82d0SSteven Rostedt 
2333d083395SSteven Rostedt 	resched = need_resched();
2343d083395SSteven Rostedt 	preempt_disable_notrace();
2353d083395SSteven Rostedt 
2363d083395SSteven Rostedt 	/* We simply need to protect against recursion */
2373d083395SSteven Rostedt 	__get_cpu_var(ftrace_shutdown_disable_cpu)++;
2383d083395SSteven Rostedt 	if (__get_cpu_var(ftrace_shutdown_disable_cpu) != 1)
2393d083395SSteven Rostedt 		goto out;
2403d083395SSteven Rostedt 
2413d083395SSteven Rostedt 	if (unlikely(ftrace_record_suspend))
2423d083395SSteven Rostedt 		goto out;
2433d083395SSteven Rostedt 
2443d083395SSteven Rostedt 	key = hash_long(ip, FTRACE_HASHBITS);
2453d083395SSteven Rostedt 
2463d083395SSteven Rostedt 	WARN_ON_ONCE(key >= FTRACE_HASHSIZE);
2473d083395SSteven Rostedt 
2483d083395SSteven Rostedt 	if (ftrace_ip_in_hash(ip, key))
2493d083395SSteven Rostedt 		goto out;
2503d083395SSteven Rostedt 
2513d083395SSteven Rostedt 	atomic = irqs_disabled();
2523d083395SSteven Rostedt 
2533d083395SSteven Rostedt 	spin_lock_irqsave(&ftrace_shutdown_lock, flags);
2543d083395SSteven Rostedt 
2553d083395SSteven Rostedt 	/* This ip may have hit the hash before the lock */
2563d083395SSteven Rostedt 	if (ftrace_ip_in_hash(ip, key))
2573d083395SSteven Rostedt 		goto out_unlock;
2583d083395SSteven Rostedt 
2593d083395SSteven Rostedt 	/*
2603d083395SSteven Rostedt 	 * There's a slight race that the ftraced will update the
261d61f82d0SSteven Rostedt 	 * hash and reset here. If it is already converted, skip it.
2623d083395SSteven Rostedt 	 */
263d61f82d0SSteven Rostedt 	if (ftrace_ip_converted(ip))
264d61f82d0SSteven Rostedt 		goto out_unlock;
265d61f82d0SSteven Rostedt 
266d61f82d0SSteven Rostedt 	node = ftrace_alloc_dyn_node(ip);
2673d083395SSteven Rostedt 	if (!node)
2683d083395SSteven Rostedt 		goto out_unlock;
2693d083395SSteven Rostedt 
2703d083395SSteven Rostedt 	node->ip = ip;
2713d083395SSteven Rostedt 
2723d083395SSteven Rostedt 	ftrace_add_hash(node, key);
2733d083395SSteven Rostedt 
2743d083395SSteven Rostedt 	ftraced_trigger = 1;
2753d083395SSteven Rostedt 
2763d083395SSteven Rostedt  out_unlock:
2773d083395SSteven Rostedt 	spin_unlock_irqrestore(&ftrace_shutdown_lock, flags);
2783d083395SSteven Rostedt  out:
2793d083395SSteven Rostedt 	__get_cpu_var(ftrace_shutdown_disable_cpu)--;
2803d083395SSteven Rostedt 
2813d083395SSteven Rostedt 	/* prevent recursion with scheduler */
2823d083395SSteven Rostedt 	if (resched)
2833d083395SSteven Rostedt 		preempt_enable_no_resched_notrace();
2843d083395SSteven Rostedt 	else
2853d083395SSteven Rostedt 		preempt_enable_notrace();
2863d083395SSteven Rostedt }
2873d083395SSteven Rostedt 
288d61f82d0SSteven Rostedt #define FTRACE_ADDR ((long)(&ftrace_caller))
2893c1720f0SSteven Rostedt #define MCOUNT_ADDR ((long)(&mcount))
2903c1720f0SSteven Rostedt 
291*5072c59fSSteven Rostedt static void notrace
292*5072c59fSSteven Rostedt __ftrace_replace_code(struct dyn_ftrace *rec,
293*5072c59fSSteven Rostedt 		      unsigned char *old, unsigned char *new, int enable)
294*5072c59fSSteven Rostedt {
295*5072c59fSSteven Rostedt 	unsigned long ip;
296*5072c59fSSteven Rostedt 	int failed;
297*5072c59fSSteven Rostedt 
298*5072c59fSSteven Rostedt 	ip = rec->ip;
299*5072c59fSSteven Rostedt 
300*5072c59fSSteven Rostedt 	if (ftrace_filtered && enable) {
301*5072c59fSSteven Rostedt 		unsigned long fl;
302*5072c59fSSteven Rostedt 		/*
303*5072c59fSSteven Rostedt 		 * If filtering is on:
304*5072c59fSSteven Rostedt 		 *
305*5072c59fSSteven Rostedt 		 * If this record is set to be filtered and
306*5072c59fSSteven Rostedt 		 * is enabled then do nothing.
307*5072c59fSSteven Rostedt 		 *
308*5072c59fSSteven Rostedt 		 * If this record is set to be filtered and
309*5072c59fSSteven Rostedt 		 * it is not enabled, enable it.
310*5072c59fSSteven Rostedt 		 *
311*5072c59fSSteven Rostedt 		 * If this record is not set to be filtered
312*5072c59fSSteven Rostedt 		 * and it is not enabled do nothing.
313*5072c59fSSteven Rostedt 		 *
314*5072c59fSSteven Rostedt 		 * If this record is not set to be filtered and
315*5072c59fSSteven Rostedt 		 * it is enabled, disable it.
316*5072c59fSSteven Rostedt 		 */
317*5072c59fSSteven Rostedt 		fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED);
318*5072c59fSSteven Rostedt 
319*5072c59fSSteven Rostedt 		if ((fl ==  (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) ||
320*5072c59fSSteven Rostedt 		    (fl == 0))
321*5072c59fSSteven Rostedt 			return;
322*5072c59fSSteven Rostedt 
323*5072c59fSSteven Rostedt 		/*
324*5072c59fSSteven Rostedt 		 * If it is enabled disable it,
325*5072c59fSSteven Rostedt 		 * otherwise enable it!
326*5072c59fSSteven Rostedt 		 */
327*5072c59fSSteven Rostedt 		if (fl == FTRACE_FL_ENABLED) {
328*5072c59fSSteven Rostedt 			/* swap new and old */
329*5072c59fSSteven Rostedt 			new = old;
330*5072c59fSSteven Rostedt 			old = ftrace_call_replace(ip, FTRACE_ADDR);
331*5072c59fSSteven Rostedt 			rec->flags &= ~FTRACE_FL_ENABLED;
332*5072c59fSSteven Rostedt 		} else {
333*5072c59fSSteven Rostedt 			new = ftrace_call_replace(ip, FTRACE_ADDR);
334*5072c59fSSteven Rostedt 			rec->flags |= FTRACE_FL_ENABLED;
335*5072c59fSSteven Rostedt 		}
336*5072c59fSSteven Rostedt 	} else {
337*5072c59fSSteven Rostedt 
338*5072c59fSSteven Rostedt 		if (enable)
339*5072c59fSSteven Rostedt 			new = ftrace_call_replace(ip, FTRACE_ADDR);
340*5072c59fSSteven Rostedt 		else
341*5072c59fSSteven Rostedt 			old = ftrace_call_replace(ip, FTRACE_ADDR);
342*5072c59fSSteven Rostedt 
343*5072c59fSSteven Rostedt 		if (enable) {
344*5072c59fSSteven Rostedt 			if (rec->flags & FTRACE_FL_ENABLED)
345*5072c59fSSteven Rostedt 				return;
346*5072c59fSSteven Rostedt 			rec->flags |= FTRACE_FL_ENABLED;
347*5072c59fSSteven Rostedt 		} else {
348*5072c59fSSteven Rostedt 			if (!(rec->flags & FTRACE_FL_ENABLED))
349*5072c59fSSteven Rostedt 				return;
350*5072c59fSSteven Rostedt 			rec->flags &= ~FTRACE_FL_ENABLED;
351*5072c59fSSteven Rostedt 		}
352*5072c59fSSteven Rostedt 	}
353*5072c59fSSteven Rostedt 
354*5072c59fSSteven Rostedt 	failed = ftrace_modify_code(ip, old, new);
355*5072c59fSSteven Rostedt 	if (failed)
356*5072c59fSSteven Rostedt 		rec->flags |= FTRACE_FL_FAILED;
357*5072c59fSSteven Rostedt }
358*5072c59fSSteven Rostedt 
359*5072c59fSSteven Rostedt static void notrace ftrace_replace_code(int enable)
3603c1720f0SSteven Rostedt {
3613c1720f0SSteven Rostedt 	unsigned char *new = NULL, *old = NULL;
3623c1720f0SSteven Rostedt 	struct dyn_ftrace *rec;
3633c1720f0SSteven Rostedt 	struct ftrace_page *pg;
3643c1720f0SSteven Rostedt 	int i;
3653c1720f0SSteven Rostedt 
366*5072c59fSSteven Rostedt 	if (enable)
3673c1720f0SSteven Rostedt 		old = ftrace_nop_replace();
3683c1720f0SSteven Rostedt 	else
3693c1720f0SSteven Rostedt 		new = ftrace_nop_replace();
3703c1720f0SSteven Rostedt 
3713c1720f0SSteven Rostedt 	for (pg = ftrace_pages_start; pg; pg = pg->next) {
3723c1720f0SSteven Rostedt 		for (i = 0; i < pg->index; i++) {
3733c1720f0SSteven Rostedt 			rec = &pg->records[i];
3743c1720f0SSteven Rostedt 
3753c1720f0SSteven Rostedt 			/* don't modify code that has already faulted */
3763c1720f0SSteven Rostedt 			if (rec->flags & FTRACE_FL_FAILED)
3773c1720f0SSteven Rostedt 				continue;
3783c1720f0SSteven Rostedt 
379*5072c59fSSteven Rostedt 			__ftrace_replace_code(rec, old, new, enable);
3803c1720f0SSteven Rostedt 		}
3813c1720f0SSteven Rostedt 	}
3823c1720f0SSteven Rostedt }
3833c1720f0SSteven Rostedt 
3843c1720f0SSteven Rostedt static notrace void ftrace_shutdown_replenish(void)
3853c1720f0SSteven Rostedt {
3863c1720f0SSteven Rostedt 	if (ftrace_pages->next)
3873c1720f0SSteven Rostedt 		return;
3883c1720f0SSteven Rostedt 
3893c1720f0SSteven Rostedt 	/* allocate another page */
3903c1720f0SSteven Rostedt 	ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
3913c1720f0SSteven Rostedt }
3923d083395SSteven Rostedt 
3933c1720f0SSteven Rostedt static notrace void
394d61f82d0SSteven Rostedt ftrace_code_disable(struct dyn_ftrace *rec)
3953c1720f0SSteven Rostedt {
3963c1720f0SSteven Rostedt 	unsigned long ip;
3973c1720f0SSteven Rostedt 	unsigned char *nop, *call;
3983c1720f0SSteven Rostedt 	int failed;
3993c1720f0SSteven Rostedt 
4003c1720f0SSteven Rostedt 	ip = rec->ip;
4013c1720f0SSteven Rostedt 
4023c1720f0SSteven Rostedt 	nop = ftrace_nop_replace();
403d61f82d0SSteven Rostedt 	call = ftrace_call_replace(ip, MCOUNT_ADDR);
4043c1720f0SSteven Rostedt 
4053c1720f0SSteven Rostedt 	failed = ftrace_modify_code(ip, call, nop);
4063c1720f0SSteven Rostedt 	if (failed)
4073c1720f0SSteven Rostedt 		rec->flags |= FTRACE_FL_FAILED;
4083c1720f0SSteven Rostedt }
4093c1720f0SSteven Rostedt 
410d61f82d0SSteven Rostedt static int notrace __ftrace_modify_code(void *data)
4113d083395SSteven Rostedt {
412d61f82d0SSteven Rostedt 	unsigned long addr;
413d61f82d0SSteven Rostedt 	int *command = data;
414d61f82d0SSteven Rostedt 
415d61f82d0SSteven Rostedt 	if (*command & FTRACE_ENABLE_CALLS)
416d61f82d0SSteven Rostedt 		ftrace_replace_code(1);
417d61f82d0SSteven Rostedt 	else if (*command & FTRACE_DISABLE_CALLS)
418d61f82d0SSteven Rostedt 		ftrace_replace_code(0);
419d61f82d0SSteven Rostedt 
420d61f82d0SSteven Rostedt 	if (*command & FTRACE_UPDATE_TRACE_FUNC)
421d61f82d0SSteven Rostedt 		ftrace_update_ftrace_func(ftrace_trace_function);
422d61f82d0SSteven Rostedt 
423d61f82d0SSteven Rostedt 	if (*command & FTRACE_ENABLE_MCOUNT) {
424d61f82d0SSteven Rostedt 		addr = (unsigned long)ftrace_record_ip;
425d61f82d0SSteven Rostedt 		ftrace_mcount_set(&addr);
426d61f82d0SSteven Rostedt 	} else if (*command & FTRACE_DISABLE_MCOUNT) {
427d61f82d0SSteven Rostedt 		addr = (unsigned long)ftrace_stub;
428d61f82d0SSteven Rostedt 		ftrace_mcount_set(&addr);
4293d083395SSteven Rostedt 	}
4303d083395SSteven Rostedt 
431d61f82d0SSteven Rostedt 	return 0;
4323d083395SSteven Rostedt }
4333d083395SSteven Rostedt 
434d61f82d0SSteven Rostedt static void notrace ftrace_run_update_code(int command)
435d61f82d0SSteven Rostedt {
436d61f82d0SSteven Rostedt 	stop_machine_run(__ftrace_modify_code, &command, NR_CPUS);
437d61f82d0SSteven Rostedt }
438d61f82d0SSteven Rostedt 
439d61f82d0SSteven Rostedt static ftrace_func_t saved_ftrace_func;
440d61f82d0SSteven Rostedt 
4413d083395SSteven Rostedt static void notrace ftrace_startup(void)
4423d083395SSteven Rostedt {
443d61f82d0SSteven Rostedt 	int command = 0;
444d61f82d0SSteven Rostedt 
4453d083395SSteven Rostedt 	mutex_lock(&ftraced_lock);
4463d083395SSteven Rostedt 	ftraced_suspend++;
447d61f82d0SSteven Rostedt 	if (ftraced_suspend == 1)
448d61f82d0SSteven Rostedt 		command |= FTRACE_ENABLE_CALLS;
4493d083395SSteven Rostedt 
450d61f82d0SSteven Rostedt 	if (saved_ftrace_func != ftrace_trace_function) {
451d61f82d0SSteven Rostedt 		saved_ftrace_func = ftrace_trace_function;
452d61f82d0SSteven Rostedt 		command |= FTRACE_UPDATE_TRACE_FUNC;
453d61f82d0SSteven Rostedt 	}
454d61f82d0SSteven Rostedt 
455d61f82d0SSteven Rostedt 	if (!command || !ftrace_enabled)
456d61f82d0SSteven Rostedt 		goto out;
457d61f82d0SSteven Rostedt 
458d61f82d0SSteven Rostedt 	ftrace_run_update_code(command);
4593d083395SSteven Rostedt  out:
4603d083395SSteven Rostedt 	mutex_unlock(&ftraced_lock);
4613d083395SSteven Rostedt }
4623d083395SSteven Rostedt 
4633d083395SSteven Rostedt static void notrace ftrace_shutdown(void)
4643d083395SSteven Rostedt {
465d61f82d0SSteven Rostedt 	int command = 0;
466d61f82d0SSteven Rostedt 
4673d083395SSteven Rostedt 	mutex_lock(&ftraced_lock);
4683d083395SSteven Rostedt 	ftraced_suspend--;
469d61f82d0SSteven Rostedt 	if (!ftraced_suspend)
470d61f82d0SSteven Rostedt 		command |= FTRACE_DISABLE_CALLS;
471d61f82d0SSteven Rostedt 
472d61f82d0SSteven Rostedt 	if (saved_ftrace_func != ftrace_trace_function) {
473d61f82d0SSteven Rostedt 		saved_ftrace_func = ftrace_trace_function;
474d61f82d0SSteven Rostedt 		command |= FTRACE_UPDATE_TRACE_FUNC;
475d61f82d0SSteven Rostedt 	}
476d61f82d0SSteven Rostedt 
477d61f82d0SSteven Rostedt 	if (!command || !ftrace_enabled)
4783d083395SSteven Rostedt 		goto out;
4793d083395SSteven Rostedt 
480d61f82d0SSteven Rostedt 	ftrace_run_update_code(command);
4813d083395SSteven Rostedt  out:
4823d083395SSteven Rostedt 	mutex_unlock(&ftraced_lock);
4833d083395SSteven Rostedt }
4843d083395SSteven Rostedt 
485b0fc494fSSteven Rostedt static void notrace ftrace_startup_sysctl(void)
486b0fc494fSSteven Rostedt {
487d61f82d0SSteven Rostedt 	int command = FTRACE_ENABLE_MCOUNT;
488d61f82d0SSteven Rostedt 
489b0fc494fSSteven Rostedt 	mutex_lock(&ftraced_lock);
490d61f82d0SSteven Rostedt 	/* Force update next time */
491d61f82d0SSteven Rostedt 	saved_ftrace_func = NULL;
492b0fc494fSSteven Rostedt 	/* ftraced_suspend is true if we want ftrace running */
493b0fc494fSSteven Rostedt 	if (ftraced_suspend)
494d61f82d0SSteven Rostedt 		command |= FTRACE_ENABLE_CALLS;
495d61f82d0SSteven Rostedt 
496d61f82d0SSteven Rostedt 	ftrace_run_update_code(command);
497b0fc494fSSteven Rostedt 	mutex_unlock(&ftraced_lock);
498b0fc494fSSteven Rostedt }
499b0fc494fSSteven Rostedt 
500b0fc494fSSteven Rostedt static void notrace ftrace_shutdown_sysctl(void)
501b0fc494fSSteven Rostedt {
502d61f82d0SSteven Rostedt 	int command = FTRACE_DISABLE_MCOUNT;
503d61f82d0SSteven Rostedt 
504b0fc494fSSteven Rostedt 	mutex_lock(&ftraced_lock);
505b0fc494fSSteven Rostedt 	/* ftraced_suspend is true if ftrace is running */
506b0fc494fSSteven Rostedt 	if (ftraced_suspend)
507d61f82d0SSteven Rostedt 		command |= FTRACE_DISABLE_CALLS;
508d61f82d0SSteven Rostedt 
509d61f82d0SSteven Rostedt 	ftrace_run_update_code(command);
510b0fc494fSSteven Rostedt 	mutex_unlock(&ftraced_lock);
511b0fc494fSSteven Rostedt }
512b0fc494fSSteven Rostedt 
5133d083395SSteven Rostedt static cycle_t		ftrace_update_time;
5143d083395SSteven Rostedt static unsigned long	ftrace_update_cnt;
5153d083395SSteven Rostedt unsigned long		ftrace_update_tot_cnt;
5163d083395SSteven Rostedt 
5173d083395SSteven Rostedt static int notrace __ftrace_update_code(void *ignore)
5183d083395SSteven Rostedt {
5193d083395SSteven Rostedt 	struct dyn_ftrace *p;
5203d083395SSteven Rostedt 	struct hlist_head head;
5213d083395SSteven Rostedt 	struct hlist_node *t;
522d61f82d0SSteven Rostedt 	int save_ftrace_enabled;
5233d083395SSteven Rostedt 	cycle_t start, stop;
5243d083395SSteven Rostedt 	int i;
5253d083395SSteven Rostedt 
526d61f82d0SSteven Rostedt 	/* Don't be recording funcs now */
527d61f82d0SSteven Rostedt 	save_ftrace_enabled = ftrace_enabled;
528d61f82d0SSteven Rostedt 	ftrace_enabled = 0;
5293d083395SSteven Rostedt 
5303d083395SSteven Rostedt 	start = now(raw_smp_processor_id());
5313d083395SSteven Rostedt 	ftrace_update_cnt = 0;
5323d083395SSteven Rostedt 
5333d083395SSteven Rostedt 	/* No locks needed, the machine is stopped! */
5343d083395SSteven Rostedt 	for (i = 0; i < FTRACE_HASHSIZE; i++) {
5353d083395SSteven Rostedt 		if (hlist_empty(&ftrace_hash[i]))
5363d083395SSteven Rostedt 			continue;
5373d083395SSteven Rostedt 
5383d083395SSteven Rostedt 		head = ftrace_hash[i];
5393d083395SSteven Rostedt 		INIT_HLIST_HEAD(&ftrace_hash[i]);
5403d083395SSteven Rostedt 
5413d083395SSteven Rostedt 		/* all CPUS are stopped, we are safe to modify code */
5423d083395SSteven Rostedt 		hlist_for_each_entry(p, t, &head, node) {
543d61f82d0SSteven Rostedt 			ftrace_code_disable(p);
5443d083395SSteven Rostedt 			ftrace_update_cnt++;
5453d083395SSteven Rostedt 		}
5463d083395SSteven Rostedt 
5473d083395SSteven Rostedt 	}
5483d083395SSteven Rostedt 
5493d083395SSteven Rostedt 	stop = now(raw_smp_processor_id());
5503d083395SSteven Rostedt 	ftrace_update_time = stop - start;
5513d083395SSteven Rostedt 	ftrace_update_tot_cnt += ftrace_update_cnt;
5523d083395SSteven Rostedt 
553d61f82d0SSteven Rostedt 	ftrace_enabled = save_ftrace_enabled;
55416444a8aSArnaldo Carvalho de Melo 
55516444a8aSArnaldo Carvalho de Melo 	return 0;
55616444a8aSArnaldo Carvalho de Melo }
55716444a8aSArnaldo Carvalho de Melo 
5583d083395SSteven Rostedt static void notrace ftrace_update_code(void)
55916444a8aSArnaldo Carvalho de Melo {
5603d083395SSteven Rostedt 	stop_machine_run(__ftrace_update_code, NULL, NR_CPUS);
5613d083395SSteven Rostedt }
5623d083395SSteven Rostedt 
5633d083395SSteven Rostedt static int notrace ftraced(void *ignore)
5643d083395SSteven Rostedt {
5653d083395SSteven Rostedt 	unsigned long usecs;
5663d083395SSteven Rostedt 
5673d083395SSteven Rostedt 	set_current_state(TASK_INTERRUPTIBLE);
5683d083395SSteven Rostedt 
5693d083395SSteven Rostedt 	while (!kthread_should_stop()) {
5703d083395SSteven Rostedt 
5713d083395SSteven Rostedt 		/* check once a second */
5723d083395SSteven Rostedt 		schedule_timeout(HZ);
5733d083395SSteven Rostedt 
574b0fc494fSSteven Rostedt 		mutex_lock(&ftrace_sysctl_lock);
5753d083395SSteven Rostedt 		mutex_lock(&ftraced_lock);
576b0fc494fSSteven Rostedt 		if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) {
5773d083395SSteven Rostedt 			ftrace_record_suspend++;
5783d083395SSteven Rostedt 			ftrace_update_code();
5793d083395SSteven Rostedt 			usecs = nsecs_to_usecs(ftrace_update_time);
5803d083395SSteven Rostedt 			if (ftrace_update_tot_cnt > 100000) {
5813d083395SSteven Rostedt 				ftrace_update_tot_cnt = 0;
5823d083395SSteven Rostedt 				pr_info("hm, dftrace overflow: %lu change%s"
5833d083395SSteven Rostedt 					 " (%lu total) in %lu usec%s\n",
5843d083395SSteven Rostedt 					ftrace_update_cnt,
5853d083395SSteven Rostedt 					ftrace_update_cnt != 1 ? "s" : "",
5863d083395SSteven Rostedt 					ftrace_update_tot_cnt,
5873d083395SSteven Rostedt 					usecs, usecs != 1 ? "s" : "");
5883d083395SSteven Rostedt 				WARN_ON_ONCE(1);
5893d083395SSteven Rostedt 			}
5903d083395SSteven Rostedt 			ftraced_trigger = 0;
5913d083395SSteven Rostedt 			ftrace_record_suspend--;
5923d083395SSteven Rostedt 		}
5933d083395SSteven Rostedt 		mutex_unlock(&ftraced_lock);
594b0fc494fSSteven Rostedt 		mutex_unlock(&ftrace_sysctl_lock);
5953d083395SSteven Rostedt 
5963d083395SSteven Rostedt 		ftrace_shutdown_replenish();
5973d083395SSteven Rostedt 
5983d083395SSteven Rostedt 		set_current_state(TASK_INTERRUPTIBLE);
5993d083395SSteven Rostedt 	}
6003d083395SSteven Rostedt 	__set_current_state(TASK_RUNNING);
6013d083395SSteven Rostedt 	return 0;
6023d083395SSteven Rostedt }
6033d083395SSteven Rostedt 
6043c1720f0SSteven Rostedt static int __init ftrace_dyn_table_alloc(void)
6053c1720f0SSteven Rostedt {
6063c1720f0SSteven Rostedt 	struct ftrace_page *pg;
6073c1720f0SSteven Rostedt 	int cnt;
6083c1720f0SSteven Rostedt 	int i;
6093c1720f0SSteven Rostedt 
6103c1720f0SSteven Rostedt 	/* allocate a few pages */
6113c1720f0SSteven Rostedt 	ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
6123c1720f0SSteven Rostedt 	if (!ftrace_pages_start)
6133c1720f0SSteven Rostedt 		return -1;
6143c1720f0SSteven Rostedt 
6153c1720f0SSteven Rostedt 	/*
6163c1720f0SSteven Rostedt 	 * Allocate a few more pages.
6173c1720f0SSteven Rostedt 	 *
6183c1720f0SSteven Rostedt 	 * TODO: have some parser search vmlinux before
6193c1720f0SSteven Rostedt 	 *   final linking to find all calls to ftrace.
6203c1720f0SSteven Rostedt 	 *   Then we can:
6213c1720f0SSteven Rostedt 	 *    a) know how many pages to allocate.
6223c1720f0SSteven Rostedt 	 *     and/or
6233c1720f0SSteven Rostedt 	 *    b) set up the table then.
6243c1720f0SSteven Rostedt 	 *
6253c1720f0SSteven Rostedt 	 *  The dynamic code is still necessary for
6263c1720f0SSteven Rostedt 	 *  modules.
6273c1720f0SSteven Rostedt 	 */
6283c1720f0SSteven Rostedt 
6293c1720f0SSteven Rostedt 	pg = ftrace_pages = ftrace_pages_start;
6303c1720f0SSteven Rostedt 
6313c1720f0SSteven Rostedt 	cnt = NR_TO_INIT / ENTRIES_PER_PAGE;
6323c1720f0SSteven Rostedt 
6333c1720f0SSteven Rostedt 	for (i = 0; i < cnt; i++) {
6343c1720f0SSteven Rostedt 		pg->next = (void *)get_zeroed_page(GFP_KERNEL);
6353c1720f0SSteven Rostedt 
6363c1720f0SSteven Rostedt 		/* If we fail, we'll try later anyway */
6373c1720f0SSteven Rostedt 		if (!pg->next)
6383c1720f0SSteven Rostedt 			break;
6393c1720f0SSteven Rostedt 
6403c1720f0SSteven Rostedt 		pg = pg->next;
6413c1720f0SSteven Rostedt 	}
6423c1720f0SSteven Rostedt 
6433c1720f0SSteven Rostedt 	return 0;
6443c1720f0SSteven Rostedt }
6453c1720f0SSteven Rostedt 
646*5072c59fSSteven Rostedt enum {
647*5072c59fSSteven Rostedt 	FTRACE_ITER_FILTER	= (1 << 0),
648*5072c59fSSteven Rostedt 	FTRACE_ITER_CONT	= (1 << 1),
649*5072c59fSSteven Rostedt };
650*5072c59fSSteven Rostedt 
651*5072c59fSSteven Rostedt #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */
652*5072c59fSSteven Rostedt 
653*5072c59fSSteven Rostedt struct ftrace_iterator {
654*5072c59fSSteven Rostedt 	loff_t			pos;
655*5072c59fSSteven Rostedt 	struct ftrace_page	*pg;
656*5072c59fSSteven Rostedt 	unsigned		idx;
657*5072c59fSSteven Rostedt 	unsigned		flags;
658*5072c59fSSteven Rostedt 	unsigned char		buffer[FTRACE_BUFF_MAX+1];
659*5072c59fSSteven Rostedt 	unsigned		buffer_idx;
660*5072c59fSSteven Rostedt 	unsigned		filtered;
661*5072c59fSSteven Rostedt };
662*5072c59fSSteven Rostedt 
663*5072c59fSSteven Rostedt static void notrace *
664*5072c59fSSteven Rostedt t_next(struct seq_file *m, void *v, loff_t *pos)
665*5072c59fSSteven Rostedt {
666*5072c59fSSteven Rostedt 	struct ftrace_iterator *iter = m->private;
667*5072c59fSSteven Rostedt 	struct dyn_ftrace *rec = NULL;
668*5072c59fSSteven Rostedt 
669*5072c59fSSteven Rostedt 	(*pos)++;
670*5072c59fSSteven Rostedt 
671*5072c59fSSteven Rostedt  retry:
672*5072c59fSSteven Rostedt 	if (iter->idx >= iter->pg->index) {
673*5072c59fSSteven Rostedt 		if (iter->pg->next) {
674*5072c59fSSteven Rostedt 			iter->pg = iter->pg->next;
675*5072c59fSSteven Rostedt 			iter->idx = 0;
676*5072c59fSSteven Rostedt 			goto retry;
677*5072c59fSSteven Rostedt 		}
678*5072c59fSSteven Rostedt 	} else {
679*5072c59fSSteven Rostedt 		rec = &iter->pg->records[iter->idx++];
680*5072c59fSSteven Rostedt 		if ((rec->flags & FTRACE_FL_FAILED) ||
681*5072c59fSSteven Rostedt 		    ((iter->flags & FTRACE_ITER_FILTER) &&
682*5072c59fSSteven Rostedt 		     !(rec->flags & FTRACE_FL_FILTER))) {
683*5072c59fSSteven Rostedt 			rec = NULL;
684*5072c59fSSteven Rostedt 			goto retry;
685*5072c59fSSteven Rostedt 		}
686*5072c59fSSteven Rostedt 	}
687*5072c59fSSteven Rostedt 
688*5072c59fSSteven Rostedt 	iter->pos = *pos;
689*5072c59fSSteven Rostedt 
690*5072c59fSSteven Rostedt 	return rec;
691*5072c59fSSteven Rostedt }
692*5072c59fSSteven Rostedt 
693*5072c59fSSteven Rostedt static void *t_start(struct seq_file *m, loff_t *pos)
694*5072c59fSSteven Rostedt {
695*5072c59fSSteven Rostedt 	struct ftrace_iterator *iter = m->private;
696*5072c59fSSteven Rostedt 	void *p = NULL;
697*5072c59fSSteven Rostedt 	loff_t l = -1;
698*5072c59fSSteven Rostedt 
699*5072c59fSSteven Rostedt 	if (*pos != iter->pos) {
700*5072c59fSSteven Rostedt 		for (p = t_next(m, p, &l); p && l < *pos; p = t_next(m, p, &l))
701*5072c59fSSteven Rostedt 			;
702*5072c59fSSteven Rostedt 	} else {
703*5072c59fSSteven Rostedt 		l = *pos;
704*5072c59fSSteven Rostedt 		p = t_next(m, p, &l);
705*5072c59fSSteven Rostedt 	}
706*5072c59fSSteven Rostedt 
707*5072c59fSSteven Rostedt 	return p;
708*5072c59fSSteven Rostedt }
709*5072c59fSSteven Rostedt 
710*5072c59fSSteven Rostedt static void t_stop(struct seq_file *m, void *p)
711*5072c59fSSteven Rostedt {
712*5072c59fSSteven Rostedt }
713*5072c59fSSteven Rostedt 
714*5072c59fSSteven Rostedt static int t_show(struct seq_file *m, void *v)
715*5072c59fSSteven Rostedt {
716*5072c59fSSteven Rostedt 	struct dyn_ftrace *rec = v;
717*5072c59fSSteven Rostedt 	char str[KSYM_SYMBOL_LEN];
718*5072c59fSSteven Rostedt 
719*5072c59fSSteven Rostedt 	if (!rec)
720*5072c59fSSteven Rostedt 		return 0;
721*5072c59fSSteven Rostedt 
722*5072c59fSSteven Rostedt 	kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
723*5072c59fSSteven Rostedt 
724*5072c59fSSteven Rostedt 	seq_printf(m, "%s\n", str);
725*5072c59fSSteven Rostedt 
726*5072c59fSSteven Rostedt 	return 0;
727*5072c59fSSteven Rostedt }
728*5072c59fSSteven Rostedt 
729*5072c59fSSteven Rostedt static struct seq_operations show_ftrace_seq_ops = {
730*5072c59fSSteven Rostedt 	.start = t_start,
731*5072c59fSSteven Rostedt 	.next = t_next,
732*5072c59fSSteven Rostedt 	.stop = t_stop,
733*5072c59fSSteven Rostedt 	.show = t_show,
734*5072c59fSSteven Rostedt };
735*5072c59fSSteven Rostedt 
736*5072c59fSSteven Rostedt static int notrace
737*5072c59fSSteven Rostedt ftrace_avail_open(struct inode *inode, struct file *file)
738*5072c59fSSteven Rostedt {
739*5072c59fSSteven Rostedt 	struct ftrace_iterator *iter;
740*5072c59fSSteven Rostedt 	int ret;
741*5072c59fSSteven Rostedt 
742*5072c59fSSteven Rostedt 	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
743*5072c59fSSteven Rostedt 	if (!iter)
744*5072c59fSSteven Rostedt 		return -ENOMEM;
745*5072c59fSSteven Rostedt 
746*5072c59fSSteven Rostedt 	iter->pg = ftrace_pages_start;
747*5072c59fSSteven Rostedt 	iter->pos = -1;
748*5072c59fSSteven Rostedt 
749*5072c59fSSteven Rostedt 	ret = seq_open(file, &show_ftrace_seq_ops);
750*5072c59fSSteven Rostedt 	if (!ret) {
751*5072c59fSSteven Rostedt 		struct seq_file *m = file->private_data;
752*5072c59fSSteven Rostedt 		m->private = iter;
753*5072c59fSSteven Rostedt 	} else
754*5072c59fSSteven Rostedt 		kfree(iter);
755*5072c59fSSteven Rostedt 
756*5072c59fSSteven Rostedt 	return ret;
757*5072c59fSSteven Rostedt }
758*5072c59fSSteven Rostedt 
759*5072c59fSSteven Rostedt int ftrace_avail_release(struct inode *inode, struct file *file)
760*5072c59fSSteven Rostedt {
761*5072c59fSSteven Rostedt 	struct seq_file *m = (struct seq_file *)file->private_data;
762*5072c59fSSteven Rostedt 	struct ftrace_iterator *iter = m->private;
763*5072c59fSSteven Rostedt 
764*5072c59fSSteven Rostedt 	seq_release(inode, file);
765*5072c59fSSteven Rostedt 	kfree(iter);
766*5072c59fSSteven Rostedt 	return 0;
767*5072c59fSSteven Rostedt }
768*5072c59fSSteven Rostedt 
769*5072c59fSSteven Rostedt static void notrace ftrace_filter_reset(void)
770*5072c59fSSteven Rostedt {
771*5072c59fSSteven Rostedt 	struct ftrace_page *pg;
772*5072c59fSSteven Rostedt 	struct dyn_ftrace *rec;
773*5072c59fSSteven Rostedt 	unsigned i;
774*5072c59fSSteven Rostedt 
775*5072c59fSSteven Rostedt 	/* keep kstop machine from running */
776*5072c59fSSteven Rostedt 	preempt_disable();
777*5072c59fSSteven Rostedt 	ftrace_filtered = 0;
778*5072c59fSSteven Rostedt 	pg = ftrace_pages_start;
779*5072c59fSSteven Rostedt 	while (pg) {
780*5072c59fSSteven Rostedt 		for (i = 0; i < pg->index; i++) {
781*5072c59fSSteven Rostedt 			rec = &pg->records[i];
782*5072c59fSSteven Rostedt 			if (rec->flags & FTRACE_FL_FAILED)
783*5072c59fSSteven Rostedt 				continue;
784*5072c59fSSteven Rostedt 			rec->flags &= ~FTRACE_FL_FILTER;
785*5072c59fSSteven Rostedt 		}
786*5072c59fSSteven Rostedt 		pg = pg->next;
787*5072c59fSSteven Rostedt 	}
788*5072c59fSSteven Rostedt 	preempt_enable();
789*5072c59fSSteven Rostedt }
790*5072c59fSSteven Rostedt 
791*5072c59fSSteven Rostedt static int notrace
792*5072c59fSSteven Rostedt ftrace_filter_open(struct inode *inode, struct file *file)
793*5072c59fSSteven Rostedt {
794*5072c59fSSteven Rostedt 	struct ftrace_iterator *iter;
795*5072c59fSSteven Rostedt 	int ret = 0;
796*5072c59fSSteven Rostedt 
797*5072c59fSSteven Rostedt 	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
798*5072c59fSSteven Rostedt 	if (!iter)
799*5072c59fSSteven Rostedt 		return -ENOMEM;
800*5072c59fSSteven Rostedt 
801*5072c59fSSteven Rostedt 	mutex_lock(&ftrace_filter_lock);
802*5072c59fSSteven Rostedt 	if ((file->f_mode & FMODE_WRITE) &&
803*5072c59fSSteven Rostedt 	    !(file->f_flags & O_APPEND))
804*5072c59fSSteven Rostedt 		ftrace_filter_reset();
805*5072c59fSSteven Rostedt 
806*5072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ) {
807*5072c59fSSteven Rostedt 		iter->pg = ftrace_pages_start;
808*5072c59fSSteven Rostedt 		iter->pos = -1;
809*5072c59fSSteven Rostedt 		iter->flags = FTRACE_ITER_FILTER;
810*5072c59fSSteven Rostedt 
811*5072c59fSSteven Rostedt 		ret = seq_open(file, &show_ftrace_seq_ops);
812*5072c59fSSteven Rostedt 		if (!ret) {
813*5072c59fSSteven Rostedt 			struct seq_file *m = file->private_data;
814*5072c59fSSteven Rostedt 			m->private = iter;
815*5072c59fSSteven Rostedt 		} else
816*5072c59fSSteven Rostedt 			kfree(iter);
817*5072c59fSSteven Rostedt 	} else
818*5072c59fSSteven Rostedt 		file->private_data = iter;
819*5072c59fSSteven Rostedt 	mutex_unlock(&ftrace_filter_lock);
820*5072c59fSSteven Rostedt 
821*5072c59fSSteven Rostedt 	return ret;
822*5072c59fSSteven Rostedt }
823*5072c59fSSteven Rostedt 
824*5072c59fSSteven Rostedt static ssize_t notrace
825*5072c59fSSteven Rostedt ftrace_filter_read(struct file *file, char __user *ubuf,
826*5072c59fSSteven Rostedt 		       size_t cnt, loff_t *ppos)
827*5072c59fSSteven Rostedt {
828*5072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ)
829*5072c59fSSteven Rostedt 		return seq_read(file, ubuf, cnt, ppos);
830*5072c59fSSteven Rostedt 	else
831*5072c59fSSteven Rostedt 		return -EPERM;
832*5072c59fSSteven Rostedt }
833*5072c59fSSteven Rostedt 
834*5072c59fSSteven Rostedt static loff_t notrace
835*5072c59fSSteven Rostedt ftrace_filter_lseek(struct file *file, loff_t offset, int origin)
836*5072c59fSSteven Rostedt {
837*5072c59fSSteven Rostedt 	loff_t ret;
838*5072c59fSSteven Rostedt 
839*5072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ)
840*5072c59fSSteven Rostedt 		ret = seq_lseek(file, offset, origin);
841*5072c59fSSteven Rostedt 	else
842*5072c59fSSteven Rostedt 		file->f_pos = ret = 1;
843*5072c59fSSteven Rostedt 
844*5072c59fSSteven Rostedt 	return ret;
845*5072c59fSSteven Rostedt }
846*5072c59fSSteven Rostedt 
847*5072c59fSSteven Rostedt enum {
848*5072c59fSSteven Rostedt 	MATCH_FULL,
849*5072c59fSSteven Rostedt 	MATCH_FRONT_ONLY,
850*5072c59fSSteven Rostedt 	MATCH_MIDDLE_ONLY,
851*5072c59fSSteven Rostedt 	MATCH_END_ONLY,
852*5072c59fSSteven Rostedt };
853*5072c59fSSteven Rostedt 
854*5072c59fSSteven Rostedt static void notrace
855*5072c59fSSteven Rostedt ftrace_match(unsigned char *buff, int len)
856*5072c59fSSteven Rostedt {
857*5072c59fSSteven Rostedt 	char str[KSYM_SYMBOL_LEN];
858*5072c59fSSteven Rostedt 	char *search = NULL;
859*5072c59fSSteven Rostedt 	struct ftrace_page *pg;
860*5072c59fSSteven Rostedt 	struct dyn_ftrace *rec;
861*5072c59fSSteven Rostedt 	int type = MATCH_FULL;
862*5072c59fSSteven Rostedt 	unsigned i, match = 0, search_len = 0;
863*5072c59fSSteven Rostedt 
864*5072c59fSSteven Rostedt 	for (i = 0; i < len; i++) {
865*5072c59fSSteven Rostedt 		if (buff[i] == '*') {
866*5072c59fSSteven Rostedt 			if (!i) {
867*5072c59fSSteven Rostedt 				search = buff + i + 1;
868*5072c59fSSteven Rostedt 				type = MATCH_END_ONLY;
869*5072c59fSSteven Rostedt 				search_len = len - (i + 1);
870*5072c59fSSteven Rostedt 			} else {
871*5072c59fSSteven Rostedt 				if (type == MATCH_END_ONLY) {
872*5072c59fSSteven Rostedt 					type = MATCH_MIDDLE_ONLY;
873*5072c59fSSteven Rostedt 				} else {
874*5072c59fSSteven Rostedt 					match = i;
875*5072c59fSSteven Rostedt 					type = MATCH_FRONT_ONLY;
876*5072c59fSSteven Rostedt 				}
877*5072c59fSSteven Rostedt 				buff[i] = 0;
878*5072c59fSSteven Rostedt 				break;
879*5072c59fSSteven Rostedt 			}
880*5072c59fSSteven Rostedt 		}
881*5072c59fSSteven Rostedt 	}
882*5072c59fSSteven Rostedt 
883*5072c59fSSteven Rostedt 	/* keep kstop machine from running */
884*5072c59fSSteven Rostedt 	preempt_disable();
885*5072c59fSSteven Rostedt 	ftrace_filtered = 1;
886*5072c59fSSteven Rostedt 	pg = ftrace_pages_start;
887*5072c59fSSteven Rostedt 	while (pg) {
888*5072c59fSSteven Rostedt 		for (i = 0; i < pg->index; i++) {
889*5072c59fSSteven Rostedt 			int matched = 0;
890*5072c59fSSteven Rostedt 			char *ptr;
891*5072c59fSSteven Rostedt 
892*5072c59fSSteven Rostedt 			rec = &pg->records[i];
893*5072c59fSSteven Rostedt 			if (rec->flags & FTRACE_FL_FAILED)
894*5072c59fSSteven Rostedt 				continue;
895*5072c59fSSteven Rostedt 			kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
896*5072c59fSSteven Rostedt 			switch (type) {
897*5072c59fSSteven Rostedt 			case MATCH_FULL:
898*5072c59fSSteven Rostedt 				if (strcmp(str, buff) == 0)
899*5072c59fSSteven Rostedt 					matched = 1;
900*5072c59fSSteven Rostedt 				break;
901*5072c59fSSteven Rostedt 			case MATCH_FRONT_ONLY:
902*5072c59fSSteven Rostedt 				if (memcmp(str, buff, match) == 0)
903*5072c59fSSteven Rostedt 					matched = 1;
904*5072c59fSSteven Rostedt 				break;
905*5072c59fSSteven Rostedt 			case MATCH_MIDDLE_ONLY:
906*5072c59fSSteven Rostedt 				if (strstr(str, search))
907*5072c59fSSteven Rostedt 					matched = 1;
908*5072c59fSSteven Rostedt 				break;
909*5072c59fSSteven Rostedt 			case MATCH_END_ONLY:
910*5072c59fSSteven Rostedt 				ptr = strstr(str, search);
911*5072c59fSSteven Rostedt 				if (ptr && (ptr[search_len] == 0))
912*5072c59fSSteven Rostedt 					matched = 1;
913*5072c59fSSteven Rostedt 				break;
914*5072c59fSSteven Rostedt 			}
915*5072c59fSSteven Rostedt 			if (matched)
916*5072c59fSSteven Rostedt 				rec->flags |= FTRACE_FL_FILTER;
917*5072c59fSSteven Rostedt 		}
918*5072c59fSSteven Rostedt 		pg = pg->next;
919*5072c59fSSteven Rostedt 	}
920*5072c59fSSteven Rostedt 	preempt_enable();
921*5072c59fSSteven Rostedt }
922*5072c59fSSteven Rostedt 
923*5072c59fSSteven Rostedt static ssize_t notrace
924*5072c59fSSteven Rostedt ftrace_filter_write(struct file *file, const char __user *ubuf,
925*5072c59fSSteven Rostedt 		    size_t cnt, loff_t *ppos)
926*5072c59fSSteven Rostedt {
927*5072c59fSSteven Rostedt 	struct ftrace_iterator *iter;
928*5072c59fSSteven Rostedt 	char ch;
929*5072c59fSSteven Rostedt 	size_t read = 0;
930*5072c59fSSteven Rostedt 	ssize_t ret;
931*5072c59fSSteven Rostedt 
932*5072c59fSSteven Rostedt 	if (!cnt || cnt < 0)
933*5072c59fSSteven Rostedt 		return 0;
934*5072c59fSSteven Rostedt 
935*5072c59fSSteven Rostedt 	mutex_lock(&ftrace_filter_lock);
936*5072c59fSSteven Rostedt 
937*5072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ) {
938*5072c59fSSteven Rostedt 		struct seq_file *m = file->private_data;
939*5072c59fSSteven Rostedt 		iter = m->private;
940*5072c59fSSteven Rostedt 	} else
941*5072c59fSSteven Rostedt 		iter = file->private_data;
942*5072c59fSSteven Rostedt 
943*5072c59fSSteven Rostedt 	if (!*ppos) {
944*5072c59fSSteven Rostedt 		iter->flags &= ~FTRACE_ITER_CONT;
945*5072c59fSSteven Rostedt 		iter->buffer_idx = 0;
946*5072c59fSSteven Rostedt 	}
947*5072c59fSSteven Rostedt 
948*5072c59fSSteven Rostedt 	ret = get_user(ch, ubuf++);
949*5072c59fSSteven Rostedt 	if (ret)
950*5072c59fSSteven Rostedt 		goto out;
951*5072c59fSSteven Rostedt 	read++;
952*5072c59fSSteven Rostedt 	cnt--;
953*5072c59fSSteven Rostedt 
954*5072c59fSSteven Rostedt 	if (!(iter->flags & ~FTRACE_ITER_CONT)) {
955*5072c59fSSteven Rostedt 		/* skip white space */
956*5072c59fSSteven Rostedt 		while (cnt && isspace(ch)) {
957*5072c59fSSteven Rostedt 			ret = get_user(ch, ubuf++);
958*5072c59fSSteven Rostedt 			if (ret)
959*5072c59fSSteven Rostedt 				goto out;
960*5072c59fSSteven Rostedt 			read++;
961*5072c59fSSteven Rostedt 			cnt--;
962*5072c59fSSteven Rostedt 		}
963*5072c59fSSteven Rostedt 
964*5072c59fSSteven Rostedt 
965*5072c59fSSteven Rostedt 		if (isspace(ch)) {
966*5072c59fSSteven Rostedt 			file->f_pos += read;
967*5072c59fSSteven Rostedt 			ret = read;
968*5072c59fSSteven Rostedt 			goto out;
969*5072c59fSSteven Rostedt 		}
970*5072c59fSSteven Rostedt 
971*5072c59fSSteven Rostedt 		iter->buffer_idx = 0;
972*5072c59fSSteven Rostedt 	}
973*5072c59fSSteven Rostedt 
974*5072c59fSSteven Rostedt 	while (cnt && !isspace(ch)) {
975*5072c59fSSteven Rostedt 		if (iter->buffer_idx < FTRACE_BUFF_MAX)
976*5072c59fSSteven Rostedt 			iter->buffer[iter->buffer_idx++] = ch;
977*5072c59fSSteven Rostedt 		else {
978*5072c59fSSteven Rostedt 			ret = -EINVAL;
979*5072c59fSSteven Rostedt 			goto out;
980*5072c59fSSteven Rostedt 		}
981*5072c59fSSteven Rostedt 		ret = get_user(ch, ubuf++);
982*5072c59fSSteven Rostedt 		if (ret)
983*5072c59fSSteven Rostedt 			goto out;
984*5072c59fSSteven Rostedt 		read++;
985*5072c59fSSteven Rostedt 		cnt--;
986*5072c59fSSteven Rostedt 	}
987*5072c59fSSteven Rostedt 
988*5072c59fSSteven Rostedt 	if (isspace(ch)) {
989*5072c59fSSteven Rostedt 		iter->filtered++;
990*5072c59fSSteven Rostedt 		iter->buffer[iter->buffer_idx] = 0;
991*5072c59fSSteven Rostedt 		ftrace_match(iter->buffer, iter->buffer_idx);
992*5072c59fSSteven Rostedt 		iter->buffer_idx = 0;
993*5072c59fSSteven Rostedt 	} else
994*5072c59fSSteven Rostedt 		iter->flags |= FTRACE_ITER_CONT;
995*5072c59fSSteven Rostedt 
996*5072c59fSSteven Rostedt 
997*5072c59fSSteven Rostedt 	file->f_pos += read;
998*5072c59fSSteven Rostedt 
999*5072c59fSSteven Rostedt 	ret = read;
1000*5072c59fSSteven Rostedt  out:
1001*5072c59fSSteven Rostedt 	mutex_unlock(&ftrace_filter_lock);
1002*5072c59fSSteven Rostedt 
1003*5072c59fSSteven Rostedt 	return ret;
1004*5072c59fSSteven Rostedt }
1005*5072c59fSSteven Rostedt 
1006*5072c59fSSteven Rostedt static int notrace
1007*5072c59fSSteven Rostedt ftrace_filter_release(struct inode *inode, struct file *file)
1008*5072c59fSSteven Rostedt {
1009*5072c59fSSteven Rostedt 	struct seq_file *m = (struct seq_file *)file->private_data;
1010*5072c59fSSteven Rostedt 	struct ftrace_iterator *iter;
1011*5072c59fSSteven Rostedt 
1012*5072c59fSSteven Rostedt 	mutex_lock(&ftrace_filter_lock);
1013*5072c59fSSteven Rostedt 	if (file->f_mode & FMODE_READ) {
1014*5072c59fSSteven Rostedt 		iter = m->private;
1015*5072c59fSSteven Rostedt 
1016*5072c59fSSteven Rostedt 		seq_release(inode, file);
1017*5072c59fSSteven Rostedt 	} else
1018*5072c59fSSteven Rostedt 		iter = file->private_data;
1019*5072c59fSSteven Rostedt 
1020*5072c59fSSteven Rostedt 	if (iter->buffer_idx) {
1021*5072c59fSSteven Rostedt 		iter->filtered++;
1022*5072c59fSSteven Rostedt 		iter->buffer[iter->buffer_idx] = 0;
1023*5072c59fSSteven Rostedt 		ftrace_match(iter->buffer, iter->buffer_idx);
1024*5072c59fSSteven Rostedt 	}
1025*5072c59fSSteven Rostedt 
1026*5072c59fSSteven Rostedt 	mutex_lock(&ftrace_sysctl_lock);
1027*5072c59fSSteven Rostedt 	mutex_lock(&ftraced_lock);
1028*5072c59fSSteven Rostedt 	if (iter->filtered && ftraced_suspend && ftrace_enabled)
1029*5072c59fSSteven Rostedt 		ftrace_run_update_code(FTRACE_ENABLE_CALLS);
1030*5072c59fSSteven Rostedt 	mutex_unlock(&ftraced_lock);
1031*5072c59fSSteven Rostedt 	mutex_unlock(&ftrace_sysctl_lock);
1032*5072c59fSSteven Rostedt 
1033*5072c59fSSteven Rostedt 	kfree(iter);
1034*5072c59fSSteven Rostedt 	mutex_unlock(&ftrace_filter_lock);
1035*5072c59fSSteven Rostedt 	return 0;
1036*5072c59fSSteven Rostedt }
1037*5072c59fSSteven Rostedt 
1038*5072c59fSSteven Rostedt static struct file_operations ftrace_avail_fops = {
1039*5072c59fSSteven Rostedt 	.open = ftrace_avail_open,
1040*5072c59fSSteven Rostedt 	.read = seq_read,
1041*5072c59fSSteven Rostedt 	.llseek = seq_lseek,
1042*5072c59fSSteven Rostedt 	.release = ftrace_avail_release,
1043*5072c59fSSteven Rostedt };
1044*5072c59fSSteven Rostedt 
1045*5072c59fSSteven Rostedt static struct file_operations ftrace_filter_fops = {
1046*5072c59fSSteven Rostedt 	.open = ftrace_filter_open,
1047*5072c59fSSteven Rostedt 	.read = ftrace_filter_read,
1048*5072c59fSSteven Rostedt 	.write = ftrace_filter_write,
1049*5072c59fSSteven Rostedt 	.llseek = ftrace_filter_lseek,
1050*5072c59fSSteven Rostedt 	.release = ftrace_filter_release,
1051*5072c59fSSteven Rostedt };
1052*5072c59fSSteven Rostedt 
1053*5072c59fSSteven Rostedt static __init int ftrace_init_debugfs(void)
1054*5072c59fSSteven Rostedt {
1055*5072c59fSSteven Rostedt 	struct dentry *d_tracer;
1056*5072c59fSSteven Rostedt 	struct dentry *entry;
1057*5072c59fSSteven Rostedt 
1058*5072c59fSSteven Rostedt 	d_tracer = tracing_init_dentry();
1059*5072c59fSSteven Rostedt 
1060*5072c59fSSteven Rostedt 	entry = debugfs_create_file("available_filter_functions", 0444,
1061*5072c59fSSteven Rostedt 				    d_tracer, NULL, &ftrace_avail_fops);
1062*5072c59fSSteven Rostedt 	if (!entry)
1063*5072c59fSSteven Rostedt 		pr_warning("Could not create debugfs "
1064*5072c59fSSteven Rostedt 			   "'available_filter_functions' entry\n");
1065*5072c59fSSteven Rostedt 
1066*5072c59fSSteven Rostedt 	entry = debugfs_create_file("set_ftrace_filter", 0644, d_tracer,
1067*5072c59fSSteven Rostedt 				    NULL, &ftrace_filter_fops);
1068*5072c59fSSteven Rostedt 	if (!entry)
1069*5072c59fSSteven Rostedt 		pr_warning("Could not create debugfs "
1070*5072c59fSSteven Rostedt 			   "'set_ftrace_filter' entry\n");
1071*5072c59fSSteven Rostedt 	return 0;
1072*5072c59fSSteven Rostedt }
1073*5072c59fSSteven Rostedt 
1074*5072c59fSSteven Rostedt fs_initcall(ftrace_init_debugfs);
1075*5072c59fSSteven Rostedt 
1076d61f82d0SSteven Rostedt static int __init notrace ftrace_dynamic_init(void)
10773d083395SSteven Rostedt {
10783d083395SSteven Rostedt 	struct task_struct *p;
1079d61f82d0SSteven Rostedt 	unsigned long addr;
10803d083395SSteven Rostedt 	int ret;
10813d083395SSteven Rostedt 
1082d61f82d0SSteven Rostedt 	addr = (unsigned long)ftrace_record_ip;
1083d61f82d0SSteven Rostedt 	stop_machine_run(ftrace_dyn_arch_init, &addr, NR_CPUS);
1084d61f82d0SSteven Rostedt 
1085d61f82d0SSteven Rostedt 	/* ftrace_dyn_arch_init places the return code in addr */
1086d61f82d0SSteven Rostedt 	if (addr)
1087d61f82d0SSteven Rostedt 		return addr;
1088d61f82d0SSteven Rostedt 
10893c1720f0SSteven Rostedt 	ret = ftrace_dyn_table_alloc();
10903d083395SSteven Rostedt 	if (ret)
10913d083395SSteven Rostedt 		return ret;
10923d083395SSteven Rostedt 
10933d083395SSteven Rostedt 	p = kthread_run(ftraced, NULL, "ftraced");
10943d083395SSteven Rostedt 	if (IS_ERR(p))
10953d083395SSteven Rostedt 		return -1;
10963d083395SSteven Rostedt 
1097d61f82d0SSteven Rostedt 	last_ftrace_enabled = ftrace_enabled = 1;
10983d083395SSteven Rostedt 
10993d083395SSteven Rostedt 	return 0;
11003d083395SSteven Rostedt }
11013d083395SSteven Rostedt 
1102d61f82d0SSteven Rostedt core_initcall(ftrace_dynamic_init);
11033d083395SSteven Rostedt #else
11043d083395SSteven Rostedt # define ftrace_startup()	  do { } while (0)
11053d083395SSteven Rostedt # define ftrace_shutdown()	  do { } while (0)
1106b0fc494fSSteven Rostedt # define ftrace_startup_sysctl()  do { } while (0)
1107b0fc494fSSteven Rostedt # define ftrace_shutdown_sysctl() do { } while (0)
11083d083395SSteven Rostedt #endif /* CONFIG_DYNAMIC_FTRACE */
11093d083395SSteven Rostedt 
11103d083395SSteven Rostedt /**
11113d083395SSteven Rostedt  * register_ftrace_function - register a function for profiling
11123d083395SSteven Rostedt  * @ops - ops structure that holds the function for profiling.
11133d083395SSteven Rostedt  *
11143d083395SSteven Rostedt  * Register a function to be called by all functions in the
11153d083395SSteven Rostedt  * kernel.
11163d083395SSteven Rostedt  *
11173d083395SSteven Rostedt  * Note: @ops->func and all the functions it calls must be labeled
11183d083395SSteven Rostedt  *       with "notrace", otherwise it will go into a
11193d083395SSteven Rostedt  *       recursive loop.
11203d083395SSteven Rostedt  */
11213d083395SSteven Rostedt int register_ftrace_function(struct ftrace_ops *ops)
11223d083395SSteven Rostedt {
1123b0fc494fSSteven Rostedt 	int ret;
1124b0fc494fSSteven Rostedt 
1125b0fc494fSSteven Rostedt 	mutex_lock(&ftrace_sysctl_lock);
1126b0fc494fSSteven Rostedt 	ret = __register_ftrace_function(ops);
1127d61f82d0SSteven Rostedt 	ftrace_startup();
1128b0fc494fSSteven Rostedt 	mutex_unlock(&ftrace_sysctl_lock);
1129b0fc494fSSteven Rostedt 
1130b0fc494fSSteven Rostedt 	return ret;
11313d083395SSteven Rostedt }
11323d083395SSteven Rostedt 
11333d083395SSteven Rostedt /**
11343d083395SSteven Rostedt  * unregister_ftrace_function - unresgister a function for profiling.
11353d083395SSteven Rostedt  * @ops - ops structure that holds the function to unregister
11363d083395SSteven Rostedt  *
11373d083395SSteven Rostedt  * Unregister a function that was added to be called by ftrace profiling.
11383d083395SSteven Rostedt  */
11393d083395SSteven Rostedt int unregister_ftrace_function(struct ftrace_ops *ops)
11403d083395SSteven Rostedt {
11413d083395SSteven Rostedt 	int ret;
11423d083395SSteven Rostedt 
1143b0fc494fSSteven Rostedt 	mutex_lock(&ftrace_sysctl_lock);
11443d083395SSteven Rostedt 	ret = __unregister_ftrace_function(ops);
11453d083395SSteven Rostedt 	ftrace_shutdown();
1146b0fc494fSSteven Rostedt 	mutex_unlock(&ftrace_sysctl_lock);
1147b0fc494fSSteven Rostedt 
1148b0fc494fSSteven Rostedt 	return ret;
1149b0fc494fSSteven Rostedt }
1150b0fc494fSSteven Rostedt 
1151b0fc494fSSteven Rostedt notrace int
1152b0fc494fSSteven Rostedt ftrace_enable_sysctl(struct ctl_table *table, int write,
1153*5072c59fSSteven Rostedt 		     struct file *file, void __user *buffer, size_t *lenp,
1154b0fc494fSSteven Rostedt 		     loff_t *ppos)
1155b0fc494fSSteven Rostedt {
1156b0fc494fSSteven Rostedt 	int ret;
1157b0fc494fSSteven Rostedt 
1158b0fc494fSSteven Rostedt 	mutex_lock(&ftrace_sysctl_lock);
1159b0fc494fSSteven Rostedt 
1160*5072c59fSSteven Rostedt 	ret  = proc_dointvec(table, write, file, buffer, lenp, ppos);
1161b0fc494fSSteven Rostedt 
1162b0fc494fSSteven Rostedt 	if (ret || !write || (last_ftrace_enabled == ftrace_enabled))
1163b0fc494fSSteven Rostedt 		goto out;
1164b0fc494fSSteven Rostedt 
1165b0fc494fSSteven Rostedt 	last_ftrace_enabled = ftrace_enabled;
1166b0fc494fSSteven Rostedt 
1167b0fc494fSSteven Rostedt 	if (ftrace_enabled) {
1168b0fc494fSSteven Rostedt 
1169b0fc494fSSteven Rostedt 		ftrace_startup_sysctl();
1170b0fc494fSSteven Rostedt 
1171b0fc494fSSteven Rostedt 		/* we are starting ftrace again */
1172b0fc494fSSteven Rostedt 		if (ftrace_list != &ftrace_list_end) {
1173b0fc494fSSteven Rostedt 			if (ftrace_list->next == &ftrace_list_end)
1174b0fc494fSSteven Rostedt 				ftrace_trace_function = ftrace_list->func;
1175b0fc494fSSteven Rostedt 			else
1176b0fc494fSSteven Rostedt 				ftrace_trace_function = ftrace_list_func;
1177b0fc494fSSteven Rostedt 		}
1178b0fc494fSSteven Rostedt 
1179b0fc494fSSteven Rostedt 	} else {
1180b0fc494fSSteven Rostedt 		/* stopping ftrace calls (just send to ftrace_stub) */
1181b0fc494fSSteven Rostedt 		ftrace_trace_function = ftrace_stub;
1182b0fc494fSSteven Rostedt 
1183b0fc494fSSteven Rostedt 		ftrace_shutdown_sysctl();
1184b0fc494fSSteven Rostedt 	}
1185b0fc494fSSteven Rostedt 
1186b0fc494fSSteven Rostedt  out:
1187b0fc494fSSteven Rostedt 	mutex_unlock(&ftrace_sysctl_lock);
11883d083395SSteven Rostedt 	return ret;
118916444a8aSArnaldo Carvalho de Melo }
1190