| .. | .. |
|---|
| 14 | 14 | #include <linux/uaccess.h> |
|---|
| 15 | 15 | #include <linux/module.h> |
|---|
| 16 | 16 | #include <linux/ftrace.h> |
|---|
| 17 | +#include <linux/kprobes.h> |
|---|
| 17 | 18 | |
|---|
| 18 | 19 | #include "trace.h" |
|---|
| 19 | 20 | |
|---|
| .. | .. |
|---|
| 121 | 122 | if (!irqs_disabled_flags(*flags) && !preempt_count()) |
|---|
| 122 | 123 | return 0; |
|---|
| 123 | 124 | |
|---|
| 124 | | - *data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
|---|
| 125 | + *data = per_cpu_ptr(tr->array_buffer.data, cpu); |
|---|
| 125 | 126 | disabled = atomic_inc_return(&(*data)->disabled); |
|---|
| 126 | 127 | |
|---|
| 127 | 128 | if (likely(disabled == 1)) |
|---|
| .. | .. |
|---|
| 166 | 167 | per_cpu(tracing_cpu, cpu) = 0; |
|---|
| 167 | 168 | |
|---|
| 168 | 169 | tr->max_latency = 0; |
|---|
| 169 | | - tracing_reset_online_cpus(&irqsoff_trace->trace_buffer); |
|---|
| 170 | + tracing_reset_online_cpus(&irqsoff_trace->array_buffer); |
|---|
| 170 | 171 | |
|---|
| 171 | 172 | return start_irqsoff_tracer(irqsoff_trace, set); |
|---|
| 172 | 173 | } |
|---|
| .. | .. |
|---|
| 218 | 219 | atomic_dec(&data->disabled); |
|---|
| 219 | 220 | } |
|---|
| 220 | 221 | |
|---|
| 222 | +static struct fgraph_ops fgraph_ops = { |
|---|
| 223 | + .entryfunc = &irqsoff_graph_entry, |
|---|
| 224 | + .retfunc = &irqsoff_graph_return, |
|---|
| 225 | +}; |
|---|
| 226 | + |
|---|
| 221 | 227 | static void irqsoff_trace_open(struct trace_iterator *iter) |
|---|
| 222 | 228 | { |
|---|
| 223 | 229 | if (is_graph(iter->tr)) |
|---|
| 224 | 230 | graph_trace_open(iter); |
|---|
| 225 | | - |
|---|
| 231 | + else |
|---|
| 232 | + iter->private = NULL; |
|---|
| 226 | 233 | } |
|---|
| 227 | 234 | |
|---|
| 228 | 235 | static void irqsoff_trace_close(struct trace_iterator *iter) |
|---|
| .. | .. |
|---|
| 233 | 240 | |
|---|
| 234 | 241 | #define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_CPU | \ |
|---|
| 235 | 242 | TRACE_GRAPH_PRINT_PROC | \ |
|---|
| 236 | | - TRACE_GRAPH_PRINT_ABS_TIME | \ |
|---|
| 243 | + TRACE_GRAPH_PRINT_REL_TIME | \ |
|---|
| 237 | 244 | TRACE_GRAPH_PRINT_DURATION) |
|---|
| 238 | 245 | |
|---|
| 239 | 246 | static enum print_line_t irqsoff_print_line(struct trace_iterator *iter) |
|---|
| .. | .. |
|---|
| 272 | 279 | #else |
|---|
| 273 | 280 | #define __trace_function trace_function |
|---|
| 274 | 281 | |
|---|
| 275 | | -#ifdef CONFIG_FUNCTION_TRACER |
|---|
| 276 | | -static int irqsoff_graph_entry(struct ftrace_graph_ent *trace) |
|---|
| 277 | | -{ |
|---|
| 278 | | - return -1; |
|---|
| 279 | | -} |
|---|
| 280 | | -#endif |
|---|
| 281 | | - |
|---|
| 282 | 282 | static enum print_line_t irqsoff_print_line(struct trace_iterator *iter) |
|---|
| 283 | 283 | { |
|---|
| 284 | 284 | return TRACE_TYPE_UNHANDLED; |
|---|
| .. | .. |
|---|
| 288 | 288 | static void irqsoff_trace_close(struct trace_iterator *iter) { } |
|---|
| 289 | 289 | |
|---|
| 290 | 290 | #ifdef CONFIG_FUNCTION_TRACER |
|---|
| 291 | | -static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { } |
|---|
| 292 | 291 | static void irqsoff_print_header(struct seq_file *s) |
|---|
| 293 | 292 | { |
|---|
| 294 | 293 | trace_default_header(s); |
|---|
| .. | .. |
|---|
| 368 | 367 | __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc); |
|---|
| 369 | 368 | } |
|---|
| 370 | 369 | |
|---|
| 371 | | -static inline void |
|---|
| 370 | +static nokprobe_inline void |
|---|
| 372 | 371 | start_critical_timing(unsigned long ip, unsigned long parent_ip, int pc) |
|---|
| 373 | 372 | { |
|---|
| 374 | 373 | int cpu; |
|---|
| .. | .. |
|---|
| 384 | 383 | if (per_cpu(tracing_cpu, cpu)) |
|---|
| 385 | 384 | return; |
|---|
| 386 | 385 | |
|---|
| 387 | | - data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
|---|
| 386 | + data = per_cpu_ptr(tr->array_buffer.data, cpu); |
|---|
| 388 | 387 | |
|---|
| 389 | 388 | if (unlikely(!data) || atomic_read(&data->disabled)) |
|---|
| 390 | 389 | return; |
|---|
| .. | .. |
|---|
| 404 | 403 | atomic_dec(&data->disabled); |
|---|
| 405 | 404 | } |
|---|
| 406 | 405 | |
|---|
| 407 | | -static inline void |
|---|
| 406 | +static nokprobe_inline void |
|---|
| 408 | 407 | stop_critical_timing(unsigned long ip, unsigned long parent_ip, int pc) |
|---|
| 409 | 408 | { |
|---|
| 410 | 409 | int cpu; |
|---|
| .. | .. |
|---|
| 422 | 421 | if (!tracer_enabled || !tracing_is_enabled()) |
|---|
| 423 | 422 | return; |
|---|
| 424 | 423 | |
|---|
| 425 | | - data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
|---|
| 424 | + data = per_cpu_ptr(tr->array_buffer.data, cpu); |
|---|
| 426 | 425 | |
|---|
| 427 | 426 | if (unlikely(!data) || |
|---|
| 428 | 427 | !data->critical_start || atomic_read(&data->disabled)) |
|---|
| .. | .. |
|---|
| 446 | 445 | start_critical_timing(CALLER_ADDR0, CALLER_ADDR1, pc); |
|---|
| 447 | 446 | } |
|---|
| 448 | 447 | EXPORT_SYMBOL_GPL(start_critical_timings); |
|---|
| 448 | +NOKPROBE_SYMBOL(start_critical_timings); |
|---|
| 449 | 449 | |
|---|
| 450 | 450 | void stop_critical_timings(void) |
|---|
| 451 | 451 | { |
|---|
| .. | .. |
|---|
| 455 | 455 | stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1, pc); |
|---|
| 456 | 456 | } |
|---|
| 457 | 457 | EXPORT_SYMBOL_GPL(stop_critical_timings); |
|---|
| 458 | +NOKPROBE_SYMBOL(stop_critical_timings); |
|---|
| 458 | 459 | |
|---|
| 459 | 460 | #ifdef CONFIG_FUNCTION_TRACER |
|---|
| 460 | 461 | static bool function_enabled; |
|---|
| .. | .. |
|---|
| 468 | 469 | return 0; |
|---|
| 469 | 470 | |
|---|
| 470 | 471 | if (graph) |
|---|
| 471 | | - ret = register_ftrace_graph(&irqsoff_graph_return, |
|---|
| 472 | | - &irqsoff_graph_entry); |
|---|
| 472 | + ret = register_ftrace_graph(&fgraph_ops); |
|---|
| 473 | 473 | else |
|---|
| 474 | 474 | ret = register_ftrace_function(tr->ops); |
|---|
| 475 | 475 | |
|---|
| .. | .. |
|---|
| 485 | 485 | return; |
|---|
| 486 | 486 | |
|---|
| 487 | 487 | if (graph) |
|---|
| 488 | | - unregister_ftrace_graph(); |
|---|
| 488 | + unregister_ftrace_graph(&fgraph_ops); |
|---|
| 489 | 489 | else |
|---|
| 490 | 490 | unregister_ftrace_function(tr->ops); |
|---|
| 491 | 491 | |
|---|
| .. | .. |
|---|
| 563 | 563 | /* non overwrite screws up the latency tracers */ |
|---|
| 564 | 564 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1); |
|---|
| 565 | 565 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1); |
|---|
| 566 | + /* without pause, we will produce garbage if another latency occurs */ |
|---|
| 567 | + set_tracer_flag(tr, TRACE_ITER_PAUSE_ON_TRACE, 1); |
|---|
| 566 | 568 | |
|---|
| 567 | 569 | tr->max_latency = 0; |
|---|
| 568 | 570 | irqsoff_trace = tr; |
|---|
| .. | .. |
|---|
| 584 | 586 | { |
|---|
| 585 | 587 | int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT; |
|---|
| 586 | 588 | int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE; |
|---|
| 589 | + int pause_flag = save_flags & TRACE_ITER_PAUSE_ON_TRACE; |
|---|
| 587 | 590 | |
|---|
| 588 | 591 | stop_irqsoff_tracer(tr, is_graph(tr)); |
|---|
| 589 | 592 | |
|---|
| 590 | 593 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag); |
|---|
| 591 | 594 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag); |
|---|
| 595 | + set_tracer_flag(tr, TRACE_ITER_PAUSE_ON_TRACE, pause_flag); |
|---|
| 592 | 596 | ftrace_reset_array_ops(tr); |
|---|
| 593 | 597 | |
|---|
| 594 | 598 | irqsoff_busy = false; |
|---|
| .. | .. |
|---|
| 615 | 619 | if (!preempt_trace(pc) && irq_trace()) |
|---|
| 616 | 620 | stop_critical_timing(a0, a1, pc); |
|---|
| 617 | 621 | } |
|---|
| 622 | +NOKPROBE_SYMBOL(tracer_hardirqs_on); |
|---|
| 618 | 623 | |
|---|
| 619 | 624 | void tracer_hardirqs_off(unsigned long a0, unsigned long a1) |
|---|
| 620 | 625 | { |
|---|
| .. | .. |
|---|
| 623 | 628 | if (!preempt_trace(pc) && irq_trace()) |
|---|
| 624 | 629 | start_critical_timing(a0, a1, pc); |
|---|
| 625 | 630 | } |
|---|
| 631 | +NOKPROBE_SYMBOL(tracer_hardirqs_off); |
|---|
| 626 | 632 | |
|---|
| 627 | 633 | static int irqsoff_tracer_init(struct trace_array *tr) |
|---|
| 628 | 634 | { |
|---|