Commit 05daae0f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'trace-v5.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing fixes from Steven Rostedt:

 - Fix deadloop in ring buffer because of using stale "read" variable

 - Fix synthetic event use of field_pos as boolean and not an index

 - Fixed histogram special var "cpu" overriding event fields called
   "cpu"

 - Cleaned up error prone logic in alloc_synth_event()

 - Removed call to synchronize_rcu_tasks_rude() when not needed

 - Removed redundant initialization of a local variable "ret"

 - Fixed kernel crash when updating tracepoint callbacks of different
   priorities.

* tag 'trace-v5.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  tracepoints: Update static_call before tp_funcs when adding a tracepoint
  ftrace: Remove redundant initialization of variable ret
  ftrace: Avoid synchronize_rcu_tasks_rude() call when not necessary
  tracing: Clean up alloc_synth_event()
  tracing/histogram: Rename "cpu" to "common_cpu"
  tracing: Synthetic event field_pos is an index not a boolean
  tracing: Fix bug in rb_per_cpu_empty() that might cause deadloop.
parents 1af09ed5 352384d5
...@@ -191,7 +191,7 @@ Documentation written by Tom Zanussi ...@@ -191,7 +191,7 @@ Documentation written by Tom Zanussi
with the event, in nanoseconds. May be with the event, in nanoseconds. May be
modified by .usecs to have timestamps modified by .usecs to have timestamps
interpreted as microseconds. interpreted as microseconds.
cpu int the cpu on which the event occurred. common_cpu int the cpu on which the event occurred.
====================== ==== ======================================= ====================== ==== =======================================
Extended error information Extended error information
......
...@@ -5985,6 +5985,7 @@ ftrace_graph_release(struct inode *inode, struct file *file) ...@@ -5985,6 +5985,7 @@ ftrace_graph_release(struct inode *inode, struct file *file)
* infrastructure to do the synchronization, thus we must do it * infrastructure to do the synchronization, thus we must do it
* ourselves. * ourselves.
*/ */
if (old_hash != EMPTY_HASH)
synchronize_rcu_tasks_rude(); synchronize_rcu_tasks_rude();
free_ftrace_hash(old_hash); free_ftrace_hash(old_hash);
...@@ -7544,7 +7545,7 @@ int ftrace_is_dead(void) ...@@ -7544,7 +7545,7 @@ int ftrace_is_dead(void)
*/ */
int register_ftrace_function(struct ftrace_ops *ops) int register_ftrace_function(struct ftrace_ops *ops)
{ {
int ret = -1; int ret;
ftrace_ops_init(ops); ftrace_ops_init(ops);
......
...@@ -3880,10 +3880,30 @@ static bool rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer) ...@@ -3880,10 +3880,30 @@ static bool rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer)
if (unlikely(!head)) if (unlikely(!head))
return true; return true;
return reader->read == rb_page_commit(reader) && /* Reader should exhaust content in reader page */
(commit == reader || if (reader->read != rb_page_commit(reader))
(commit == head && return false;
head->read == rb_page_commit(commit)));
/*
* If writers are committing on the reader page, knowing all
* committed content has been read, the ring buffer is empty.
*/
if (commit == reader)
return true;
/*
* If writers are committing on a page other than reader page
* and head page, there should always be content to read.
*/
if (commit != head)
return false;
/*
* Writers are committing on the head page, we just need
* to care about there're committed data, and the reader will
* swap reader page with head page when it is to read data.
*/
return rb_page_commit(commit) == 0;
} }
/** /**
......
...@@ -5609,6 +5609,10 @@ static const char readme_msg[] = ...@@ -5609,6 +5609,10 @@ static const char readme_msg[] =
"\t [:name=histname1]\n" "\t [:name=histname1]\n"
"\t [:<handler>.<action>]\n" "\t [:<handler>.<action>]\n"
"\t [if <filter>]\n\n" "\t [if <filter>]\n\n"
"\t Note, special fields can be used as well:\n"
"\t common_timestamp - to record current timestamp\n"
"\t common_cpu - to record the CPU the event happened on\n"
"\n"
"\t When a matching event is hit, an entry is added to a hash\n" "\t When a matching event is hit, an entry is added to a hash\n"
"\t table using the key(s) and value(s) named, and the value of a\n" "\t table using the key(s) and value(s) named, and the value of a\n"
"\t sum called 'hitcount' is incremented. Keys and values\n" "\t sum called 'hitcount' is incremented. Keys and values\n"
......
...@@ -1111,7 +1111,7 @@ static const char *hist_field_name(struct hist_field *field, ...@@ -1111,7 +1111,7 @@ static const char *hist_field_name(struct hist_field *field,
field->flags & HIST_FIELD_FL_ALIAS) field->flags & HIST_FIELD_FL_ALIAS)
field_name = hist_field_name(field->operands[0], ++level); field_name = hist_field_name(field->operands[0], ++level);
else if (field->flags & HIST_FIELD_FL_CPU) else if (field->flags & HIST_FIELD_FL_CPU)
field_name = "cpu"; field_name = "common_cpu";
else if (field->flags & HIST_FIELD_FL_EXPR || else if (field->flags & HIST_FIELD_FL_EXPR ||
field->flags & HIST_FIELD_FL_VAR_REF) { field->flags & HIST_FIELD_FL_VAR_REF) {
if (field->system) { if (field->system) {
...@@ -1991,16 +1991,26 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file, ...@@ -1991,16 +1991,26 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
hist_data->enable_timestamps = true; hist_data->enable_timestamps = true;
if (*flags & HIST_FIELD_FL_TIMESTAMP_USECS) if (*flags & HIST_FIELD_FL_TIMESTAMP_USECS)
hist_data->attrs->ts_in_usecs = true; hist_data->attrs->ts_in_usecs = true;
} else if (strcmp(field_name, "cpu") == 0) } else if (strcmp(field_name, "common_cpu") == 0)
*flags |= HIST_FIELD_FL_CPU; *flags |= HIST_FIELD_FL_CPU;
else { else {
field = trace_find_event_field(file->event_call, field_name); field = trace_find_event_field(file->event_call, field_name);
if (!field || !field->size) { if (!field || !field->size) {
hist_err(tr, HIST_ERR_FIELD_NOT_FOUND, errpos(field_name)); /*
* For backward compatibility, if field_name
* was "cpu", then we treat this the same as
* common_cpu.
*/
if (strcmp(field_name, "cpu") == 0) {
*flags |= HIST_FIELD_FL_CPU;
} else {
hist_err(tr, HIST_ERR_FIELD_NOT_FOUND,
errpos(field_name));
field = ERR_PTR(-EINVAL); field = ERR_PTR(-EINVAL);
goto out; goto out;
} }
} }
}
out: out:
kfree(str); kfree(str);
...@@ -5085,7 +5095,7 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field) ...@@ -5085,7 +5095,7 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
seq_printf(m, "%s=", hist_field->var.name); seq_printf(m, "%s=", hist_field->var.name);
if (hist_field->flags & HIST_FIELD_FL_CPU) if (hist_field->flags & HIST_FIELD_FL_CPU)
seq_puts(m, "cpu"); seq_puts(m, "common_cpu");
else if (field_name) { else if (field_name) {
if (hist_field->flags & HIST_FIELD_FL_VAR_REF || if (hist_field->flags & HIST_FIELD_FL_VAR_REF ||
hist_field->flags & HIST_FIELD_FL_ALIAS) hist_field->flags & HIST_FIELD_FL_ALIAS)
......
...@@ -893,15 +893,13 @@ static struct synth_event *alloc_synth_event(const char *name, int n_fields, ...@@ -893,15 +893,13 @@ static struct synth_event *alloc_synth_event(const char *name, int n_fields,
dyn_event_init(&event->devent, &synth_event_ops); dyn_event_init(&event->devent, &synth_event_ops);
for (i = 0, j = 0; i < n_fields; i++) { for (i = 0, j = 0; i < n_fields; i++) {
fields[i]->field_pos = i;
event->fields[i] = fields[i]; event->fields[i] = fields[i];
if (fields[i]->is_dynamic) { if (fields[i]->is_dynamic)
event->dynamic_fields[j] = fields[i];
event->dynamic_fields[j]->field_pos = i;
event->dynamic_fields[j++] = fields[i]; event->dynamic_fields[j++] = fields[i];
event->n_dynamic_fields++;
}
} }
event->n_dynamic_fields = j;
event->n_fields = n_fields; event->n_fields = n_fields;
out: out:
return event; return event;
......
...@@ -14,10 +14,10 @@ struct synth_field { ...@@ -14,10 +14,10 @@ struct synth_field {
char *name; char *name;
size_t size; size_t size;
unsigned int offset; unsigned int offset;
unsigned int field_pos;
bool is_signed; bool is_signed;
bool is_string; bool is_string;
bool is_dynamic; bool is_dynamic;
bool field_pos;
}; };
struct synth_event { struct synth_event {
......
...@@ -299,8 +299,8 @@ static int tracepoint_add_func(struct tracepoint *tp, ...@@ -299,8 +299,8 @@ static int tracepoint_add_func(struct tracepoint *tp,
* a pointer to it. This array is referenced by __DO_TRACE from * a pointer to it. This array is referenced by __DO_TRACE from
* include/linux/tracepoint.h using rcu_dereference_sched(). * include/linux/tracepoint.h using rcu_dereference_sched().
*/ */
rcu_assign_pointer(tp->funcs, tp_funcs);
tracepoint_update_call(tp, tp_funcs, false); tracepoint_update_call(tp, tp_funcs, false);
rcu_assign_pointer(tp->funcs, tp_funcs);
static_key_enable(&tp->key); static_key_enable(&tp->key);
release_probes(old); release_probes(old);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment