aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r--kernel/trace/trace.c119
1 files changed, 94 insertions, 25 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 4dcc4e85c5..4a87560073 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -27,6 +27,7 @@
27#include <linux/poll.h> 27#include <linux/poll.h>
28#include <linux/gfp.h> 28#include <linux/gfp.h>
29#include <linux/fs.h> 29#include <linux/fs.h>
30#include <linux/kprobes.h>
30#include <linux/writeback.h> 31#include <linux/writeback.h>
31 32
32#include <linux/stacktrace.h> 33#include <linux/stacktrace.h>
@@ -42,11 +43,6 @@ static cpumask_t __read_mostly tracing_buffer_mask;
42#define for_each_tracing_cpu(cpu) \ 43#define for_each_tracing_cpu(cpu) \
43 for_each_cpu_mask(cpu, tracing_buffer_mask) 44 for_each_cpu_mask(cpu, tracing_buffer_mask)
44 45
45/* dummy trace to disable tracing */
46static struct tracer no_tracer __read_mostly = {
47 .name = "none",
48};
49
50static int trace_alloc_page(void); 46static int trace_alloc_page(void);
51static int trace_free_page(void); 47static int trace_free_page(void);
52 48
@@ -134,6 +130,23 @@ static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
134/* trace_flags holds iter_ctrl options */ 130/* trace_flags holds iter_ctrl options */
135unsigned long trace_flags = TRACE_ITER_PRINT_PARENT; 131unsigned long trace_flags = TRACE_ITER_PRINT_PARENT;
136 132
133static notrace void no_trace_init(struct trace_array *tr)
134{
135 int cpu;
136
137 if(tr->ctrl)
138 for_each_online_cpu(cpu)
139 tracing_reset(tr->data[cpu]);
140 tracer_enabled = 0;
141}
142
143/* dummy trace to disable tracing */
144static struct tracer no_tracer __read_mostly = {
145 .name = "none",
146 .init = no_trace_init
147};
148
149
137/** 150/**
138 * trace_wake_up - wake up tasks waiting for trace input 151 * trace_wake_up - wake up tasks waiting for trace input
139 * 152 *
@@ -249,24 +262,32 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
249 tracing_record_cmdline(current); 262 tracing_record_cmdline(current);
250} 263}
251 264
265#define CHECK_COND(cond) \
266 if (unlikely(cond)) { \
267 tracing_disabled = 1; \
268 WARN_ON(1); \
269 return -1; \
270 }
271
252/** 272/**
253 * check_pages - integrity check of trace buffers 273 * check_pages - integrity check of trace buffers
254 * 274 *
255 * As a safty measure we check to make sure the data pages have not 275 * As a safty measure we check to make sure the data pages have not
256 * been corrupted. TODO: configure to disable this because it adds 276 * been corrupted.
257 * a bit of overhead.
258 */ 277 */
259void check_pages(struct trace_array_cpu *data) 278int check_pages(struct trace_array_cpu *data)
260{ 279{
261 struct page *page, *tmp; 280 struct page *page, *tmp;
262 281
263 BUG_ON(data->trace_pages.next->prev != &data->trace_pages); 282 CHECK_COND(data->trace_pages.next->prev != &data->trace_pages);
264 BUG_ON(data->trace_pages.prev->next != &data->trace_pages); 283 CHECK_COND(data->trace_pages.prev->next != &data->trace_pages);
265 284
266 list_for_each_entry_safe(page, tmp, &data->trace_pages, lru) { 285 list_for_each_entry_safe(page, tmp, &data->trace_pages, lru) {
267 BUG_ON(page->lru.next->prev != &page->lru); 286 CHECK_COND(page->lru.next->prev != &page->lru);
268 BUG_ON(page->lru.prev->next != &page->lru); 287 CHECK_COND(page->lru.prev->next != &page->lru);
269 } 288 }
289
290 return 0;
270} 291}
271 292
272/** 293/**
@@ -280,7 +301,6 @@ void *head_page(struct trace_array_cpu *data)
280{ 301{
281 struct page *page; 302 struct page *page;
282 303
283 check_pages(data);
284 if (list_empty(&data->trace_pages)) 304 if (list_empty(&data->trace_pages))
285 return NULL; 305 return NULL;
286 306
@@ -645,9 +665,6 @@ static char saved_cmdlines[SAVED_CMDLINES][TASK_COMM_LEN];
645static int cmdline_idx; 665static int cmdline_idx;
646static DEFINE_SPINLOCK(trace_cmdline_lock); 666static DEFINE_SPINLOCK(trace_cmdline_lock);
647 667
648/* trace in all context switches */
649atomic_t trace_record_cmdline_enabled __read_mostly;
650
651/* temporary disable recording */ 668/* temporary disable recording */
652atomic_t trace_record_cmdline_disabled __read_mostly; 669atomic_t trace_record_cmdline_disabled __read_mostly;
653 670
@@ -976,6 +993,30 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
976 trace_wake_up(); 993 trace_wake_up();
977} 994}
978 995
996void
997ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3)
998{
999 struct trace_array *tr = &global_trace;
1000 struct trace_array_cpu *data;
1001 unsigned long flags;
1002 long disabled;
1003 int cpu;
1004
1005 if (tracing_disabled || current_trace == &no_tracer || !tr->ctrl)
1006 return;
1007
1008 local_irq_save(flags);
1009 cpu = raw_smp_processor_id();
1010 data = tr->data[cpu];
1011 disabled = atomic_inc_return(&data->disabled);
1012
1013 if (likely(disabled == 1))
1014 __trace_special(tr, data, arg1, arg2, arg3);
1015
1016 atomic_dec(&data->disabled);
1017 local_irq_restore(flags);
1018}
1019
979#ifdef CONFIG_FTRACE 1020#ifdef CONFIG_FTRACE
980static void 1021static void
981function_trace_call(unsigned long ip, unsigned long parent_ip) 1022function_trace_call(unsigned long ip, unsigned long parent_ip)
@@ -989,6 +1030,9 @@ function_trace_call(unsigned long ip, unsigned long parent_ip)
989 if (unlikely(!tracer_enabled)) 1030 if (unlikely(!tracer_enabled))
990 return; 1031 return;
991 1032
1033 if (skip_trace(ip))
1034 return;
1035
992 local_irq_save(flags); 1036 local_irq_save(flags);
993 cpu = raw_smp_processor_id(); 1037 cpu = raw_smp_processor_id();
994 data = tr->data[cpu]; 1038 data = tr->data[cpu];
@@ -1213,6 +1257,20 @@ static void s_stop(struct seq_file *m, void *p)
1213 mutex_unlock(&trace_types_lock); 1257 mutex_unlock(&trace_types_lock);
1214} 1258}
1215 1259
1260#define KRETPROBE_MSG "[unknown/kretprobe'd]"
1261
1262#ifdef CONFIG_KRETPROBES
1263static inline int kretprobed(unsigned long addr)
1264{
1265 return addr == (unsigned long)kretprobe_trampoline;
1266}
1267#else
1268static inline int kretprobed(unsigned long addr)
1269{
1270 return 0;
1271}
1272#endif /* CONFIG_KRETPROBES */
1273
1216static int 1274static int
1217seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address) 1275seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
1218{ 1276{
@@ -1448,7 +1506,10 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
1448 case TRACE_FN: 1506 case TRACE_FN:
1449 seq_print_ip_sym(s, entry->fn.ip, sym_flags); 1507 seq_print_ip_sym(s, entry->fn.ip, sym_flags);
1450 trace_seq_puts(s, " ("); 1508 trace_seq_puts(s, " (");
1451 seq_print_ip_sym(s, entry->fn.parent_ip, sym_flags); 1509 if (kretprobed(entry->fn.parent_ip))
1510 trace_seq_puts(s, KRETPROBE_MSG);
1511 else
1512 seq_print_ip_sym(s, entry->fn.parent_ip, sym_flags);
1452 trace_seq_puts(s, ")\n"); 1513 trace_seq_puts(s, ")\n");
1453 break; 1514 break;
1454 case TRACE_CTX: 1515 case TRACE_CTX:
@@ -1528,8 +1589,11 @@ static int print_trace_fmt(struct trace_iterator *iter)
1528 ret = trace_seq_printf(s, " <-"); 1589 ret = trace_seq_printf(s, " <-");
1529 if (!ret) 1590 if (!ret)
1530 return 0; 1591 return 0;
1531 ret = seq_print_ip_sym(s, entry->fn.parent_ip, 1592 if (kretprobed(entry->fn.parent_ip))
1532 sym_flags); 1593 ret = trace_seq_puts(s, KRETPROBE_MSG);
1594 else
1595 ret = seq_print_ip_sym(s, entry->fn.parent_ip,
1596 sym_flags);
1533 if (!ret) 1597 if (!ret)
1534 return 0; 1598 return 0;
1535 } 1599 }
@@ -2608,7 +2672,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
2608{ 2672{
2609 unsigned long val; 2673 unsigned long val;
2610 char buf[64]; 2674 char buf[64];
2611 int ret; 2675 int i, ret;
2612 2676
2613 if (cnt >= sizeof(buf)) 2677 if (cnt >= sizeof(buf))
2614 return -EINVAL; 2678 return -EINVAL;
@@ -2677,8 +2741,15 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
2677 trace_free_page(); 2741 trace_free_page();
2678 } 2742 }
2679 2743
2744 /* check integrity */
2745 for_each_tracing_cpu(i)
2746 check_pages(global_trace.data[i]);
2747
2680 filp->f_pos += cnt; 2748 filp->f_pos += cnt;
2681 2749
2750 /* If check pages failed, return ENOMEM */
2751 if (tracing_disabled)
2752 cnt = -ENOMEM;
2682 out: 2753 out:
2683 max_tr.entries = global_trace.entries; 2754 max_tr.entries = global_trace.entries;
2684 mutex_unlock(&trace_types_lock); 2755 mutex_unlock(&trace_types_lock);
@@ -2969,8 +3040,6 @@ __init static int tracer_alloc_buffers(void)
2969 int ret = -ENOMEM; 3040 int ret = -ENOMEM;
2970 int i; 3041 int i;
2971 3042
2972 global_trace.ctrl = tracer_enabled;
2973
2974 /* TODO: make the number of buffers hot pluggable with CPUS */ 3043 /* TODO: make the number of buffers hot pluggable with CPUS */
2975 tracing_nr_buffers = num_possible_cpus(); 3044 tracing_nr_buffers = num_possible_cpus();
2976 tracing_buffer_mask = cpu_possible_map; 3045 tracing_buffer_mask = cpu_possible_map;
@@ -3027,9 +3096,8 @@ __init static int tracer_alloc_buffers(void)
3027 } 3096 }
3028 max_tr.entries = global_trace.entries; 3097 max_tr.entries = global_trace.entries;
3029 3098
3030 pr_info("tracer: %d pages allocated for %ld", 3099 pr_info("tracer: %d pages allocated for %ld entries of %ld bytes\n",
3031 pages, trace_nr_entries); 3100 pages, trace_nr_entries, (long)TRACE_ENTRY_SIZE);
3032 pr_info(" entries of %ld bytes\n", (long)TRACE_ENTRY_SIZE);
3033 pr_info(" actual entries %ld\n", global_trace.entries); 3101 pr_info(" actual entries %ld\n", global_trace.entries);
3034 3102
3035 tracer_init_debugfs(); 3103 tracer_init_debugfs();
@@ -3040,6 +3108,7 @@ __init static int tracer_alloc_buffers(void)
3040 current_trace = &no_tracer; 3108 current_trace = &no_tracer;
3041 3109
3042 /* All seems OK, enable tracing */ 3110 /* All seems OK, enable tracing */
3111 global_trace.ctrl = tracer_enabled;
3043 tracing_disabled = 0; 3112 tracing_disabled = 0;
3044 3113
3045 return 0; 3114 return 0;