blob: b42ec1de546bdb8081136e601056b801b367ae3a [file] [log] [blame]
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +02001/*
2 * Infrastructure for profiling code inserted by 'gcc -pg'.
3 *
4 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
5 * Copyright (C) 2004-2008 Ingo Molnar <mingo@redhat.com>
6 *
7 * Originally ported from the -rt patch by:
8 * Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
9 *
10 * Based on code in the latency_tracer, that is:
11 *
12 * Copyright (C) 2004-2006 Ingo Molnar
13 * Copyright (C) 2004 William Lee Irwin III
14 */
15
Steven Rostedt3d083392008-05-12 21:20:42 +020016#include <linux/stop_machine.h>
17#include <linux/clocksource.h>
18#include <linux/kallsyms.h>
Steven Rostedt5072c592008-05-12 21:20:43 +020019#include <linux/seq_file.h>
20#include <linux/debugfs.h>
Steven Rostedt3d083392008-05-12 21:20:42 +020021#include <linux/hardirq.h>
Ingo Molnar2d8b8202008-02-23 16:55:50 +010022#include <linux/kthread.h>
Steven Rostedt5072c592008-05-12 21:20:43 +020023#include <linux/uaccess.h>
Abhishek Sagarf22f9a82008-06-21 23:50:29 +053024#include <linux/kprobes.h>
Ingo Molnar2d8b8202008-02-23 16:55:50 +010025#include <linux/ftrace.h>
Steven Rostedtb0fc4942008-05-12 21:20:43 +020026#include <linux/sysctl.h>
Steven Rostedt5072c592008-05-12 21:20:43 +020027#include <linux/ctype.h>
Steven Rostedt3d083392008-05-12 21:20:42 +020028#include <linux/list.h>
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020029
Abhishek Sagar395a59d2008-06-21 23:47:27 +053030#include <asm/ftrace.h>
31
Steven Rostedt3d083392008-05-12 21:20:42 +020032#include "trace.h"
33
Steven Rostedt6912896e2008-10-23 09:33:03 -040034#define FTRACE_WARN_ON(cond) \
35 do { \
36 if (WARN_ON(cond)) \
37 ftrace_kill(); \
38 } while (0)
39
40#define FTRACE_WARN_ON_ONCE(cond) \
41 do { \
42 if (WARN_ON_ONCE(cond)) \
43 ftrace_kill(); \
44 } while (0)
45
Steven Rostedt4eebcc82008-05-12 21:20:48 +020046/* ftrace_enabled is a method to turn ftrace on or off */
47int ftrace_enabled __read_mostly;
Steven Rostedtd61f82d2008-05-12 21:20:43 +020048static int last_ftrace_enabled;
Steven Rostedtb0fc4942008-05-12 21:20:43 +020049
Steven Rostedt60a7ecf2008-11-05 16:05:44 -050050/* Quick disabling of function tracer. */
51int function_trace_stop;
52
Steven Rostedt4eebcc82008-05-12 21:20:48 +020053/*
54 * ftrace_disabled is set when an anomaly is discovered.
55 * ftrace_disabled is much stronger than ftrace_enabled.
56 */
57static int ftrace_disabled __read_mostly;
58
Steven Rostedt3d083392008-05-12 21:20:42 +020059static DEFINE_SPINLOCK(ftrace_lock);
Steven Rostedtb0fc4942008-05-12 21:20:43 +020060static DEFINE_MUTEX(ftrace_sysctl_lock);
61
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020062static struct ftrace_ops ftrace_list_end __read_mostly =
63{
64 .func = ftrace_stub,
65};
66
67static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end;
68ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
Steven Rostedt60a7ecf2008-11-05 16:05:44 -050069ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020070
Ingo Molnarf2252932008-05-22 10:37:48 +020071static void ftrace_list_func(unsigned long ip, unsigned long parent_ip)
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020072{
73 struct ftrace_ops *op = ftrace_list;
74
75 /* in case someone actually ports this to alpha! */
76 read_barrier_depends();
77
78 while (op != &ftrace_list_end) {
79 /* silly alpha */
80 read_barrier_depends();
81 op->func(ip, parent_ip);
82 op = op->next;
83 };
84}
85
86/**
Steven Rostedt3d083392008-05-12 21:20:42 +020087 * clear_ftrace_function - reset the ftrace function
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020088 *
Steven Rostedt3d083392008-05-12 21:20:42 +020089 * This NULLs the ftrace function and in essence stops
90 * tracing. There may be lag
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020091 */
Steven Rostedt3d083392008-05-12 21:20:42 +020092void clear_ftrace_function(void)
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020093{
Steven Rostedt3d083392008-05-12 21:20:42 +020094 ftrace_trace_function = ftrace_stub;
Steven Rostedt60a7ecf2008-11-05 16:05:44 -050095 __ftrace_trace_function = ftrace_stub;
Steven Rostedt3d083392008-05-12 21:20:42 +020096}
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +020097
Steven Rostedt60a7ecf2008-11-05 16:05:44 -050098#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
99/*
100 * For those archs that do not test ftrace_trace_stop in their
101 * mcount call site, we need to do it from C.
102 */
103static void ftrace_test_stop_func(unsigned long ip, unsigned long parent_ip)
104{
105 if (function_trace_stop)
106 return;
107
108 __ftrace_trace_function(ip, parent_ip);
109}
110#endif
111
Ingo Molnare309b412008-05-12 21:20:51 +0200112static int __register_ftrace_function(struct ftrace_ops *ops)
Steven Rostedt3d083392008-05-12 21:20:42 +0200113{
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400114 /* should not be called from interrupt context */
Steven Rostedt3d083392008-05-12 21:20:42 +0200115 spin_lock(&ftrace_lock);
116
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200117 ops->next = ftrace_list;
118 /*
119 * We are entering ops into the ftrace_list but another
120 * CPU might be walking that list. We need to make sure
121 * the ops->next pointer is valid before another CPU sees
122 * the ops pointer included into the ftrace_list.
123 */
124 smp_wmb();
125 ftrace_list = ops;
Steven Rostedt3d083392008-05-12 21:20:42 +0200126
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200127 if (ftrace_enabled) {
128 /*
129 * For one func, simply call it directly.
130 * For more than one func, call the chain.
131 */
Steven Rostedt60a7ecf2008-11-05 16:05:44 -0500132#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200133 if (ops->next == &ftrace_list_end)
134 ftrace_trace_function = ops->func;
135 else
136 ftrace_trace_function = ftrace_list_func;
Steven Rostedt60a7ecf2008-11-05 16:05:44 -0500137#else
138 if (ops->next == &ftrace_list_end)
139 __ftrace_trace_function = ops->func;
140 else
141 __ftrace_trace_function = ftrace_list_func;
142 ftrace_trace_function = ftrace_test_stop_func;
143#endif
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200144 }
Steven Rostedt3d083392008-05-12 21:20:42 +0200145
146 spin_unlock(&ftrace_lock);
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200147
148 return 0;
149}
150
Ingo Molnare309b412008-05-12 21:20:51 +0200151static int __unregister_ftrace_function(struct ftrace_ops *ops)
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200152{
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200153 struct ftrace_ops **p;
154 int ret = 0;
155
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400156 /* should not be called from interrupt context */
Steven Rostedt3d083392008-05-12 21:20:42 +0200157 spin_lock(&ftrace_lock);
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200158
159 /*
Steven Rostedt3d083392008-05-12 21:20:42 +0200160 * If we are removing the last function, then simply point
161 * to the ftrace_stub.
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200162 */
163 if (ftrace_list == ops && ops->next == &ftrace_list_end) {
164 ftrace_trace_function = ftrace_stub;
165 ftrace_list = &ftrace_list_end;
166 goto out;
167 }
168
169 for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next)
170 if (*p == ops)
171 break;
172
173 if (*p != ops) {
174 ret = -1;
175 goto out;
176 }
177
178 *p = (*p)->next;
179
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200180 if (ftrace_enabled) {
181 /* If we only have one func left, then call that directly */
walimisb3535c62008-11-14 00:21:02 +0800182 if (ftrace_list->next == &ftrace_list_end)
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200183 ftrace_trace_function = ftrace_list->func;
184 }
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200185
186 out:
Steven Rostedt3d083392008-05-12 21:20:42 +0200187 spin_unlock(&ftrace_lock);
188
189 return ret;
190}
191
192#ifdef CONFIG_DYNAMIC_FTRACE
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400193#ifndef CONFIG_FTRACE_MCOUNT_RECORD
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400194# error Dynamic ftrace depends on MCOUNT_RECORD
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400195#endif
196
Steven Noonan71c67d582008-09-20 01:00:37 -0700197/*
198 * Since MCOUNT_ADDR may point to mcount itself, we do not want
199 * to get it confused by reading a reference in the code as we
200 * are parsing on objcopy output of text. Use a variable for
201 * it instead.
202 */
203static unsigned long mcount_addr = MCOUNT_ADDR;
204
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200205enum {
206 FTRACE_ENABLE_CALLS = (1 << 0),
207 FTRACE_DISABLE_CALLS = (1 << 1),
208 FTRACE_UPDATE_TRACE_FUNC = (1 << 2),
209 FTRACE_ENABLE_MCOUNT = (1 << 3),
210 FTRACE_DISABLE_MCOUNT = (1 << 4),
211};
212
Steven Rostedt5072c592008-05-12 21:20:43 +0200213static int ftrace_filtered;
214
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400215static LIST_HEAD(ftrace_new_addrs);
Steven Rostedt3d083392008-05-12 21:20:42 +0200216
Steven Rostedt41c52c02008-05-22 11:46:33 -0400217static DEFINE_MUTEX(ftrace_regex_lock);
Steven Rostedt3d083392008-05-12 21:20:42 +0200218
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200219struct ftrace_page {
220 struct ftrace_page *next;
David Milleraa5e5ce2008-05-13 22:06:56 -0700221 unsigned long index;
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200222 struct dyn_ftrace records[];
David Milleraa5e5ce2008-05-13 22:06:56 -0700223};
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200224
225#define ENTRIES_PER_PAGE \
226 ((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct dyn_ftrace))
227
228/* estimate from running different kernels */
229#define NR_TO_INIT 10000
230
231static struct ftrace_page *ftrace_pages_start;
232static struct ftrace_page *ftrace_pages;
233
Steven Rostedt37ad5082008-05-12 21:20:48 +0200234static struct dyn_ftrace *ftrace_free_records;
235
Abhishek Sagarecea6562008-06-21 23:47:53 +0530236
237#ifdef CONFIG_KPROBES
Ingo Molnarf17845e2008-10-24 12:47:10 +0200238
239static int frozen_record_count;
240
Abhishek Sagarecea6562008-06-21 23:47:53 +0530241static inline void freeze_record(struct dyn_ftrace *rec)
242{
243 if (!(rec->flags & FTRACE_FL_FROZEN)) {
244 rec->flags |= FTRACE_FL_FROZEN;
245 frozen_record_count++;
246 }
247}
248
249static inline void unfreeze_record(struct dyn_ftrace *rec)
250{
251 if (rec->flags & FTRACE_FL_FROZEN) {
252 rec->flags &= ~FTRACE_FL_FROZEN;
253 frozen_record_count--;
254 }
255}
256
257static inline int record_frozen(struct dyn_ftrace *rec)
258{
259 return rec->flags & FTRACE_FL_FROZEN;
260}
261#else
262# define freeze_record(rec) ({ 0; })
263# define unfreeze_record(rec) ({ 0; })
264# define record_frozen(rec) ({ 0; })
265#endif /* CONFIG_KPROBES */
266
Ingo Molnare309b412008-05-12 21:20:51 +0200267static void ftrace_free_rec(struct dyn_ftrace *rec)
Steven Rostedt37ad5082008-05-12 21:20:48 +0200268{
Steven Rostedt37ad5082008-05-12 21:20:48 +0200269 rec->ip = (unsigned long)ftrace_free_records;
270 ftrace_free_records = rec;
271 rec->flags |= FTRACE_FL_FREE;
272}
273
Steven Rostedtfed19392008-08-14 22:47:19 -0400274void ftrace_release(void *start, unsigned long size)
275{
276 struct dyn_ftrace *rec;
277 struct ftrace_page *pg;
278 unsigned long s = (unsigned long)start;
279 unsigned long e = s + size;
280 int i;
281
Steven Rostedt00fd61a2008-08-15 21:40:04 -0400282 if (ftrace_disabled || !start)
Steven Rostedtfed19392008-08-14 22:47:19 -0400283 return;
284
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400285 /* should not be called from interrupt context */
Steven Rostedtfed19392008-08-14 22:47:19 -0400286 spin_lock(&ftrace_lock);
287
288 for (pg = ftrace_pages_start; pg; pg = pg->next) {
289 for (i = 0; i < pg->index; i++) {
290 rec = &pg->records[i];
291
292 if ((rec->ip >= s) && (rec->ip < e))
293 ftrace_free_rec(rec);
294 }
295 }
296 spin_unlock(&ftrace_lock);
Steven Rostedtfed19392008-08-14 22:47:19 -0400297}
298
Ingo Molnare309b412008-05-12 21:20:51 +0200299static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200300{
Steven Rostedt37ad5082008-05-12 21:20:48 +0200301 struct dyn_ftrace *rec;
302
303 /* First check for freed records */
304 if (ftrace_free_records) {
305 rec = ftrace_free_records;
306
Steven Rostedt37ad5082008-05-12 21:20:48 +0200307 if (unlikely(!(rec->flags & FTRACE_FL_FREE))) {
Steven Rostedt6912896e2008-10-23 09:33:03 -0400308 FTRACE_WARN_ON_ONCE(1);
Steven Rostedt37ad5082008-05-12 21:20:48 +0200309 ftrace_free_records = NULL;
310 return NULL;
311 }
312
313 ftrace_free_records = (void *)rec->ip;
314 memset(rec, 0, sizeof(*rec));
315 return rec;
316 }
317
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200318 if (ftrace_pages->index == ENTRIES_PER_PAGE) {
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400319 if (!ftrace_pages->next) {
320 /* allocate another page */
321 ftrace_pages->next =
322 (void *)get_zeroed_page(GFP_KERNEL);
323 if (!ftrace_pages->next)
324 return NULL;
325 }
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200326 ftrace_pages = ftrace_pages->next;
327 }
328
329 return &ftrace_pages->records[ftrace_pages->index++];
330}
331
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400332static struct dyn_ftrace *
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200333ftrace_record_ip(unsigned long ip)
Steven Rostedt3d083392008-05-12 21:20:42 +0200334{
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400335 struct dyn_ftrace *rec;
Steven Rostedt3d083392008-05-12 21:20:42 +0200336
Steven Rostedtf3c7ac42008-11-14 16:21:19 -0800337 if (ftrace_disabled)
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400338 return NULL;
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200339
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400340 rec = ftrace_alloc_dyn_node(ip);
341 if (!rec)
342 return NULL;
Steven Rostedt3d083392008-05-12 21:20:42 +0200343
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400344 rec->ip = ip;
Steven Rostedt3d083392008-05-12 21:20:42 +0200345
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400346 list_add(&rec->list, &ftrace_new_addrs);
Steven Rostedt3d083392008-05-12 21:20:42 +0200347
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400348 return rec;
Steven Rostedt3d083392008-05-12 21:20:42 +0200349}
350
Steven Rostedtb17e8a32008-11-14 16:21:19 -0800351static void print_ip_ins(const char *fmt, unsigned char *p)
352{
353 int i;
354
355 printk(KERN_CONT "%s", fmt);
356
357 for (i = 0; i < MCOUNT_INSN_SIZE; i++)
358 printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
359}
360
Steven Rostedt31e88902008-11-14 16:21:19 -0800361static void ftrace_bug(int failed, unsigned long ip)
Steven Rostedtb17e8a32008-11-14 16:21:19 -0800362{
363 switch (failed) {
364 case -EFAULT:
365 FTRACE_WARN_ON_ONCE(1);
366 pr_info("ftrace faulted on modifying ");
367 print_ip_sym(ip);
368 break;
369 case -EINVAL:
370 FTRACE_WARN_ON_ONCE(1);
371 pr_info("ftrace failed to modify ");
372 print_ip_sym(ip);
Steven Rostedtb17e8a32008-11-14 16:21:19 -0800373 print_ip_ins(" actual: ", (unsigned char *)ip);
Steven Rostedtb17e8a32008-11-14 16:21:19 -0800374 printk(KERN_CONT "\n");
375 break;
376 case -EPERM:
377 FTRACE_WARN_ON_ONCE(1);
378 pr_info("ftrace faulted on writing ");
379 print_ip_sym(ip);
380 break;
381 default:
382 FTRACE_WARN_ON_ONCE(1);
383 pr_info("ftrace faulted on unknown error ");
384 print_ip_sym(ip);
385 }
386}
387
Steven Rostedtcaf8cde2008-05-12 21:20:50 +0200388#define FTRACE_ADDR ((long)(ftrace_caller))
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200389
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530390static int
Steven Rostedt31e88902008-11-14 16:21:19 -0800391__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
Steven Rostedt5072c592008-05-12 21:20:43 +0200392{
Steven Rostedt41c52c02008-05-22 11:46:33 -0400393 unsigned long ip, fl;
Steven Rostedt5072c592008-05-12 21:20:43 +0200394
395 ip = rec->ip;
396
Steven Rostedt982c3502008-11-15 16:31:41 -0500397 /*
398 * If this record is not to be traced and
399 * it is not enabled then do nothing.
400 *
401 * If this record is not to be traced and
402 * it is enabled then disabled it.
403 *
404 */
405 if (rec->flags & FTRACE_FL_NOTRACE) {
406 if (rec->flags & FTRACE_FL_ENABLED)
407 rec->flags &= ~FTRACE_FL_ENABLED;
408 else
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530409 return 0;
Steven Rostedt5072c592008-05-12 21:20:43 +0200410
Steven Rostedt982c3502008-11-15 16:31:41 -0500411 } else if (ftrace_filtered && enable) {
Steven Rostedt5072c592008-05-12 21:20:43 +0200412 /*
Steven Rostedt982c3502008-11-15 16:31:41 -0500413 * Filtering is on:
Steven Rostedt5072c592008-05-12 21:20:43 +0200414 */
Steven Rostedt982c3502008-11-15 16:31:41 -0500415
416 fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED);
417
418 /* Record is filtered and enabled, do nothing */
419 if (fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED))
420 return 0;
421
422 /* Record is not filtered and is not enabled do nothing */
423 if (!fl)
424 return 0;
425
426 /* Record is not filtered but enabled, disable it */
427 if (fl == FTRACE_FL_ENABLED)
Steven Rostedt5072c592008-05-12 21:20:43 +0200428 rec->flags &= ~FTRACE_FL_ENABLED;
Steven Rostedt982c3502008-11-15 16:31:41 -0500429 else
430 /* Otherwise record is filtered but not enabled, enable it */
Steven Rostedt5072c592008-05-12 21:20:43 +0200431 rec->flags |= FTRACE_FL_ENABLED;
Steven Rostedt5072c592008-05-12 21:20:43 +0200432 } else {
Steven Rostedt982c3502008-11-15 16:31:41 -0500433 /* Disable or not filtered */
Steven Rostedt5072c592008-05-12 21:20:43 +0200434
Steven Rostedt41c52c02008-05-22 11:46:33 -0400435 if (enable) {
Steven Rostedt982c3502008-11-15 16:31:41 -0500436 /* if record is enabled, do nothing */
Steven Rostedt5072c592008-05-12 21:20:43 +0200437 if (rec->flags & FTRACE_FL_ENABLED)
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530438 return 0;
Steven Rostedt982c3502008-11-15 16:31:41 -0500439
Steven Rostedt5072c592008-05-12 21:20:43 +0200440 rec->flags |= FTRACE_FL_ENABLED;
Steven Rostedt982c3502008-11-15 16:31:41 -0500441
Steven Rostedt5072c592008-05-12 21:20:43 +0200442 } else {
Steven Rostedt982c3502008-11-15 16:31:41 -0500443
444 /* if record is not enabled do nothing */
Steven Rostedt5072c592008-05-12 21:20:43 +0200445 if (!(rec->flags & FTRACE_FL_ENABLED))
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530446 return 0;
Steven Rostedt982c3502008-11-15 16:31:41 -0500447
Steven Rostedt5072c592008-05-12 21:20:43 +0200448 rec->flags &= ~FTRACE_FL_ENABLED;
449 }
450 }
451
Steven Rostedt982c3502008-11-15 16:31:41 -0500452 if (rec->flags & FTRACE_FL_ENABLED)
Steven Rostedt31e88902008-11-14 16:21:19 -0800453 return ftrace_make_call(rec, FTRACE_ADDR);
454 else
455 return ftrace_make_nop(NULL, rec, FTRACE_ADDR);
Steven Rostedt5072c592008-05-12 21:20:43 +0200456}
457
Ingo Molnare309b412008-05-12 21:20:51 +0200458static void ftrace_replace_code(int enable)
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200459{
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530460 int i, failed;
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200461 struct dyn_ftrace *rec;
462 struct ftrace_page *pg;
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200463
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200464 for (pg = ftrace_pages_start; pg; pg = pg->next) {
465 for (i = 0; i < pg->index; i++) {
466 rec = &pg->records[i];
467
Steven Rostedt918c1152008-11-14 16:21:19 -0800468 /*
469 * Skip over free records and records that have
470 * failed.
471 */
472 if (rec->flags & FTRACE_FL_FREE ||
473 rec->flags & FTRACE_FL_FAILED)
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200474 continue;
475
Abhishek Sagarf22f9a82008-06-21 23:50:29 +0530476 /* ignore updates to this record's mcount site */
Abhishek Sagar98a05ed2008-06-26 22:51:51 +0530477 if (get_kprobe((void *)rec->ip)) {
478 freeze_record(rec);
Abhishek Sagarf22f9a82008-06-21 23:50:29 +0530479 continue;
Abhishek Sagar98a05ed2008-06-26 22:51:51 +0530480 } else {
481 unfreeze_record(rec);
482 }
Abhishek Sagarf22f9a82008-06-21 23:50:29 +0530483
Steven Rostedt31e88902008-11-14 16:21:19 -0800484 failed = __ftrace_replace_code(rec, enable);
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530485 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) {
486 rec->flags |= FTRACE_FL_FAILED;
487 if ((system_state == SYSTEM_BOOTING) ||
Abhishek Sagar34078a52008-06-03 08:33:41 +0530488 !core_kernel_text(rec->ip)) {
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530489 ftrace_free_rec(rec);
Steven Rostedtb17e8a32008-11-14 16:21:19 -0800490 } else
Steven Rostedt31e88902008-11-14 16:21:19 -0800491 ftrace_bug(failed, rec->ip);
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530492 }
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200493 }
494 }
495}
496
Abhishek Sagar492a7ea52008-05-25 00:10:04 +0530497static int
Steven Rostedt31e88902008-11-14 16:21:19 -0800498ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200499{
500 unsigned long ip;
Steven Rostedt593eb8a2008-10-23 09:32:59 -0400501 int ret;
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200502
503 ip = rec->ip;
504
Steven Rostedt31e88902008-11-14 16:21:19 -0800505 ret = ftrace_make_nop(mod, rec, mcount_addr);
Steven Rostedt593eb8a2008-10-23 09:32:59 -0400506 if (ret) {
Steven Rostedt31e88902008-11-14 16:21:19 -0800507 ftrace_bug(ret, ip);
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200508 rec->flags |= FTRACE_FL_FAILED;
Abhishek Sagar492a7ea52008-05-25 00:10:04 +0530509 return 0;
Steven Rostedt37ad5082008-05-12 21:20:48 +0200510 }
Abhishek Sagar492a7ea52008-05-25 00:10:04 +0530511 return 1;
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200512}
513
Ingo Molnare309b412008-05-12 21:20:51 +0200514static int __ftrace_modify_code(void *data)
Steven Rostedt3d083392008-05-12 21:20:42 +0200515{
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200516 int *command = data;
517
Steven Rostedta3583242008-11-11 15:01:42 -0500518 if (*command & FTRACE_ENABLE_CALLS)
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200519 ftrace_replace_code(1);
Steven Rostedta3583242008-11-11 15:01:42 -0500520 else if (*command & FTRACE_DISABLE_CALLS)
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200521 ftrace_replace_code(0);
522
523 if (*command & FTRACE_UPDATE_TRACE_FUNC)
524 ftrace_update_ftrace_func(ftrace_trace_function);
525
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200526 return 0;
Steven Rostedt3d083392008-05-12 21:20:42 +0200527}
528
Ingo Molnare309b412008-05-12 21:20:51 +0200529static void ftrace_run_update_code(int command)
Steven Rostedt3d083392008-05-12 21:20:42 +0200530{
Rusty Russell784e2d72008-07-28 12:16:31 -0500531 stop_machine(__ftrace_modify_code, &command, NULL);
Steven Rostedt3d083392008-05-12 21:20:42 +0200532}
533
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200534static ftrace_func_t saved_ftrace_func;
Steven Rostedt60a7ecf2008-11-05 16:05:44 -0500535static int ftrace_start_up;
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400536static DEFINE_MUTEX(ftrace_start_lock);
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200537
Ingo Molnare309b412008-05-12 21:20:51 +0200538static void ftrace_startup(void)
Steven Rostedt3d083392008-05-12 21:20:42 +0200539{
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200540 int command = 0;
541
Steven Rostedt4eebcc82008-05-12 21:20:48 +0200542 if (unlikely(ftrace_disabled))
543 return;
544
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400545 mutex_lock(&ftrace_start_lock);
Steven Rostedt60a7ecf2008-11-05 16:05:44 -0500546 ftrace_start_up++;
Steven Rostedt982c3502008-11-15 16:31:41 -0500547 command |= FTRACE_ENABLE_CALLS;
Steven Rostedt3d083392008-05-12 21:20:42 +0200548
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200549 if (saved_ftrace_func != ftrace_trace_function) {
550 saved_ftrace_func = ftrace_trace_function;
551 command |= FTRACE_UPDATE_TRACE_FUNC;
552 }
553
554 if (!command || !ftrace_enabled)
555 goto out;
556
557 ftrace_run_update_code(command);
Steven Rostedt3d083392008-05-12 21:20:42 +0200558 out:
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400559 mutex_unlock(&ftrace_start_lock);
Steven Rostedt3d083392008-05-12 21:20:42 +0200560}
561
Ingo Molnare309b412008-05-12 21:20:51 +0200562static void ftrace_shutdown(void)
Steven Rostedt3d083392008-05-12 21:20:42 +0200563{
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200564 int command = 0;
565
Steven Rostedt4eebcc82008-05-12 21:20:48 +0200566 if (unlikely(ftrace_disabled))
567 return;
568
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400569 mutex_lock(&ftrace_start_lock);
Steven Rostedt60a7ecf2008-11-05 16:05:44 -0500570 ftrace_start_up--;
571 if (!ftrace_start_up)
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200572 command |= FTRACE_DISABLE_CALLS;
573
574 if (saved_ftrace_func != ftrace_trace_function) {
575 saved_ftrace_func = ftrace_trace_function;
576 command |= FTRACE_UPDATE_TRACE_FUNC;
577 }
578
579 if (!command || !ftrace_enabled)
Steven Rostedt3d083392008-05-12 21:20:42 +0200580 goto out;
581
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200582 ftrace_run_update_code(command);
Steven Rostedt3d083392008-05-12 21:20:42 +0200583 out:
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400584 mutex_unlock(&ftrace_start_lock);
Steven Rostedt3d083392008-05-12 21:20:42 +0200585}
586
Ingo Molnare309b412008-05-12 21:20:51 +0200587static void ftrace_startup_sysctl(void)
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200588{
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200589 int command = FTRACE_ENABLE_MCOUNT;
590
Steven Rostedt4eebcc82008-05-12 21:20:48 +0200591 if (unlikely(ftrace_disabled))
592 return;
593
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400594 mutex_lock(&ftrace_start_lock);
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200595 /* Force update next time */
596 saved_ftrace_func = NULL;
Steven Rostedt60a7ecf2008-11-05 16:05:44 -0500597 /* ftrace_start_up is true if we want ftrace running */
598 if (ftrace_start_up)
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200599 command |= FTRACE_ENABLE_CALLS;
600
601 ftrace_run_update_code(command);
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400602 mutex_unlock(&ftrace_start_lock);
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200603}
604
Ingo Molnare309b412008-05-12 21:20:51 +0200605static void ftrace_shutdown_sysctl(void)
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200606{
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200607 int command = FTRACE_DISABLE_MCOUNT;
608
Steven Rostedt4eebcc82008-05-12 21:20:48 +0200609 if (unlikely(ftrace_disabled))
610 return;
611
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400612 mutex_lock(&ftrace_start_lock);
Steven Rostedt60a7ecf2008-11-05 16:05:44 -0500613 /* ftrace_start_up is true if ftrace is running */
614 if (ftrace_start_up)
Steven Rostedtd61f82d2008-05-12 21:20:43 +0200615 command |= FTRACE_DISABLE_CALLS;
616
617 ftrace_run_update_code(command);
Steven Rostedtcb7be3b2008-10-23 09:33:05 -0400618 mutex_unlock(&ftrace_start_lock);
Steven Rostedtb0fc4942008-05-12 21:20:43 +0200619}
620
Steven Rostedt3d083392008-05-12 21:20:42 +0200621static cycle_t ftrace_update_time;
622static unsigned long ftrace_update_cnt;
623unsigned long ftrace_update_tot_cnt;
624
Steven Rostedt31e88902008-11-14 16:21:19 -0800625static int ftrace_update_code(struct module *mod)
Steven Rostedt3d083392008-05-12 21:20:42 +0200626{
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400627 struct dyn_ftrace *p, *t;
Abhishek Sagarf22f9a82008-06-21 23:50:29 +0530628 cycle_t start, stop;
Steven Rostedt3d083392008-05-12 21:20:42 +0200629
Ingo Molnar750ed1a2008-05-12 21:20:46 +0200630 start = ftrace_now(raw_smp_processor_id());
Steven Rostedt3d083392008-05-12 21:20:42 +0200631 ftrace_update_cnt = 0;
632
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400633 list_for_each_entry_safe(p, t, &ftrace_new_addrs, list) {
Abhishek Sagarf22f9a82008-06-21 23:50:29 +0530634
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400635 /* If something went wrong, bail without enabling anything */
636 if (unlikely(ftrace_disabled))
637 return -1;
Steven Rostedt3d083392008-05-12 21:20:42 +0200638
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400639 list_del_init(&p->list);
Abhishek Sagar0eb96702008-06-01 21:47:30 +0530640
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400641 /* convert record (i.e, patch mcount-call with NOP) */
Steven Rostedt31e88902008-11-14 16:21:19 -0800642 if (ftrace_code_disable(mod, p)) {
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400643 p->flags |= FTRACE_FL_CONVERTED;
644 ftrace_update_cnt++;
645 } else
646 ftrace_free_rec(p);
Steven Rostedt3d083392008-05-12 21:20:42 +0200647 }
648
Ingo Molnar750ed1a2008-05-12 21:20:46 +0200649 stop = ftrace_now(raw_smp_processor_id());
Steven Rostedt3d083392008-05-12 21:20:42 +0200650 ftrace_update_time = stop - start;
651 ftrace_update_tot_cnt += ftrace_update_cnt;
652
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +0200653 return 0;
654}
655
Steven Rostedt68bf21a2008-08-14 15:45:08 -0400656static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200657{
658 struct ftrace_page *pg;
659 int cnt;
660 int i;
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200661
662 /* allocate a few pages */
663 ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
664 if (!ftrace_pages_start)
665 return -1;
666
667 /*
668 * Allocate a few more pages.
669 *
670 * TODO: have some parser search vmlinux before
671 * final linking to find all calls to ftrace.
672 * Then we can:
673 * a) know how many pages to allocate.
674 * and/or
675 * b) set up the table then.
676 *
677 * The dynamic code is still necessary for
678 * modules.
679 */
680
681 pg = ftrace_pages = ftrace_pages_start;
682
Steven Rostedt68bf21a2008-08-14 15:45:08 -0400683 cnt = num_to_init / ENTRIES_PER_PAGE;
Steven Rostedt08f5ac902008-10-23 09:33:07 -0400684 pr_info("ftrace: allocating %ld entries in %d pages\n",
Steven Rostedt68bf21a2008-08-14 15:45:08 -0400685 num_to_init, cnt);
Steven Rostedt3c1720f2008-05-12 21:20:43 +0200686
687 for (i = 0; i < cnt; i++) {
688 pg->next = (void *)get_zeroed_page(GFP_KERNEL);
689
690 /* If we fail, we'll try later anyway */
691 if (!pg->next)
692 break;
693
694 pg = pg->next;
695 }
696
697 return 0;
698}
699
Steven Rostedt5072c592008-05-12 21:20:43 +0200700enum {
701 FTRACE_ITER_FILTER = (1 << 0),
702 FTRACE_ITER_CONT = (1 << 1),
Steven Rostedt41c52c02008-05-22 11:46:33 -0400703 FTRACE_ITER_NOTRACE = (1 << 2),
Abhishek Sagareb9a7bf2008-06-01 21:47:54 +0530704 FTRACE_ITER_FAILURES = (1 << 3),
Steven Rostedt5072c592008-05-12 21:20:43 +0200705};
706
707#define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */
708
709struct ftrace_iterator {
710 loff_t pos;
711 struct ftrace_page *pg;
712 unsigned idx;
713 unsigned flags;
714 unsigned char buffer[FTRACE_BUFF_MAX+1];
715 unsigned buffer_idx;
716 unsigned filtered;
717};
718
Ingo Molnare309b412008-05-12 21:20:51 +0200719static void *
Steven Rostedt5072c592008-05-12 21:20:43 +0200720t_next(struct seq_file *m, void *v, loff_t *pos)
721{
722 struct ftrace_iterator *iter = m->private;
723 struct dyn_ftrace *rec = NULL;
724
725 (*pos)++;
726
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400727 /* should not be called from interrupt context */
728 spin_lock(&ftrace_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +0200729 retry:
730 if (iter->idx >= iter->pg->index) {
731 if (iter->pg->next) {
732 iter->pg = iter->pg->next;
733 iter->idx = 0;
734 goto retry;
735 }
736 } else {
737 rec = &iter->pg->records[iter->idx++];
Steven Rostedta9fdda32008-08-14 22:47:17 -0400738 if ((rec->flags & FTRACE_FL_FREE) ||
739
740 (!(iter->flags & FTRACE_ITER_FAILURES) &&
Abhishek Sagareb9a7bf2008-06-01 21:47:54 +0530741 (rec->flags & FTRACE_FL_FAILED)) ||
742
743 ((iter->flags & FTRACE_ITER_FAILURES) &&
Steven Rostedta9fdda32008-08-14 22:47:17 -0400744 !(rec->flags & FTRACE_FL_FAILED)) ||
Abhishek Sagareb9a7bf2008-06-01 21:47:54 +0530745
Steven Rostedt0183fb12008-11-07 22:36:02 -0500746 ((iter->flags & FTRACE_ITER_FILTER) &&
747 !(rec->flags & FTRACE_FL_FILTER)) ||
748
Steven Rostedt41c52c02008-05-22 11:46:33 -0400749 ((iter->flags & FTRACE_ITER_NOTRACE) &&
750 !(rec->flags & FTRACE_FL_NOTRACE))) {
Steven Rostedt5072c592008-05-12 21:20:43 +0200751 rec = NULL;
752 goto retry;
753 }
754 }
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400755 spin_unlock(&ftrace_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +0200756
757 iter->pos = *pos;
758
759 return rec;
760}
761
762static void *t_start(struct seq_file *m, loff_t *pos)
763{
764 struct ftrace_iterator *iter = m->private;
765 void *p = NULL;
766 loff_t l = -1;
767
768 if (*pos != iter->pos) {
769 for (p = t_next(m, p, &l); p && l < *pos; p = t_next(m, p, &l))
770 ;
771 } else {
772 l = *pos;
773 p = t_next(m, p, &l);
774 }
775
776 return p;
777}
778
779static void t_stop(struct seq_file *m, void *p)
780{
781}
782
783static int t_show(struct seq_file *m, void *v)
784{
785 struct dyn_ftrace *rec = v;
786 char str[KSYM_SYMBOL_LEN];
787
788 if (!rec)
789 return 0;
790
791 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
792
793 seq_printf(m, "%s\n", str);
794
795 return 0;
796}
797
798static struct seq_operations show_ftrace_seq_ops = {
799 .start = t_start,
800 .next = t_next,
801 .stop = t_stop,
802 .show = t_show,
803};
804
Ingo Molnare309b412008-05-12 21:20:51 +0200805static int
Steven Rostedt5072c592008-05-12 21:20:43 +0200806ftrace_avail_open(struct inode *inode, struct file *file)
807{
808 struct ftrace_iterator *iter;
809 int ret;
810
Steven Rostedt4eebcc82008-05-12 21:20:48 +0200811 if (unlikely(ftrace_disabled))
812 return -ENODEV;
813
Steven Rostedt5072c592008-05-12 21:20:43 +0200814 iter = kzalloc(sizeof(*iter), GFP_KERNEL);
815 if (!iter)
816 return -ENOMEM;
817
818 iter->pg = ftrace_pages_start;
819 iter->pos = -1;
820
821 ret = seq_open(file, &show_ftrace_seq_ops);
822 if (!ret) {
823 struct seq_file *m = file->private_data;
Ingo Molnar4bf39a92008-05-12 21:20:46 +0200824
Steven Rostedt5072c592008-05-12 21:20:43 +0200825 m->private = iter;
Ingo Molnar4bf39a92008-05-12 21:20:46 +0200826 } else {
Steven Rostedt5072c592008-05-12 21:20:43 +0200827 kfree(iter);
Ingo Molnar4bf39a92008-05-12 21:20:46 +0200828 }
Steven Rostedt5072c592008-05-12 21:20:43 +0200829
830 return ret;
831}
832
833int ftrace_avail_release(struct inode *inode, struct file *file)
834{
835 struct seq_file *m = (struct seq_file *)file->private_data;
836 struct ftrace_iterator *iter = m->private;
837
838 seq_release(inode, file);
839 kfree(iter);
Ingo Molnar4bf39a92008-05-12 21:20:46 +0200840
Steven Rostedt5072c592008-05-12 21:20:43 +0200841 return 0;
842}
843
Abhishek Sagareb9a7bf2008-06-01 21:47:54 +0530844static int
845ftrace_failures_open(struct inode *inode, struct file *file)
846{
847 int ret;
848 struct seq_file *m;
849 struct ftrace_iterator *iter;
850
851 ret = ftrace_avail_open(inode, file);
852 if (!ret) {
853 m = (struct seq_file *)file->private_data;
854 iter = (struct ftrace_iterator *)m->private;
855 iter->flags = FTRACE_ITER_FAILURES;
856 }
857
858 return ret;
859}
860
861
Steven Rostedt41c52c02008-05-22 11:46:33 -0400862static void ftrace_filter_reset(int enable)
Steven Rostedt5072c592008-05-12 21:20:43 +0200863{
864 struct ftrace_page *pg;
865 struct dyn_ftrace *rec;
Steven Rostedt41c52c02008-05-22 11:46:33 -0400866 unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
Steven Rostedt5072c592008-05-12 21:20:43 +0200867 unsigned i;
868
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400869 /* should not be called from interrupt context */
870 spin_lock(&ftrace_lock);
Steven Rostedt41c52c02008-05-22 11:46:33 -0400871 if (enable)
872 ftrace_filtered = 0;
Steven Rostedt5072c592008-05-12 21:20:43 +0200873 pg = ftrace_pages_start;
874 while (pg) {
875 for (i = 0; i < pg->index; i++) {
876 rec = &pg->records[i];
877 if (rec->flags & FTRACE_FL_FAILED)
878 continue;
Steven Rostedt41c52c02008-05-22 11:46:33 -0400879 rec->flags &= ~type;
Steven Rostedt5072c592008-05-12 21:20:43 +0200880 }
881 pg = pg->next;
882 }
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400883 spin_unlock(&ftrace_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +0200884}
885
Ingo Molnare309b412008-05-12 21:20:51 +0200886static int
Steven Rostedt41c52c02008-05-22 11:46:33 -0400887ftrace_regex_open(struct inode *inode, struct file *file, int enable)
Steven Rostedt5072c592008-05-12 21:20:43 +0200888{
889 struct ftrace_iterator *iter;
890 int ret = 0;
891
Steven Rostedt4eebcc82008-05-12 21:20:48 +0200892 if (unlikely(ftrace_disabled))
893 return -ENODEV;
894
Steven Rostedt5072c592008-05-12 21:20:43 +0200895 iter = kzalloc(sizeof(*iter), GFP_KERNEL);
896 if (!iter)
897 return -ENOMEM;
898
Steven Rostedt41c52c02008-05-22 11:46:33 -0400899 mutex_lock(&ftrace_regex_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +0200900 if ((file->f_mode & FMODE_WRITE) &&
901 !(file->f_flags & O_APPEND))
Steven Rostedt41c52c02008-05-22 11:46:33 -0400902 ftrace_filter_reset(enable);
Steven Rostedt5072c592008-05-12 21:20:43 +0200903
904 if (file->f_mode & FMODE_READ) {
905 iter->pg = ftrace_pages_start;
906 iter->pos = -1;
Steven Rostedt41c52c02008-05-22 11:46:33 -0400907 iter->flags = enable ? FTRACE_ITER_FILTER :
908 FTRACE_ITER_NOTRACE;
Steven Rostedt5072c592008-05-12 21:20:43 +0200909
910 ret = seq_open(file, &show_ftrace_seq_ops);
911 if (!ret) {
912 struct seq_file *m = file->private_data;
913 m->private = iter;
914 } else
915 kfree(iter);
916 } else
917 file->private_data = iter;
Steven Rostedt41c52c02008-05-22 11:46:33 -0400918 mutex_unlock(&ftrace_regex_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +0200919
920 return ret;
921}
922
Steven Rostedt41c52c02008-05-22 11:46:33 -0400923static int
924ftrace_filter_open(struct inode *inode, struct file *file)
925{
926 return ftrace_regex_open(inode, file, 1);
927}
928
929static int
930ftrace_notrace_open(struct inode *inode, struct file *file)
931{
932 return ftrace_regex_open(inode, file, 0);
933}
934
Ingo Molnare309b412008-05-12 21:20:51 +0200935static ssize_t
Steven Rostedt41c52c02008-05-22 11:46:33 -0400936ftrace_regex_read(struct file *file, char __user *ubuf,
Steven Rostedt5072c592008-05-12 21:20:43 +0200937 size_t cnt, loff_t *ppos)
938{
939 if (file->f_mode & FMODE_READ)
940 return seq_read(file, ubuf, cnt, ppos);
941 else
942 return -EPERM;
943}
944
Ingo Molnare309b412008-05-12 21:20:51 +0200945static loff_t
Steven Rostedt41c52c02008-05-22 11:46:33 -0400946ftrace_regex_lseek(struct file *file, loff_t offset, int origin)
Steven Rostedt5072c592008-05-12 21:20:43 +0200947{
948 loff_t ret;
949
950 if (file->f_mode & FMODE_READ)
951 ret = seq_lseek(file, offset, origin);
952 else
953 file->f_pos = ret = 1;
954
955 return ret;
956}
957
958enum {
959 MATCH_FULL,
960 MATCH_FRONT_ONLY,
961 MATCH_MIDDLE_ONLY,
962 MATCH_END_ONLY,
963};
964
Ingo Molnare309b412008-05-12 21:20:51 +0200965static void
Steven Rostedt41c52c02008-05-22 11:46:33 -0400966ftrace_match(unsigned char *buff, int len, int enable)
Steven Rostedt5072c592008-05-12 21:20:43 +0200967{
968 char str[KSYM_SYMBOL_LEN];
969 char *search = NULL;
970 struct ftrace_page *pg;
971 struct dyn_ftrace *rec;
972 int type = MATCH_FULL;
Steven Rostedt41c52c02008-05-22 11:46:33 -0400973 unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
Steven Rostedt5072c592008-05-12 21:20:43 +0200974 unsigned i, match = 0, search_len = 0;
975
976 for (i = 0; i < len; i++) {
977 if (buff[i] == '*') {
978 if (!i) {
979 search = buff + i + 1;
980 type = MATCH_END_ONLY;
981 search_len = len - (i + 1);
982 } else {
983 if (type == MATCH_END_ONLY) {
984 type = MATCH_MIDDLE_ONLY;
985 } else {
986 match = i;
987 type = MATCH_FRONT_ONLY;
988 }
989 buff[i] = 0;
990 break;
991 }
992 }
993 }
994
Steven Rostedt99ecdc42008-08-15 21:40:05 -0400995 /* should not be called from interrupt context */
996 spin_lock(&ftrace_lock);
Steven Rostedt41c52c02008-05-22 11:46:33 -0400997 if (enable)
998 ftrace_filtered = 1;
Steven Rostedt5072c592008-05-12 21:20:43 +0200999 pg = ftrace_pages_start;
1000 while (pg) {
1001 for (i = 0; i < pg->index; i++) {
1002 int matched = 0;
1003 char *ptr;
1004
1005 rec = &pg->records[i];
1006 if (rec->flags & FTRACE_FL_FAILED)
1007 continue;
1008 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
1009 switch (type) {
1010 case MATCH_FULL:
1011 if (strcmp(str, buff) == 0)
1012 matched = 1;
1013 break;
1014 case MATCH_FRONT_ONLY:
1015 if (memcmp(str, buff, match) == 0)
1016 matched = 1;
1017 break;
1018 case MATCH_MIDDLE_ONLY:
1019 if (strstr(str, search))
1020 matched = 1;
1021 break;
1022 case MATCH_END_ONLY:
1023 ptr = strstr(str, search);
1024 if (ptr && (ptr[search_len] == 0))
1025 matched = 1;
1026 break;
1027 }
1028 if (matched)
Steven Rostedt41c52c02008-05-22 11:46:33 -04001029 rec->flags |= flag;
Steven Rostedt5072c592008-05-12 21:20:43 +02001030 }
1031 pg = pg->next;
1032 }
Steven Rostedt99ecdc42008-08-15 21:40:05 -04001033 spin_unlock(&ftrace_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +02001034}
1035
Ingo Molnare309b412008-05-12 21:20:51 +02001036static ssize_t
Steven Rostedt41c52c02008-05-22 11:46:33 -04001037ftrace_regex_write(struct file *file, const char __user *ubuf,
1038 size_t cnt, loff_t *ppos, int enable)
Steven Rostedt5072c592008-05-12 21:20:43 +02001039{
1040 struct ftrace_iterator *iter;
1041 char ch;
1042 size_t read = 0;
1043 ssize_t ret;
1044
1045 if (!cnt || cnt < 0)
1046 return 0;
1047
Steven Rostedt41c52c02008-05-22 11:46:33 -04001048 mutex_lock(&ftrace_regex_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +02001049
1050 if (file->f_mode & FMODE_READ) {
1051 struct seq_file *m = file->private_data;
1052 iter = m->private;
1053 } else
1054 iter = file->private_data;
1055
1056 if (!*ppos) {
1057 iter->flags &= ~FTRACE_ITER_CONT;
1058 iter->buffer_idx = 0;
1059 }
1060
1061 ret = get_user(ch, ubuf++);
1062 if (ret)
1063 goto out;
1064 read++;
1065 cnt--;
1066
1067 if (!(iter->flags & ~FTRACE_ITER_CONT)) {
1068 /* skip white space */
1069 while (cnt && isspace(ch)) {
1070 ret = get_user(ch, ubuf++);
1071 if (ret)
1072 goto out;
1073 read++;
1074 cnt--;
1075 }
1076
Steven Rostedt5072c592008-05-12 21:20:43 +02001077 if (isspace(ch)) {
1078 file->f_pos += read;
1079 ret = read;
1080 goto out;
1081 }
1082
1083 iter->buffer_idx = 0;
1084 }
1085
1086 while (cnt && !isspace(ch)) {
1087 if (iter->buffer_idx < FTRACE_BUFF_MAX)
1088 iter->buffer[iter->buffer_idx++] = ch;
1089 else {
1090 ret = -EINVAL;
1091 goto out;
1092 }
1093 ret = get_user(ch, ubuf++);
1094 if (ret)
1095 goto out;
1096 read++;
1097 cnt--;
1098 }
1099
1100 if (isspace(ch)) {
1101 iter->filtered++;
1102 iter->buffer[iter->buffer_idx] = 0;
Steven Rostedt41c52c02008-05-22 11:46:33 -04001103 ftrace_match(iter->buffer, iter->buffer_idx, enable);
Steven Rostedt5072c592008-05-12 21:20:43 +02001104 iter->buffer_idx = 0;
1105 } else
1106 iter->flags |= FTRACE_ITER_CONT;
1107
1108
1109 file->f_pos += read;
1110
1111 ret = read;
1112 out:
Steven Rostedt41c52c02008-05-22 11:46:33 -04001113 mutex_unlock(&ftrace_regex_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +02001114
1115 return ret;
1116}
1117
Steven Rostedt41c52c02008-05-22 11:46:33 -04001118static ssize_t
1119ftrace_filter_write(struct file *file, const char __user *ubuf,
1120 size_t cnt, loff_t *ppos)
1121{
1122 return ftrace_regex_write(file, ubuf, cnt, ppos, 1);
1123}
1124
1125static ssize_t
1126ftrace_notrace_write(struct file *file, const char __user *ubuf,
1127 size_t cnt, loff_t *ppos)
1128{
1129 return ftrace_regex_write(file, ubuf, cnt, ppos, 0);
1130}
1131
1132static void
1133ftrace_set_regex(unsigned char *buf, int len, int reset, int enable)
1134{
1135 if (unlikely(ftrace_disabled))
1136 return;
1137
1138 mutex_lock(&ftrace_regex_lock);
1139 if (reset)
1140 ftrace_filter_reset(enable);
1141 if (buf)
1142 ftrace_match(buf, len, enable);
1143 mutex_unlock(&ftrace_regex_lock);
1144}
1145
Steven Rostedt77a2b372008-05-12 21:20:45 +02001146/**
1147 * ftrace_set_filter - set a function to filter on in ftrace
1148 * @buf - the string that holds the function filter text.
1149 * @len - the length of the string.
1150 * @reset - non zero to reset all filters before applying this filter.
1151 *
1152 * Filters denote which functions should be enabled when tracing is enabled.
1153 * If @buf is NULL and reset is set, all functions will be enabled for tracing.
1154 */
Ingo Molnare309b412008-05-12 21:20:51 +02001155void ftrace_set_filter(unsigned char *buf, int len, int reset)
Steven Rostedt77a2b372008-05-12 21:20:45 +02001156{
Steven Rostedt41c52c02008-05-22 11:46:33 -04001157 ftrace_set_regex(buf, len, reset, 1);
1158}
Steven Rostedt4eebcc82008-05-12 21:20:48 +02001159
Steven Rostedt41c52c02008-05-22 11:46:33 -04001160/**
1161 * ftrace_set_notrace - set a function to not trace in ftrace
1162 * @buf - the string that holds the function notrace text.
1163 * @len - the length of the string.
1164 * @reset - non zero to reset all filters before applying this filter.
1165 *
1166 * Notrace Filters denote which functions should not be enabled when tracing
1167 * is enabled. If @buf is NULL and reset is set, all functions will be enabled
1168 * for tracing.
1169 */
1170void ftrace_set_notrace(unsigned char *buf, int len, int reset)
1171{
1172 ftrace_set_regex(buf, len, reset, 0);
Steven Rostedt77a2b372008-05-12 21:20:45 +02001173}
1174
Ingo Molnare309b412008-05-12 21:20:51 +02001175static int
Steven Rostedt41c52c02008-05-22 11:46:33 -04001176ftrace_regex_release(struct inode *inode, struct file *file, int enable)
Steven Rostedt5072c592008-05-12 21:20:43 +02001177{
1178 struct seq_file *m = (struct seq_file *)file->private_data;
1179 struct ftrace_iterator *iter;
1180
Steven Rostedt41c52c02008-05-22 11:46:33 -04001181 mutex_lock(&ftrace_regex_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +02001182 if (file->f_mode & FMODE_READ) {
1183 iter = m->private;
1184
1185 seq_release(inode, file);
1186 } else
1187 iter = file->private_data;
1188
1189 if (iter->buffer_idx) {
1190 iter->filtered++;
1191 iter->buffer[iter->buffer_idx] = 0;
Steven Rostedt41c52c02008-05-22 11:46:33 -04001192 ftrace_match(iter->buffer, iter->buffer_idx, enable);
Steven Rostedt5072c592008-05-12 21:20:43 +02001193 }
1194
1195 mutex_lock(&ftrace_sysctl_lock);
Steven Rostedtcb7be3b2008-10-23 09:33:05 -04001196 mutex_lock(&ftrace_start_lock);
Steven Rostedtee02a2e2008-11-15 16:31:41 -05001197 if (ftrace_start_up && ftrace_enabled)
Steven Rostedt5072c592008-05-12 21:20:43 +02001198 ftrace_run_update_code(FTRACE_ENABLE_CALLS);
Steven Rostedtcb7be3b2008-10-23 09:33:05 -04001199 mutex_unlock(&ftrace_start_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +02001200 mutex_unlock(&ftrace_sysctl_lock);
1201
1202 kfree(iter);
Steven Rostedt41c52c02008-05-22 11:46:33 -04001203 mutex_unlock(&ftrace_regex_lock);
Steven Rostedt5072c592008-05-12 21:20:43 +02001204 return 0;
1205}
1206
Steven Rostedt41c52c02008-05-22 11:46:33 -04001207static int
1208ftrace_filter_release(struct inode *inode, struct file *file)
1209{
1210 return ftrace_regex_release(inode, file, 1);
1211}
1212
1213static int
1214ftrace_notrace_release(struct inode *inode, struct file *file)
1215{
1216 return ftrace_regex_release(inode, file, 0);
1217}
1218
Steven Rostedt5072c592008-05-12 21:20:43 +02001219static struct file_operations ftrace_avail_fops = {
1220 .open = ftrace_avail_open,
1221 .read = seq_read,
1222 .llseek = seq_lseek,
1223 .release = ftrace_avail_release,
1224};
1225
Abhishek Sagareb9a7bf2008-06-01 21:47:54 +05301226static struct file_operations ftrace_failures_fops = {
1227 .open = ftrace_failures_open,
1228 .read = seq_read,
1229 .llseek = seq_lseek,
1230 .release = ftrace_avail_release,
1231};
1232
Steven Rostedt5072c592008-05-12 21:20:43 +02001233static struct file_operations ftrace_filter_fops = {
1234 .open = ftrace_filter_open,
Steven Rostedt41c52c02008-05-22 11:46:33 -04001235 .read = ftrace_regex_read,
Steven Rostedt5072c592008-05-12 21:20:43 +02001236 .write = ftrace_filter_write,
Steven Rostedt41c52c02008-05-22 11:46:33 -04001237 .llseek = ftrace_regex_lseek,
Steven Rostedt5072c592008-05-12 21:20:43 +02001238 .release = ftrace_filter_release,
1239};
1240
Steven Rostedt41c52c02008-05-22 11:46:33 -04001241static struct file_operations ftrace_notrace_fops = {
1242 .open = ftrace_notrace_open,
1243 .read = ftrace_regex_read,
1244 .write = ftrace_notrace_write,
1245 .llseek = ftrace_regex_lseek,
1246 .release = ftrace_notrace_release,
1247};
1248
Steven Rostedt5072c592008-05-12 21:20:43 +02001249static __init int ftrace_init_debugfs(void)
1250{
1251 struct dentry *d_tracer;
1252 struct dentry *entry;
1253
1254 d_tracer = tracing_init_dentry();
1255
1256 entry = debugfs_create_file("available_filter_functions", 0444,
1257 d_tracer, NULL, &ftrace_avail_fops);
1258 if (!entry)
1259 pr_warning("Could not create debugfs "
1260 "'available_filter_functions' entry\n");
1261
Abhishek Sagareb9a7bf2008-06-01 21:47:54 +05301262 entry = debugfs_create_file("failures", 0444,
1263 d_tracer, NULL, &ftrace_failures_fops);
1264 if (!entry)
1265 pr_warning("Could not create debugfs 'failures' entry\n");
1266
Steven Rostedt5072c592008-05-12 21:20:43 +02001267 entry = debugfs_create_file("set_ftrace_filter", 0644, d_tracer,
1268 NULL, &ftrace_filter_fops);
1269 if (!entry)
1270 pr_warning("Could not create debugfs "
1271 "'set_ftrace_filter' entry\n");
Steven Rostedt41c52c02008-05-22 11:46:33 -04001272
1273 entry = debugfs_create_file("set_ftrace_notrace", 0644, d_tracer,
1274 NULL, &ftrace_notrace_fops);
1275 if (!entry)
1276 pr_warning("Could not create debugfs "
1277 "'set_ftrace_notrace' entry\n");
Steven Rostedtad90c0e2008-05-27 20:48:37 -04001278
Steven Rostedt5072c592008-05-12 21:20:43 +02001279 return 0;
1280}
1281
1282fs_initcall(ftrace_init_debugfs);
1283
Steven Rostedt31e88902008-11-14 16:21:19 -08001284static int ftrace_convert_nops(struct module *mod,
1285 unsigned long *start,
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001286 unsigned long *end)
1287{
1288 unsigned long *p;
1289 unsigned long addr;
1290 unsigned long flags;
1291
Steven Rostedt08f5ac902008-10-23 09:33:07 -04001292 mutex_lock(&ftrace_start_lock);
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001293 p = start;
1294 while (p < end) {
1295 addr = ftrace_call_adjust(*p++);
Steven Rostedt20e52272008-11-14 16:21:19 -08001296 /*
1297 * Some architecture linkers will pad between
1298 * the different mcount_loc sections of different
1299 * object files to satisfy alignments.
1300 * Skip any NULL pointers.
1301 */
1302 if (!addr)
1303 continue;
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001304 ftrace_record_ip(addr);
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001305 }
1306
Steven Rostedt08f5ac902008-10-23 09:33:07 -04001307 /* disable interrupts to prevent kstop machine */
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001308 local_irq_save(flags);
Steven Rostedt31e88902008-11-14 16:21:19 -08001309 ftrace_update_code(mod);
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001310 local_irq_restore(flags);
Steven Rostedt08f5ac902008-10-23 09:33:07 -04001311 mutex_unlock(&ftrace_start_lock);
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001312
1313 return 0;
1314}
1315
Steven Rostedt31e88902008-11-14 16:21:19 -08001316void ftrace_init_module(struct module *mod,
1317 unsigned long *start, unsigned long *end)
Steven Rostedt90d595f2008-08-14 15:45:09 -04001318{
Steven Rostedt00fd61a2008-08-15 21:40:04 -04001319 if (ftrace_disabled || start == end)
Steven Rostedtfed19392008-08-14 22:47:19 -04001320 return;
Steven Rostedt31e88902008-11-14 16:21:19 -08001321 ftrace_convert_nops(mod, start, end);
Steven Rostedt90d595f2008-08-14 15:45:09 -04001322}
1323
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001324extern unsigned long __start_mcount_loc[];
1325extern unsigned long __stop_mcount_loc[];
1326
1327void __init ftrace_init(void)
1328{
1329 unsigned long count, addr, flags;
1330 int ret;
1331
1332 /* Keep the ftrace pointer to the stub */
1333 addr = (unsigned long)ftrace_stub;
1334
1335 local_irq_save(flags);
1336 ftrace_dyn_arch_init(&addr);
1337 local_irq_restore(flags);
1338
1339 /* ftrace_dyn_arch_init places the return code in addr */
1340 if (addr)
1341 goto failed;
1342
1343 count = __stop_mcount_loc - __start_mcount_loc;
1344
1345 ret = ftrace_dyn_table_alloc(count);
1346 if (ret)
1347 goto failed;
1348
1349 last_ftrace_enabled = ftrace_enabled = 1;
1350
Steven Rostedt31e88902008-11-14 16:21:19 -08001351 ret = ftrace_convert_nops(NULL,
1352 __start_mcount_loc,
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001353 __stop_mcount_loc);
1354
1355 return;
1356 failed:
1357 ftrace_disabled = 1;
1358}
Steven Rostedt68bf21a2008-08-14 15:45:08 -04001359
Steven Rostedt3d083392008-05-12 21:20:42 +02001360#else
Frederic Weisbecker0b6e4d52008-10-28 20:17:38 +01001361
1362static int __init ftrace_nodyn_init(void)
1363{
1364 ftrace_enabled = 1;
1365 return 0;
1366}
1367device_initcall(ftrace_nodyn_init);
1368
Ingo Molnarc7aafc52008-05-12 21:20:45 +02001369# define ftrace_startup() do { } while (0)
1370# define ftrace_shutdown() do { } while (0)
1371# define ftrace_startup_sysctl() do { } while (0)
1372# define ftrace_shutdown_sysctl() do { } while (0)
Steven Rostedt3d083392008-05-12 21:20:42 +02001373#endif /* CONFIG_DYNAMIC_FTRACE */
1374
1375/**
Steven Rostedt81adbdc2008-10-23 09:33:02 -04001376 * ftrace_kill - kill ftrace
Steven Rostedta2bb6a32008-07-10 20:58:15 -04001377 *
1378 * This function should be used by panic code. It stops ftrace
1379 * but in a not so nice way. If you need to simply kill ftrace
1380 * from a non-atomic section, use ftrace_kill.
1381 */
Steven Rostedt81adbdc2008-10-23 09:33:02 -04001382void ftrace_kill(void)
Steven Rostedta2bb6a32008-07-10 20:58:15 -04001383{
1384 ftrace_disabled = 1;
1385 ftrace_enabled = 0;
Steven Rostedta2bb6a32008-07-10 20:58:15 -04001386 clear_ftrace_function();
1387}
1388
1389/**
Steven Rostedt3d083392008-05-12 21:20:42 +02001390 * register_ftrace_function - register a function for profiling
1391 * @ops - ops structure that holds the function for profiling.
1392 *
1393 * Register a function to be called by all functions in the
1394 * kernel.
1395 *
1396 * Note: @ops->func and all the functions it calls must be labeled
1397 * with "notrace", otherwise it will go into a
1398 * recursive loop.
1399 */
1400int register_ftrace_function(struct ftrace_ops *ops)
1401{
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001402 int ret;
1403
Steven Rostedt4eebcc82008-05-12 21:20:48 +02001404 if (unlikely(ftrace_disabled))
1405 return -1;
1406
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001407 mutex_lock(&ftrace_sysctl_lock);
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001408 ret = __register_ftrace_function(ops);
Steven Rostedtd61f82d2008-05-12 21:20:43 +02001409 ftrace_startup();
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001410 mutex_unlock(&ftrace_sysctl_lock);
1411
1412 return ret;
Steven Rostedt3d083392008-05-12 21:20:42 +02001413}
1414
1415/**
1416 * unregister_ftrace_function - unresgister a function for profiling.
1417 * @ops - ops structure that holds the function to unregister
1418 *
1419 * Unregister a function that was added to be called by ftrace profiling.
1420 */
1421int unregister_ftrace_function(struct ftrace_ops *ops)
1422{
1423 int ret;
1424
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001425 mutex_lock(&ftrace_sysctl_lock);
Steven Rostedt3d083392008-05-12 21:20:42 +02001426 ret = __unregister_ftrace_function(ops);
Steven Rostedtd61f82d2008-05-12 21:20:43 +02001427 ftrace_shutdown();
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001428 mutex_unlock(&ftrace_sysctl_lock);
1429
1430 return ret;
1431}
1432
Ingo Molnare309b412008-05-12 21:20:51 +02001433int
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001434ftrace_enable_sysctl(struct ctl_table *table, int write,
Steven Rostedt5072c592008-05-12 21:20:43 +02001435 struct file *file, void __user *buffer, size_t *lenp,
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001436 loff_t *ppos)
1437{
1438 int ret;
1439
Steven Rostedt4eebcc82008-05-12 21:20:48 +02001440 if (unlikely(ftrace_disabled))
1441 return -ENODEV;
1442
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001443 mutex_lock(&ftrace_sysctl_lock);
1444
Steven Rostedt5072c592008-05-12 21:20:43 +02001445 ret = proc_dointvec(table, write, file, buffer, lenp, ppos);
Steven Rostedtb0fc4942008-05-12 21:20:43 +02001446
1447 if (ret || !write || (last_ftrace_enabled == ftrace_enabled))
1448 goto out;
1449
1450 last_ftrace_enabled = ftrace_enabled;
1451
1452 if (ftrace_enabled) {
1453
1454 ftrace_startup_sysctl();
1455
1456 /* we are starting ftrace again */
1457 if (ftrace_list != &ftrace_list_end) {
1458 if (ftrace_list->next == &ftrace_list_end)
1459 ftrace_trace_function = ftrace_list->func;
1460 else
1461 ftrace_trace_function = ftrace_list_func;
1462 }
1463
1464 } else {
1465 /* stopping ftrace calls (just send to ftrace_stub) */
1466 ftrace_trace_function = ftrace_stub;
1467
1468 ftrace_shutdown_sysctl();
1469 }
1470
1471 out:
1472 mutex_unlock(&ftrace_sysctl_lock);
Steven Rostedt3d083392008-05-12 21:20:42 +02001473 return ret;
Arnaldo Carvalho de Melo16444a82008-05-12 21:20:42 +02001474}
Ingo Molnarf17845e2008-10-24 12:47:10 +02001475
Frederic Weisbecker15e6cb32008-11-11 07:14:25 +01001476#ifdef CONFIG_FUNCTION_RET_TRACER
1477trace_function_return_t ftrace_function_return =
1478 (trace_function_return_t)ftrace_stub;
1479void register_ftrace_return(trace_function_return_t func)
1480{
1481 ftrace_function_return = func;
1482}
1483
1484void unregister_ftrace_return(void)
1485{
1486 ftrace_function_return = (trace_function_return_t)ftrace_stub;
1487}
1488#endif
1489
1490
1491