diff options
Diffstat (limited to 'include/trace')
-rw-r--r-- | include/trace/ftrace.h | 83 |
1 files changed, 55 insertions, 28 deletions
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index a822087857e9..a0361cb69769 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -648,11 +648,12 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
648 | * struct ftrace_raw_##call *entry; | 648 | * struct ftrace_raw_##call *entry; |
649 | * u64 __addr = 0, __count = 1; | 649 | * u64 __addr = 0, __count = 1; |
650 | * unsigned long irq_flags; | 650 | * unsigned long irq_flags; |
651 | * struct trace_entry *ent; | ||
651 | * int __entry_size; | 652 | * int __entry_size; |
652 | * int __data_size; | 653 | * int __data_size; |
654 | * int __cpu | ||
653 | * int pc; | 655 | * int pc; |
654 | * | 656 | * |
655 | * local_save_flags(irq_flags); | ||
656 | * pc = preempt_count(); | 657 | * pc = preempt_count(); |
657 | * | 658 | * |
658 | * __data_size = ftrace_get_offsets_<call>(&__data_offsets, args); | 659 | * __data_size = ftrace_get_offsets_<call>(&__data_offsets, args); |
@@ -663,25 +664,34 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
663 | * sizeof(u64)); | 664 | * sizeof(u64)); |
664 | * __entry_size -= sizeof(u32); | 665 | * __entry_size -= sizeof(u32); |
665 | * | 666 | * |
666 | * do { | 667 | * // Protect the non nmi buffer |
667 | * char raw_data[__entry_size]; <- allocate our sample in the stack | 668 | * // This also protects the rcu read side |
668 | * struct trace_entry *ent; | 669 | * local_irq_save(irq_flags); |
670 | * __cpu = smp_processor_id(); | ||
671 | * | ||
672 | * if (in_nmi()) | ||
673 | * raw_data = rcu_dereference(trace_profile_buf_nmi); | ||
674 | * else | ||
675 | * raw_data = rcu_dereference(trace_profile_buf); | ||
676 | * | ||
677 | * if (!raw_data) | ||
678 | * goto end; | ||
669 | * | 679 | * |
670 | * zero dead bytes from alignment to avoid stack leak to userspace: | 680 | * raw_data = per_cpu_ptr(raw_data, __cpu); |
671 | * | 681 | * |
672 | * *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; | 682 | * //zero dead bytes from alignment to avoid stack leak to userspace: |
673 | * entry = (struct ftrace_raw_<call> *)raw_data; | 683 | * *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; |
674 | * ent = &entry->ent; | 684 | * entry = (struct ftrace_raw_<call> *)raw_data; |
675 | * tracing_generic_entry_update(ent, irq_flags, pc); | 685 | * ent = &entry->ent; |
676 | * ent->type = event_call->id; | 686 | * tracing_generic_entry_update(ent, irq_flags, pc); |
687 | * ent->type = event_call->id; | ||
677 | * | 688 | * |
678 | * <tstruct> <- do some jobs with dynamic arrays | 689 | * <tstruct> <- do some jobs with dynamic arrays |
679 | * | 690 | * |
680 | * <assign> <- affect our values | 691 | * <assign> <- affect our values |
681 | * | 692 | * |
682 | * perf_tpcounter_event(event_call->id, __addr, __count, entry, | 693 | * perf_tpcounter_event(event_call->id, __addr, __count, entry, |
683 | * __entry_size); <- submit them to perf counter | 694 | * __entry_size); <- submit them to perf counter |
684 | * } while (0); | ||
685 | * | 695 | * |
686 | * } | 696 | * } |
687 | */ | 697 | */ |
@@ -704,11 +714,13 @@ static void ftrace_profile_##call(proto) \ | |||
704 | struct ftrace_raw_##call *entry; \ | 714 | struct ftrace_raw_##call *entry; \ |
705 | u64 __addr = 0, __count = 1; \ | 715 | u64 __addr = 0, __count = 1; \ |
706 | unsigned long irq_flags; \ | 716 | unsigned long irq_flags; \ |
717 | struct trace_entry *ent; \ | ||
707 | int __entry_size; \ | 718 | int __entry_size; \ |
708 | int __data_size; \ | 719 | int __data_size; \ |
720 | char *raw_data; \ | ||
721 | int __cpu; \ | ||
709 | int pc; \ | 722 | int pc; \ |
710 | \ | 723 | \ |
711 | local_save_flags(irq_flags); \ | ||
712 | pc = preempt_count(); \ | 724 | pc = preempt_count(); \ |
713 | \ | 725 | \ |
714 | __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ | 726 | __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ |
@@ -716,23 +728,38 @@ static void ftrace_profile_##call(proto) \ | |||
716 | sizeof(u64)); \ | 728 | sizeof(u64)); \ |
717 | __entry_size -= sizeof(u32); \ | 729 | __entry_size -= sizeof(u32); \ |
718 | \ | 730 | \ |
719 | do { \ | 731 | if (WARN_ONCE(__entry_size > FTRACE_MAX_PROFILE_SIZE, \ |
720 | char raw_data[__entry_size]; \ | 732 | "profile buffer not large enough")) \ |
721 | struct trace_entry *ent; \ | 733 | return; \ |
734 | \ | ||
735 | local_irq_save(irq_flags); \ | ||
736 | __cpu = smp_processor_id(); \ | ||
722 | \ | 737 | \ |
723 | *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ | 738 | if (in_nmi()) \ |
724 | entry = (struct ftrace_raw_##call *)raw_data; \ | 739 | raw_data = rcu_dereference(trace_profile_buf_nmi); \ |
725 | ent = &entry->ent; \ | 740 | else \ |
726 | tracing_generic_entry_update(ent, irq_flags, pc); \ | 741 | raw_data = rcu_dereference(trace_profile_buf); \ |
727 | ent->type = event_call->id; \ | ||
728 | \ | 742 | \ |
729 | tstruct \ | 743 | if (!raw_data) \ |
744 | goto end; \ | ||
730 | \ | 745 | \ |
731 | { assign; } \ | 746 | raw_data = per_cpu_ptr(raw_data, __cpu); \ |
732 | \ | 747 | \ |
733 | perf_tpcounter_event(event_call->id, __addr, __count, entry,\ | 748 | *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ |
749 | entry = (struct ftrace_raw_##call *)raw_data; \ | ||
750 | ent = &entry->ent; \ | ||
751 | tracing_generic_entry_update(ent, irq_flags, pc); \ | ||
752 | ent->type = event_call->id; \ | ||
753 | \ | ||
754 | tstruct \ | ||
755 | \ | ||
756 | { assign; } \ | ||
757 | \ | ||
758 | perf_tpcounter_event(event_call->id, __addr, __count, entry, \ | ||
734 | __entry_size); \ | 759 | __entry_size); \ |
735 | } while (0); \ | 760 | \ |
761 | end: \ | ||
762 | local_irq_restore(irq_flags); \ | ||
736 | \ | 763 | \ |
737 | } | 764 | } |
738 | 765 | ||