Merge tag 'trace-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing updates from Steven Rostedt: "One new feature was added to ftrace, which is the trace_marker now supports triggers. For example: # cd /sys/kernel/debug/tracing # echo 'snapshot' > events/ftrace/print/trigger # echo 'cause snapshot' > trace_marker The rest of the changes are various clean ups and also one stable fix that was added late in the cycle" * tag 'trace-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (21 commits) tracing: Use match_string() instead of open coding it in trace_set_options() branch-check: fix long->int truncation when profiling branches ring-buffer: Fix typo in comment ring-buffer: Fix a bunch of typos in comments tracing/selftest: Add test to test simple snapshot trigger for trace_marker tracing/selftest: Add test to test hist trigger between kernel event and trace_marker tracing/selftest: Add selftests to test trace_marker histogram triggers ftrace/selftest: Fix reset_trigger() to handle triggers with filters ftrace/selftest: Have the reset_trigger code be a bit more careful tracing: Document trace_marker triggers tracing: Allow histogram triggers to access ftrace internal events tracing: Prevent further users of zero size static arrays in trace events tracing: Have zero size length in filter logic be full string tracing: Add trigger file for trace_markers tracefs/ftrace/print tracing: Do not show filter file for ftrace internal events tracing: Add brackets in ftrace event dynamic arrays tracing: Have event_trace_init() called by trace_init_tracefs() tracing: Add __find_event_file() to find event files without restrictions tracing: Do not reference event data in post call triggers tracepoints: Fix the descriptions of tracepoint_probe_register{_prio} ...
This commit is contained in:
@ -809,7 +809,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_normalize_time_stamp);
|
||||
*
|
||||
* You can see, it is legitimate for the previous pointer of
|
||||
* the head (or any page) not to point back to itself. But only
|
||||
* temporarially.
|
||||
* temporarily.
|
||||
*/
|
||||
|
||||
#define RB_PAGE_NORMAL 0UL
|
||||
@ -906,7 +906,7 @@ static void rb_list_head_clear(struct list_head *list)
|
||||
}
|
||||
|
||||
/*
|
||||
* rb_head_page_dactivate - clears head page ptr (for free list)
|
||||
* rb_head_page_deactivate - clears head page ptr (for free list)
|
||||
*/
|
||||
static void
|
||||
rb_head_page_deactivate(struct ring_buffer_per_cpu *cpu_buffer)
|
||||
@ -1780,7 +1780,7 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
|
||||
|
||||
put_online_cpus();
|
||||
} else {
|
||||
/* Make sure this CPU has been intitialized */
|
||||
/* Make sure this CPU has been initialized */
|
||||
if (!cpumask_test_cpu(cpu_id, buffer->cpumask))
|
||||
goto out;
|
||||
|
||||
@ -2325,7 +2325,7 @@ rb_update_event(struct ring_buffer_per_cpu *cpu_buffer,
|
||||
|
||||
/*
|
||||
* If we need to add a timestamp, then we
|
||||
* add it to the start of the resevered space.
|
||||
* add it to the start of the reserved space.
|
||||
*/
|
||||
if (unlikely(info->add_timestamp)) {
|
||||
bool abs = ring_buffer_time_stamp_abs(cpu_buffer->buffer);
|
||||
@ -2681,7 +2681,7 @@ trace_recursive_unlock(struct ring_buffer_per_cpu *cpu_buffer)
|
||||
* ring_buffer_nest_start - Allow to trace while nested
|
||||
* @buffer: The ring buffer to modify
|
||||
*
|
||||
* The ring buffer has a safty mechanism to prevent recursion.
|
||||
* The ring buffer has a safety mechanism to prevent recursion.
|
||||
* But there may be a case where a trace needs to be done while
|
||||
* tracing something else. In this case, calling this function
|
||||
* will allow this function to nest within a currently active
|
||||
@ -2699,7 +2699,7 @@ void ring_buffer_nest_start(struct ring_buffer *buffer)
|
||||
preempt_disable_notrace();
|
||||
cpu = raw_smp_processor_id();
|
||||
cpu_buffer = buffer->buffers[cpu];
|
||||
/* This is the shift value for the above recusive locking */
|
||||
/* This is the shift value for the above recursive locking */
|
||||
cpu_buffer->nest += NESTED_BITS;
|
||||
}
|
||||
|
||||
@ -2718,7 +2718,7 @@ void ring_buffer_nest_end(struct ring_buffer *buffer)
|
||||
/* disabled by ring_buffer_nest_start() */
|
||||
cpu = raw_smp_processor_id();
|
||||
cpu_buffer = buffer->buffers[cpu];
|
||||
/* This is the shift value for the above recusive locking */
|
||||
/* This is the shift value for the above recursive locking */
|
||||
cpu_buffer->nest -= NESTED_BITS;
|
||||
preempt_enable_notrace();
|
||||
}
|
||||
@ -2907,7 +2907,7 @@ rb_reserve_next_event(struct ring_buffer *buffer,
|
||||
* @buffer: the ring buffer to reserve from
|
||||
* @length: the length of the data to reserve (excluding event header)
|
||||
*
|
||||
* Returns a reseverd event on the ring buffer to copy directly to.
|
||||
* Returns a reserved event on the ring buffer to copy directly to.
|
||||
* The user of this interface will need to get the body to write into
|
||||
* and can use the ring_buffer_event_data() interface.
|
||||
*
|
||||
@ -3009,7 +3009,7 @@ rb_decrement_entry(struct ring_buffer_per_cpu *cpu_buffer,
|
||||
* This function lets the user discard an event in the ring buffer
|
||||
* and then that event will not be read later.
|
||||
*
|
||||
* This function only works if it is called before the the item has been
|
||||
* This function only works if it is called before the item has been
|
||||
* committed. It will try to free the event from the ring buffer
|
||||
* if another event has not been added behind it.
|
||||
*
|
||||
@ -4127,7 +4127,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_consume);
|
||||
* through the buffer. Memory is allocated, buffer recording
|
||||
* is disabled, and the iterator pointer is returned to the caller.
|
||||
*
|
||||
* Disabling buffer recordng prevents the reading from being
|
||||
* Disabling buffer recording prevents the reading from being
|
||||
* corrupted. This is not a consuming read, so a producer is not
|
||||
* expected.
|
||||
*
|
||||
|
@ -4395,8 +4395,7 @@ static int trace_set_options(struct trace_array *tr, char *option)
|
||||
{
|
||||
char *cmp;
|
||||
int neg = 0;
|
||||
int ret = -ENODEV;
|
||||
int i;
|
||||
int ret;
|
||||
size_t orig_len = strlen(option);
|
||||
|
||||
cmp = strstrip(option);
|
||||
@ -4408,16 +4407,12 @@ static int trace_set_options(struct trace_array *tr, char *option)
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
|
||||
for (i = 0; trace_options[i]; i++) {
|
||||
if (strcmp(cmp, trace_options[i]) == 0) {
|
||||
ret = set_tracer_flag(tr, 1 << i, !neg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = match_string(trace_options, -1, cmp);
|
||||
/* If no option could be set, test the specific tracer options */
|
||||
if (!trace_options[i])
|
||||
if (ret < 0)
|
||||
ret = set_tracer_option(tr, cmp, neg);
|
||||
else
|
||||
ret = set_tracer_flag(tr, 1 << ret, !neg);
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
@ -6074,6 +6069,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
|
||||
{
|
||||
struct trace_array *tr = filp->private_data;
|
||||
struct ring_buffer_event *event;
|
||||
enum event_trigger_type tt = ETT_NONE;
|
||||
struct ring_buffer *buffer;
|
||||
struct print_entry *entry;
|
||||
unsigned long irq_flags;
|
||||
@ -6122,6 +6118,12 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
|
||||
written = cnt;
|
||||
len = cnt;
|
||||
|
||||
if (tr->trace_marker_file && !list_empty(&tr->trace_marker_file->triggers)) {
|
||||
/* do not add \n before testing triggers, but add \0 */
|
||||
entry->buf[cnt] = '\0';
|
||||
tt = event_triggers_call(tr->trace_marker_file, entry, event);
|
||||
}
|
||||
|
||||
if (entry->buf[cnt - 1] != '\n') {
|
||||
entry->buf[cnt] = '\n';
|
||||
entry->buf[cnt + 1] = '\0';
|
||||
@ -6130,6 +6132,9 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
|
||||
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
|
||||
if (tt)
|
||||
event_triggers_post_call(tr->trace_marker_file, tt);
|
||||
|
||||
if (written > 0)
|
||||
*fpos += written;
|
||||
|
||||
@ -7896,6 +7901,7 @@ static __init void create_trace_instances(struct dentry *d_tracer)
|
||||
static void
|
||||
init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
|
||||
{
|
||||
struct trace_event_file *file;
|
||||
int cpu;
|
||||
|
||||
trace_create_file("available_tracers", 0444, d_tracer,
|
||||
@ -7928,6 +7934,12 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
|
||||
trace_create_file("trace_marker", 0220, d_tracer,
|
||||
tr, &tracing_mark_fops);
|
||||
|
||||
file = __find_event_file(tr, "ftrace", "print");
|
||||
if (file && file->dir)
|
||||
trace_create_file("trigger", 0644, file->dir, file,
|
||||
&event_trigger_fops);
|
||||
tr->trace_marker_file = file;
|
||||
|
||||
trace_create_file("trace_marker_raw", 0220, d_tracer,
|
||||
tr, &tracing_mark_raw_fops);
|
||||
|
||||
@ -8111,6 +8123,8 @@ static __init int tracer_init_tracefs(void)
|
||||
if (IS_ERR(d_tracer))
|
||||
return 0;
|
||||
|
||||
event_trace_init();
|
||||
|
||||
init_tracer_tracefs(&global_trace, d_tracer);
|
||||
ftrace_init_tracefs_toplevel(&global_trace, d_tracer);
|
||||
|
||||
|
@ -259,6 +259,7 @@ struct trace_array {
|
||||
struct trace_options *topts;
|
||||
struct list_head systems;
|
||||
struct list_head events;
|
||||
struct trace_event_file *trace_marker_file;
|
||||
cpumask_var_t tracing_cpumask; /* only trace on set CPUs */
|
||||
int ref;
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
@ -1334,7 +1335,7 @@ event_trigger_unlock_commit(struct trace_event_file *file,
|
||||
trace_buffer_unlock_commit(file->tr, buffer, event, irq_flags, pc);
|
||||
|
||||
if (tt)
|
||||
event_triggers_post_call(file, tt, entry, event);
|
||||
event_triggers_post_call(file, tt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1367,7 +1368,7 @@ event_trigger_unlock_commit_regs(struct trace_event_file *file,
|
||||
irq_flags, pc, regs);
|
||||
|
||||
if (tt)
|
||||
event_triggers_post_call(file, tt, entry, event);
|
||||
event_triggers_post_call(file, tt);
|
||||
}
|
||||
|
||||
#define FILTER_PRED_INVALID ((unsigned short)-1)
|
||||
@ -1451,9 +1452,13 @@ trace_find_event_field(struct trace_event_call *call, char *name);
|
||||
extern void trace_event_enable_cmd_record(bool enable);
|
||||
extern void trace_event_enable_tgid_record(bool enable);
|
||||
|
||||
extern int event_trace_init(void);
|
||||
extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
|
||||
extern int event_trace_del_tracer(struct trace_array *tr);
|
||||
|
||||
extern struct trace_event_file *__find_event_file(struct trace_array *tr,
|
||||
const char *system,
|
||||
const char *event);
|
||||
extern struct trace_event_file *find_event_file(struct trace_array *tr,
|
||||
const char *system,
|
||||
const char *event);
|
||||
|
@ -230,7 +230,7 @@ FTRACE_ENTRY(bprint, bprint_entry,
|
||||
FILTER_OTHER
|
||||
);
|
||||
|
||||
FTRACE_ENTRY(print, print_entry,
|
||||
FTRACE_ENTRY_REG(print, print_entry,
|
||||
|
||||
TRACE_PRINT,
|
||||
|
||||
@ -242,7 +242,9 @@ FTRACE_ENTRY(print, print_entry,
|
||||
F_printk("%ps: %s",
|
||||
(void *)__entry->ip, __entry->buf),
|
||||
|
||||
FILTER_OTHER
|
||||
FILTER_OTHER,
|
||||
|
||||
ftrace_event_register
|
||||
);
|
||||
|
||||
FTRACE_ENTRY(raw_data, raw_data_entry,
|
||||
|
@ -2007,16 +2007,18 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
trace_create_file("filter", 0644, file->dir, file,
|
||||
&ftrace_event_filter_fops);
|
||||
|
||||
/*
|
||||
* Only event directories that can be enabled should have
|
||||
* triggers.
|
||||
* triggers or filters.
|
||||
*/
|
||||
if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
|
||||
if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) {
|
||||
trace_create_file("filter", 0644, file->dir, file,
|
||||
&ftrace_event_filter_fops);
|
||||
|
||||
trace_create_file("trigger", 0644, file->dir, file,
|
||||
&event_trigger_fops);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HIST_TRIGGERS
|
||||
trace_create_file("hist", 0444, file->dir, file,
|
||||
@ -2473,8 +2475,9 @@ __trace_add_event_dirs(struct trace_array *tr)
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns any file that matches the system and event */
|
||||
struct trace_event_file *
|
||||
find_event_file(struct trace_array *tr, const char *system, const char *event)
|
||||
__find_event_file(struct trace_array *tr, const char *system, const char *event)
|
||||
{
|
||||
struct trace_event_file *file;
|
||||
struct trace_event_call *call;
|
||||
@ -2485,10 +2488,7 @@ find_event_file(struct trace_array *tr, const char *system, const char *event)
|
||||
call = file->event_call;
|
||||
name = trace_event_name(call);
|
||||
|
||||
if (!name || !call->class || !call->class->reg)
|
||||
continue;
|
||||
|
||||
if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
|
||||
if (!name || !call->class)
|
||||
continue;
|
||||
|
||||
if (strcmp(event, name) == 0 &&
|
||||
@ -2498,6 +2498,20 @@ find_event_file(struct trace_array *tr, const char *system, const char *event)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns valid trace event files that match system and event */
|
||||
struct trace_event_file *
|
||||
find_event_file(struct trace_array *tr, const char *system, const char *event)
|
||||
{
|
||||
struct trace_event_file *file;
|
||||
|
||||
file = __find_event_file(tr, system, event);
|
||||
if (!file || !file->event_call->class->reg ||
|
||||
file->event_call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
|
||||
return NULL;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
||||
/* Avoid typos */
|
||||
@ -3132,7 +3146,7 @@ static __init int event_trace_enable_again(void)
|
||||
|
||||
early_initcall(event_trace_enable_again);
|
||||
|
||||
static __init int event_trace_init(void)
|
||||
__init int event_trace_init(void)
|
||||
{
|
||||
struct trace_array *tr;
|
||||
struct dentry *d_tracer;
|
||||
@ -3177,8 +3191,6 @@ void __init trace_event_init(void)
|
||||
event_trace_enable();
|
||||
}
|
||||
|
||||
fs_initcall(event_trace_init);
|
||||
|
||||
#ifdef CONFIG_FTRACE_STARTUP_TEST
|
||||
|
||||
static DEFINE_SPINLOCK(test_spinlock);
|
||||
|
@ -750,31 +750,32 @@ static int filter_pred_none(struct filter_pred *pred, void *event)
|
||||
*
|
||||
* Note:
|
||||
* - @str might not be NULL-terminated if it's of type DYN_STRING
|
||||
* or STATIC_STRING
|
||||
* or STATIC_STRING, unless @len is zero.
|
||||
*/
|
||||
|
||||
static int regex_match_full(char *str, struct regex *r, int len)
|
||||
{
|
||||
if (strncmp(str, r->pattern, len) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
/* len of zero means str is dynamic and ends with '\0' */
|
||||
if (!len)
|
||||
return strcmp(str, r->pattern) == 0;
|
||||
|
||||
return strncmp(str, r->pattern, len) == 0;
|
||||
}
|
||||
|
||||
static int regex_match_front(char *str, struct regex *r, int len)
|
||||
{
|
||||
if (len < r->len)
|
||||
if (len && len < r->len)
|
||||
return 0;
|
||||
|
||||
if (strncmp(str, r->pattern, r->len) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
return strncmp(str, r->pattern, r->len) == 0;
|
||||
}
|
||||
|
||||
static int regex_match_middle(char *str, struct regex *r, int len)
|
||||
{
|
||||
if (strnstr(str, r->pattern, len))
|
||||
return 1;
|
||||
return 0;
|
||||
if (!len)
|
||||
return strstr(str, r->pattern) != NULL;
|
||||
|
||||
return strnstr(str, r->pattern, len) != NULL;
|
||||
}
|
||||
|
||||
static int regex_match_end(char *str, struct regex *r, int len)
|
||||
|
@ -2865,7 +2865,7 @@ static struct trace_event_file *event_file(struct trace_array *tr,
|
||||
{
|
||||
struct trace_event_file *file;
|
||||
|
||||
file = find_event_file(tr, system, event_name);
|
||||
file = __find_event_file(tr, system, event_name);
|
||||
if (!file)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
|
@ -97,7 +97,6 @@ EXPORT_SYMBOL_GPL(event_triggers_call);
|
||||
* event_triggers_post_call - Call 'post_triggers' for a trace event
|
||||
* @file: The trace_event_file associated with the event
|
||||
* @tt: enum event_trigger_type containing a set bit for each trigger to invoke
|
||||
* @rec: The trace entry for the event
|
||||
*
|
||||
* For each trigger associated with an event, invoke the trigger
|
||||
* function registered with the associated trigger command, if the
|
||||
@ -108,8 +107,7 @@ EXPORT_SYMBOL_GPL(event_triggers_call);
|
||||
*/
|
||||
void
|
||||
event_triggers_post_call(struct trace_event_file *file,
|
||||
enum event_trigger_type tt,
|
||||
void *rec, struct ring_buffer_event *event)
|
||||
enum event_trigger_type tt)
|
||||
{
|
||||
struct event_trigger_data *data;
|
||||
|
||||
@ -117,7 +115,7 @@ event_triggers_post_call(struct trace_event_file *file,
|
||||
if (data->paused)
|
||||
continue;
|
||||
if (data->cmd_ops->trigger_type & tt)
|
||||
data->ops->func(data, rec, event);
|
||||
data->ops->func(data, NULL, NULL);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(event_triggers_post_call);
|
||||
|
@ -14,6 +14,13 @@
|
||||
|
||||
#include "trace_output.h"
|
||||
|
||||
/* Stub function for events with triggers */
|
||||
static int ftrace_event_register(struct trace_event_call *call,
|
||||
enum trace_reg type, void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM ftrace
|
||||
|
||||
@ -117,7 +124,7 @@ static void __always_unused ____ftrace_check_##name(void) \
|
||||
|
||||
#undef __dynamic_array
|
||||
#define __dynamic_array(type, item) \
|
||||
ret = trace_define_field(event_call, #type, #item, \
|
||||
ret = trace_define_field(event_call, #type "[]", #item, \
|
||||
offsetof(typeof(field), item), \
|
||||
0, is_signed_type(type), filter_type);\
|
||||
if (ret) \
|
||||
|
Reference in New Issue
Block a user