Commit a01fdc89 authored by Steven Rostedt (Google)'s avatar Steven Rostedt (Google)
Browse files

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: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent 8230f27b
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -6257,6 +6257,25 @@
			See also Documentation/trace/ftrace.rst "trace options"
			section.

	trace_trigger=[trigger-list]
			[FTRACE] Add a event trigger on specific events.
			Set a trigger on top of a specific event, with an optional
			filter.

			The format is is "trace_trigger=<event>.<trigger>[ if <filter>],..."
			Where more than one trigger may be specified that are comma deliminated.

			For example:

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

			The above will enable the "stacktrace" trigger on the "sched_switch"
			event but only trigger it if the "prev_state" of the "sched_switch"
			event is "2" (TASK_UNINTERUPTIBLE).

			See also "Event triggers" in Documentation/trace/events.rst


	traceoff_on_warning
			[FTRACE] enable this option to disable tracing when a
			warning is hit. This turns off "tracing_on". Tracing can
+70 −2
Original line number Diff line number Diff line
@@ -2796,6 +2796,44 @@ trace_create_new_event(struct trace_event_call *call,
	return file;
}

#ifdef CONFIG_HIST_TRIGGERS
#define MAX_BOOT_TRIGGERS 32

static struct boot_triggers {
	const char		*event;
	char			*trigger;
} bootup_triggers[MAX_BOOT_TRIGGERS];

static char bootup_trigger_buf[COMMAND_LINE_SIZE];
static int nr_boot_triggers;

static __init int setup_trace_triggers(char *str)
{
	char *trigger;
	char *buf;
	int i;

	strlcpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE);
	ring_buffer_expanded = true;
	disable_tracing_selftest("running event triggers");

	buf = bootup_trigger_buf;
	for (i = 0; i < MAX_BOOT_TRIGGERS; i++) {
		trigger = strsep(&buf, ",");
		if (!trigger)
			break;
		bootup_triggers[i].event = strsep(&trigger, ".");
		bootup_triggers[i].trigger = strsep(&trigger, ".");
		if (!bootup_triggers[i].trigger)
			break;
	}

	nr_boot_triggers = i;
	return 1;
}
__setup("trace_trigger=", setup_trace_triggers);
#endif

/* Add an event to a trace directory */
static int
__trace_add_new_event(struct trace_event_call *call, struct trace_array *tr)
@@ -2812,6 +2850,28 @@ __trace_add_new_event(struct trace_event_call *call, struct trace_array *tr)
		return event_define_fields(call);
}

#ifdef CONFIG_HIST_TRIGGERS
static void trace_early_triggers(struct trace_event_file *file, const char *name)
{
	int ret;
	int i;

	for (i = 0; i < nr_boot_triggers; i++) {
		if (strcmp(name, bootup_triggers[i].event))
			continue;
		mutex_lock(&event_mutex);
		ret = trigger_process_regex(file, bootup_triggers[i].trigger);
		mutex_unlock(&event_mutex);
		if (ret)
			pr_err("Failed to register trigger '%s' on event %s\n",
			       bootup_triggers[i].trigger,
			       bootup_triggers[i].event);
	}
}
#else
static inline void trace_early_triggers(struct trace_event_file *file, const char *name) { }
#endif

/*
 * Just create a descriptor for early init. A descriptor is required
 * for enabling events at boot. We want to enable events before
@@ -2822,12 +2882,19 @@ __trace_early_add_new_event(struct trace_event_call *call,
			    struct trace_array *tr)
{
	struct trace_event_file *file;
	int ret;

	file = trace_create_new_event(call, tr);
	if (!file)
		return -ENOMEM;

	return event_define_fields(call);
	ret = event_define_fields(call);
	if (ret)
		return ret;

	trace_early_triggers(file, trace_event_name(call));

	return 0;
}

struct ftrace_module_file_ops;
@@ -3735,6 +3802,8 @@ static __init int event_trace_enable(void)
			list_add(&call->list, &ftrace_events);
	}

	register_trigger_cmds();

	/*
	 * We need the top trace array to have a working set of trace
	 * points at early init, before the debug files and directories
@@ -3749,7 +3818,6 @@ static __init int event_trace_enable(void)

	register_event_cmds();

	register_trigger_cmds();

	return 0;
}