Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tracing: Add trace_trigger kernel command line option

Allow triggers to be enabled at kernel boot up. For example:

trace_trigger="sched_switch.stacktrace if prev_state == 2"

The above will enable the stacktrace trigger on top of the sched_switch
event and only trigger if its prev_state is 2 (TASK_UNINTERRUPTIBLE). Then
at boot up, a stacktrace will trigger and be recorded in the tracing ring
buffer every time the sched_switch happens where the previous state is
TASK_INTERRUPTIBLE.

Another useful trigger would be "traceoff" which can stop tracing on an
event if a field of the event matches a certain value defined by the
filter ("if" statement).

Link: https://lore.kernel.org/linux-trace-kernel/20221020210056.0d8d0a5b@gandalf.local.home

Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

+89 -2
+19
Documentation/admin-guide/kernel-parameters.txt
··· 6257 6257 See also Documentation/trace/ftrace.rst "trace options" 6258 6258 section. 6259 6259 6260 + trace_trigger=[trigger-list] 6261 + [FTRACE] Add a event trigger on specific events. 6262 + Set a trigger on top of a specific event, with an optional 6263 + filter. 6264 + 6265 + The format is is "trace_trigger=<event>.<trigger>[ if <filter>],..." 6266 + Where more than one trigger may be specified that are comma deliminated. 6267 + 6268 + For example: 6269 + 6270 + trace_trigger="sched_switch.stacktrace if prev_state == 2" 6271 + 6272 + The above will enable the "stacktrace" trigger on the "sched_switch" 6273 + event but only trigger it if the "prev_state" of the "sched_switch" 6274 + event is "2" (TASK_UNINTERUPTIBLE). 6275 + 6276 + See also "Event triggers" in Documentation/trace/events.rst 6277 + 6278 + 6260 6279 traceoff_on_warning 6261 6280 [FTRACE] enable this option to disable tracing when a 6262 6281 warning is hit. This turns off "tracing_on". Tracing can
+70 -2
kernel/trace/trace_events.c
··· 2796 2796 return file; 2797 2797 } 2798 2798 2799 + #ifdef CONFIG_HIST_TRIGGERS 2800 + #define MAX_BOOT_TRIGGERS 32 2801 + 2802 + static struct boot_triggers { 2803 + const char *event; 2804 + char *trigger; 2805 + } bootup_triggers[MAX_BOOT_TRIGGERS]; 2806 + 2807 + static char bootup_trigger_buf[COMMAND_LINE_SIZE]; 2808 + static int nr_boot_triggers; 2809 + 2810 + static __init int setup_trace_triggers(char *str) 2811 + { 2812 + char *trigger; 2813 + char *buf; 2814 + int i; 2815 + 2816 + strlcpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE); 2817 + ring_buffer_expanded = true; 2818 + disable_tracing_selftest("running event triggers"); 2819 + 2820 + buf = bootup_trigger_buf; 2821 + for (i = 0; i < MAX_BOOT_TRIGGERS; i++) { 2822 + trigger = strsep(&buf, ","); 2823 + if (!trigger) 2824 + break; 2825 + bootup_triggers[i].event = strsep(&trigger, "."); 2826 + bootup_triggers[i].trigger = strsep(&trigger, "."); 2827 + if (!bootup_triggers[i].trigger) 2828 + break; 2829 + } 2830 + 2831 + nr_boot_triggers = i; 2832 + return 1; 2833 + } 2834 + __setup("trace_trigger=", setup_trace_triggers); 2835 + #endif 2836 + 2799 2837 /* Add an event to a trace directory */ 2800 2838 static int 2801 2839 __trace_add_new_event(struct trace_event_call *call, struct trace_array *tr) ··· 2850 2812 return event_define_fields(call); 2851 2813 } 2852 2814 2815 + #ifdef CONFIG_HIST_TRIGGERS 2816 + static void trace_early_triggers(struct trace_event_file *file, const char *name) 2817 + { 2818 + int ret; 2819 + int i; 2820 + 2821 + for (i = 0; i < nr_boot_triggers; i++) { 2822 + if (strcmp(name, bootup_triggers[i].event)) 2823 + continue; 2824 + mutex_lock(&event_mutex); 2825 + ret = trigger_process_regex(file, bootup_triggers[i].trigger); 2826 + mutex_unlock(&event_mutex); 2827 + if (ret) 2828 + pr_err("Failed to register trigger '%s' on event %s\n", 2829 + bootup_triggers[i].trigger, 2830 + bootup_triggers[i].event); 2831 + } 2832 + } 2833 + #else 2834 + static inline void trace_early_triggers(struct trace_event_file *file, const char *name) { } 2835 + #endif 2836 + 2853 2837 /* 2854 2838 * Just create a descriptor for early init. A descriptor is required 2855 2839 * for enabling events at boot. We want to enable events before ··· 2882 2822 struct trace_array *tr) 2883 2823 { 2884 2824 struct trace_event_file *file; 2825 + int ret; 2885 2826 2886 2827 file = trace_create_new_event(call, tr); 2887 2828 if (!file) 2888 2829 return -ENOMEM; 2889 2830 2890 - return event_define_fields(call); 2831 + ret = event_define_fields(call); 2832 + if (ret) 2833 + return ret; 2834 + 2835 + trace_early_triggers(file, trace_event_name(call)); 2836 + 2837 + return 0; 2891 2838 } 2892 2839 2893 2840 struct ftrace_module_file_ops; ··· 3802 3735 list_add(&call->list, &ftrace_events); 3803 3736 } 3804 3737 3738 + register_trigger_cmds(); 3739 + 3805 3740 /* 3806 3741 * We need the top trace array to have a working set of trace 3807 3742 * points at early init, before the debug files and directories ··· 3818 3749 3819 3750 register_event_cmds(); 3820 3751 3821 - register_trigger_cmds(); 3822 3752 3823 3753 return 0; 3824 3754 }