aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c68
1 files changed, 61 insertions, 7 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 7847806eefef..1752a63f37c0 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -29,6 +29,8 @@
29#include <linux/list.h> 29#include <linux/list.h>
30#include <linux/hash.h> 30#include <linux/hash.h>
31 31
32#include <trace/sched.h>
33
32#include <asm/ftrace.h> 34#include <asm/ftrace.h>
33 35
34#include "trace.h" 36#include "trace.h"
@@ -339,7 +341,7 @@ static inline int record_frozen(struct dyn_ftrace *rec)
339 341
340static void ftrace_free_rec(struct dyn_ftrace *rec) 342static void ftrace_free_rec(struct dyn_ftrace *rec)
341{ 343{
342 rec->ip = (unsigned long)ftrace_free_records; 344 rec->freelist = ftrace_free_records;
343 ftrace_free_records = rec; 345 ftrace_free_records = rec;
344 rec->flags |= FTRACE_FL_FREE; 346 rec->flags |= FTRACE_FL_FREE;
345} 347}
@@ -356,9 +358,14 @@ void ftrace_release(void *start, unsigned long size)
356 358
357 mutex_lock(&ftrace_lock); 359 mutex_lock(&ftrace_lock);
358 do_for_each_ftrace_rec(pg, rec) { 360 do_for_each_ftrace_rec(pg, rec) {
359 if ((rec->ip >= s) && (rec->ip < e) && 361 if ((rec->ip >= s) && (rec->ip < e)) {
360 !(rec->flags & FTRACE_FL_FREE)) 362 /*
363 * rec->ip is changed in ftrace_free_rec()
364 * It should not between s and e if record was freed.
365 */
366 FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE);
361 ftrace_free_rec(rec); 367 ftrace_free_rec(rec);
368 }
362 } while_for_each_ftrace_rec(); 369 } while_for_each_ftrace_rec();
363 mutex_unlock(&ftrace_lock); 370 mutex_unlock(&ftrace_lock);
364} 371}
@@ -377,7 +384,7 @@ static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
377 return NULL; 384 return NULL;
378 } 385 }
379 386
380 ftrace_free_records = (void *)rec->ip; 387 ftrace_free_records = rec->freelist;
381 memset(rec, 0, sizeof(*rec)); 388 memset(rec, 0, sizeof(*rec));
382 return rec; 389 return rec;
383 } 390 }
@@ -409,7 +416,7 @@ ftrace_record_ip(unsigned long ip)
409 return NULL; 416 return NULL;
410 417
411 rec->ip = ip; 418 rec->ip = ip;
412 rec->flags = (unsigned long)ftrace_new_addrs; 419 rec->newlist = ftrace_new_addrs;
413 ftrace_new_addrs = rec; 420 ftrace_new_addrs = rec;
414 421
415 return rec; 422 return rec;
@@ -729,7 +736,7 @@ static int ftrace_update_code(struct module *mod)
729 return -1; 736 return -1;
730 737
731 p = ftrace_new_addrs; 738 p = ftrace_new_addrs;
732 ftrace_new_addrs = (struct dyn_ftrace *)p->flags; 739 ftrace_new_addrs = p->newlist;
733 p->flags = 0L; 740 p->flags = 0L;
734 741
735 /* convert record (i.e, patch mcount-call with NOP) */ 742 /* convert record (i.e, patch mcount-call with NOP) */
@@ -2262,7 +2269,7 @@ ftrace_pid_read(struct file *file, char __user *ubuf,
2262 if (ftrace_pid_trace == ftrace_swapper_pid) 2269 if (ftrace_pid_trace == ftrace_swapper_pid)
2263 r = sprintf(buf, "swapper tasks\n"); 2270 r = sprintf(buf, "swapper tasks\n");
2264 else if (ftrace_pid_trace) 2271 else if (ftrace_pid_trace)
2265 r = sprintf(buf, "%u\n", pid_nr(ftrace_pid_trace)); 2272 r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace));
2266 else 2273 else
2267 r = sprintf(buf, "no pid\n"); 2274 r = sprintf(buf, "no pid\n");
2268 2275
@@ -2590,6 +2597,38 @@ free:
2590 return ret; 2597 return ret;
2591} 2598}
2592 2599
2600static void
2601ftrace_graph_probe_sched_switch(struct rq *__rq, struct task_struct *prev,
2602 struct task_struct *next)
2603{
2604 unsigned long long timestamp;
2605 int index;
2606
2607 /*
2608 * Does the user want to count the time a function was asleep.
2609 * If so, do not update the time stamps.
2610 */
2611 if (trace_flags & TRACE_ITER_SLEEP_TIME)
2612 return;
2613
2614 timestamp = trace_clock_local();
2615
2616 prev->ftrace_timestamp = timestamp;
2617
2618 /* only process tasks that we timestamped */
2619 if (!next->ftrace_timestamp)
2620 return;
2621
2622 /*
2623 * Update all the counters in next to make up for the
2624 * time next was sleeping.
2625 */
2626 timestamp -= next->ftrace_timestamp;
2627
2628 for (index = next->curr_ret_stack; index >= 0; index--)
2629 next->ret_stack[index].calltime += timestamp;
2630}
2631
2593/* Allocate a return stack for each task */ 2632/* Allocate a return stack for each task */
2594static int start_graph_tracing(void) 2633static int start_graph_tracing(void)
2595{ 2634{
@@ -2611,6 +2650,13 @@ static int start_graph_tracing(void)
2611 ret = alloc_retstack_tasklist(ret_stack_list); 2650 ret = alloc_retstack_tasklist(ret_stack_list);
2612 } while (ret == -EAGAIN); 2651 } while (ret == -EAGAIN);
2613 2652
2653 if (!ret) {
2654 ret = register_trace_sched_switch(ftrace_graph_probe_sched_switch);
2655 if (ret)
2656 pr_info("ftrace_graph: Couldn't activate tracepoint"
2657 " probe to kernel_sched_switch\n");
2658 }
2659
2614 kfree(ret_stack_list); 2660 kfree(ret_stack_list);
2615 return ret; 2661 return ret;
2616} 2662}
@@ -2643,6 +2689,12 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
2643 2689
2644 mutex_lock(&ftrace_lock); 2690 mutex_lock(&ftrace_lock);
2645 2691
2692 /* we currently allow only one tracer registered at a time */
2693 if (atomic_read(&ftrace_graph_active)) {
2694 ret = -EBUSY;
2695 goto out;
2696 }
2697
2646 ftrace_suspend_notifier.notifier_call = ftrace_suspend_notifier_call; 2698 ftrace_suspend_notifier.notifier_call = ftrace_suspend_notifier_call;
2647 register_pm_notifier(&ftrace_suspend_notifier); 2699 register_pm_notifier(&ftrace_suspend_notifier);
2648 2700
@@ -2668,6 +2720,7 @@ void unregister_ftrace_graph(void)
2668 mutex_lock(&ftrace_lock); 2720 mutex_lock(&ftrace_lock);
2669 2721
2670 atomic_dec(&ftrace_graph_active); 2722 atomic_dec(&ftrace_graph_active);
2723 unregister_trace_sched_switch(ftrace_graph_probe_sched_switch);
2671 ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; 2724 ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
2672 ftrace_graph_entry = ftrace_graph_entry_stub; 2725 ftrace_graph_entry = ftrace_graph_entry_stub;
2673 ftrace_shutdown(FTRACE_STOP_FUNC_RET); 2726 ftrace_shutdown(FTRACE_STOP_FUNC_RET);
@@ -2688,6 +2741,7 @@ void ftrace_graph_init_task(struct task_struct *t)
2688 t->curr_ret_stack = -1; 2741 t->curr_ret_stack = -1;
2689 atomic_set(&t->tracing_graph_pause, 0); 2742 atomic_set(&t->tracing_graph_pause, 0);
2690 atomic_set(&t->trace_overrun, 0); 2743 atomic_set(&t->trace_overrun, 0);
2744 t->ftrace_timestamp = 0;
2691 } else 2745 } else
2692 t->ret_stack = NULL; 2746 t->ret_stack = NULL;
2693} 2747}