tracing: fixes, clean ups and optimizations
Subsystems (5)
Steven Rostedt
maintainerLinus,
This contains fixes, optimizations and some clean ups
Some of the fixes need to go back to 3.10. They are minor, and deal mostly with incorrect ref counting in accessing event files.
There was a couple of optimizations that should have perf perform a bit better when accessing trace events.
And some various clean ups. Some of the clean ups are necessary to help in a fix to a theoretical race between opening a event file and deleting that event. That fix isn't there yet, we are still working on a clean solution.
Please pull the latest trace-3.11-rc2 tree, which can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
trace-3.11-rc2
Tag SHA1: 8876f82e516564d3581e1572f10d5f229beed1b8 Head SHA1: e70e78e3c83b536730e31231dd9b979768d8df3c
Alexander Z Lam (2):
tracing: Fix error handling to ensure instances can always be removed
tracing: Miscellaneous fixes for trace_array ref counting
Masami Hiramatsu (1):
tracing/kprobe: Wait for disabling all running kprobe handlers
Oleg Nesterov (7):
tracing/function: Avoid perf_trace_buf_*() if event_function.perf_events is empty tracing/syscall: Avoid perf_trace_buf_*() if sys_data->perf_events is empty tracing/perf: Move the PERF_MAX_TRACE_SIZE check into perf_trace_buf_prepare()
tracing: Simplify the iteration logic in f_start/f_next
tracing: Do not (ab)use trace_seq in event_id_read()
tracing: Kill trace_array->waiter
tracing: Kill the unbalanced tr->ref++ in tracing_buffers_open()
Steven Rostedt (Red Hat) (1):
tracing: Add ref_data to function and fgraph tracer structs
zhangwei(Jovi) (3):
tracing: Use correct config guard CONFIG_STACK_TRACER
tracing: Use trace_seq_puts()/trace_seq_putc() where possible
tracing: Typo fix on ring buffer comments
----
include/trace/ftrace.h | 4 -- kernel/trace/ring_buffer.c | 26 ++++----- kernel/trace/trace.c | 34 ++++++++---- kernel/trace/trace.h | 10 +++- kernel/trace/trace_event_perf.c | 10 +++- kernel/trace/trace_events.c | 98 ++++++++++++++++------------------ kernel/trace/trace_events_filter.c | 4 +- kernel/trace/trace_functions.c | 2 +- kernel/trace/trace_functions_graph.c | 54 +++++++++---------- kernel/trace/trace_kprobe.c | 29 +++++----- kernel/trace/trace_mmiotrace.c | 8 +-- kernel/trace/trace_output.c | 14 ++--- kernel/trace/trace_syscalls.c | 26 ++++----- kernel/trace/trace_uprobe.c | 2 - 14 files changed, 166 insertions(+), 155 deletions(-)
Steven Rostedt
maintainerPATCH 1/14 tracing: Use correct config guard CONFIG_STACK_TRACER
From: "zhangwei(Jovi)" <[email protected]>
We should use CONFIG_STACK_TRACER to guard readme text of stack tracer related file, not CONFIG_STACKTRACE.
--- kernel/trace/trace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/trace/trace.c +2 -2
@@ -3537,14 +3537,14 @@ static const char readme_msg[] ="\n snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n" "\t\t\t Read the contents for more information\n"#endif -#ifdef CONFIG_STACKTRACE +#ifdef CONFIG_STACK_TRACER " stack_trace\t\t- Shows the max stack trace when active\n" " stack_max_size\t- Shows current max stack size that was traced\n" "\t\t\t Write into this file to reset the max size (trigger a new trace)\n" #ifdef CONFIG_DYNAMIC_FTRACE " stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n"#endif -#endif /* CONFIG_STACKTRACE */ +#endif /* CONFIG_STACK_TRACER */ ; static ssize_t
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 2/14 tracing: Use trace_seq_puts()/trace_seq_putc() where possible
In reply to Steven RostedtFrom: "zhangwei(Jovi)" <[email protected]>
For string without format specifiers, use trace_seq_puts() or trace_seq_putc().
--- kernel/trace/ring_buffer.c | 10 +++---- kernel/trace/trace_events_filter.c | 4 +-- kernel/trace/trace_functions_graph.c | 52 +++++++++++++++++----------------- kernel/trace/trace_mmiotrace.c | 8 +++--- kernel/trace/trace_output.c | 14 ++++----- kernel/trace/trace_syscalls.c | 2 +- 6 files changed, 45 insertions(+), 45 deletions(-)
kernel/trace/ring_buffer.c +5 -5
@@ -36,11 +36,11 @@ int ring_buffer_print_entry_header(struct trace_seq *s) {int ret; - ret =trace_seq_printf (s,"# compressed entry header\n" ); - ret =trace_seq_printf (s,"\ttype_len : 5 bits\n" ); - ret =trace_seq_printf (s,"\ttime_delta : 27 bits\n" ); - ret =trace_seq_printf (s,"\tarray : 32 bits\n" ); - ret =trace_seq_printf (s,"\n" ); + ret =trace_seq_puts (s,"# compressed entry header\n" ); + ret =trace_seq_puts (s,"\ttype_len : 5 bits\n" ); + ret =trace_seq_puts (s,"\ttime_delta : 27 bits\n" ); + ret =trace_seq_puts (s,"\tarray : 32 bits\n" ); + ret =trace_seq_putc (s,'\n' ); ret =trace_seq_printf (s,"\tpadding : type == %d\n" ,RINGBUF_TYPE_PADDING ); ret = trace_seq_printf(s, "\ttime_extend : type == %d\n",
kernel/trace/trace_events_filter.c +2 -2
@@ -646,7 +646,7 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)if (filter && filter->filter_string)trace_seq_printf (s,"%s\n" , filter->filter_string);else -trace_seq_printf (s,"none\n" ); +trace_seq_puts (s,"none\n" );mutex_unlock (&event_mutex); }
@@ -660,7 +660,7 @@ void print_subsystem_event_filter(struct event_subsystem *system,if (filter && filter->filter_string)trace_seq_printf (s,"%s\n" , filter->filter_string);else -trace_seq_printf (s,DEFAULT_SYS_FILTER_MESSAGE "\n" ); +trace_seq_puts (s,DEFAULT_SYS_FILTER_MESSAGE "\n" );mutex_unlock (&event_mutex); }
kernel/trace/trace_functions_graph.c +26 -26
189 lines not on this page · raw message
kernel/trace/trace_mmiotrace.c +4 -4
@@ -90,7 +90,7 @@ static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)if (drv) ret +=trace_seq_printf (s," %s\n" , drv->name);else - ret +=trace_seq_printf (s," \n" ); + ret +=trace_seq_puts (s," \n" );return ret; }
@@ -107,7 +107,7 @@ static void mmio_pipe_open(struct trace_iterator *iter)struct header_iter *hiter;struct trace_seq *s = &iter->seq; -trace_seq_printf (s,"VERSION 20070824\n" ); +trace_seq_puts (s,"VERSION 20070824\n" ); hiter =kzalloc (sizeof (*hiter),GFP_KERNEL );if (!hiter)
@@ -209,7 +209,7 @@ static enum print_line_t mmio_print_rw(struct trace_iterator *iter) (rw->value >> 0) & 0xff, rw->pc, 0);break ;default : - ret =trace_seq_printf (s,"rw what?\n" ); + ret =trace_seq_puts (s,"rw what?\n" );break ; }if (ret)
@@ -245,7 +245,7 @@ static enum print_line_t mmio_print_map(struct trace_iterator *iter) secs, usec_rem, m->map_id, 0UL, 0);break ;default : - ret =trace_seq_printf (s,"map what?\n" ); + ret =trace_seq_puts (s,"map what?\n" );break ; }if (ret)
kernel/trace/trace_output.c +7 -7
@@ -78,7 +78,7 @@ enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)trace_assign_type (field, entry); - ret =trace_seq_printf (s,"%s" , field->buf); + ret =trace_seq_puts (s, field->buf);if (!ret)return TRACE_TYPE_PARTIAL_LINE ;
@@ -558,14 +558,14 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,if (ret) ret =trace_seq_puts (s,"??" );if (ret) - ret =trace_seq_puts (s,"\n" ); + ret =trace_seq_putc (s,'\n' );continue ; }if (!ret)break ;if (ret) ret =seq_print_user_ip (s, mm, ip, sym_flags); - ret =trace_seq_puts (s,"\n" ); + ret =trace_seq_putc (s,'\n' ); }if (mm)
@@ -579,7 +579,7 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)int ret;if (!ip) -return trace_seq_printf (s,"0" ); +return trace_seq_putc (s,'0' );if (sym_flags &TRACE_ITER_SYM_OFFSET ) ret =seq_print_sym_offset (s,"%s" , ip);
@@ -964,14 +964,14 @@ static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags, goto partial;if ((flags &TRACE_ITER_PRINT_PARENT ) && field->parent_ip) { -if (!trace_seq_printf (s," <-" )) +if (!trace_seq_puts (s," <-" )) goto partial;if (!seq_print_ip_sym (s, field->parent_ip, flags)) goto partial; } -if (!trace_seq_printf (s,"\n" )) +if (!trace_seq_putc (s,'\n' )) goto partial;return TRACE_TYPE_HANDLED ;
@@ -1210,7 +1210,7 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,if (!seq_print_ip_sym (s, *p, flags)) goto partial; -if (!trace_seq_puts (s,"\n" )) +if (!trace_seq_putc (s,'\n' )) goto partial; }
kernel/trace/trace_syscalls.c +1 -1
@@ -175,7 +175,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags, entry =syscall_nr_to_meta (syscall);if (!entry) { -trace_seq_printf (s,"\n" ); +trace_seq_putc (s,'\n' );return TRACE_TYPE_HANDLED ; }
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 3/14 tracing: Typo fix on ring buffer comments
In reply to Steven RostedtFrom: "zhangwei(Jovi)" <[email protected]>
There have some mismatch between comments with
real function name, update it.
This patch also add some missed function arguments description.
--- kernel/trace/ring_buffer.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
kernel/trace/ring_buffer.c +9 -7
@@ -1066,7 +1066,7 @@ static int rb_check_list(struct ring_buffer_per_cpu *cpu_buffer, }/** -* check_pages - integrity check of buffer pages +* rb_check_pages - integrity check of buffer pages * @cpu_buffer: CPU buffer with pages to test * * As a safety measure we check to make sure the data pages have not
@@ -1258,7 +1258,7 @@ static int rb_cpu_notify(struct notifier_block *self,#endif /** -* ring_buffer_alloc - allocate a new ring_buffer +* __ring_buffer_alloc - allocate a new ring_buffer * @size: the size in bytes per cpu that is needed. * @flags: attributes to set for the ring buffer. *
@@ -1607,6 +1607,7 @@ static void update_pages_handler(struct work_struct *work)* ring_buffer_resize - resize the ring buffer * @buffer: the buffer to resize. * @size: the new size. +* @cpu_id: the cpu buffer to resize * * Minimum size is 2 * BUF_PAGE_SIZE. *
@@ -3956,11 +3957,11 @@ EXPORT_SYMBOL_GPL(ring_buffer_consume);* expected. * * After a sequence of ring_buffer_read_prepare calls, the user is -* expected to make at least one call to ring_buffer_prepare_sync. +* expected to make at least one call to ring_buffer_read_prepare_sync. * Afterwards, ring_buffer_read_start is invoked to get things going * for real. * -* This overall must be paired with ring_buffer_finish. +* This overall must be paired with ring_buffer_read_finish. */ struct ring_buffer_iter *ring_buffer_read_prepare (struct ring_buffer *buffer,int cpu)
@@ -4009,7 +4010,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_read_prepare_sync);* an intervening ring_buffer_read_prepare_sync must have been * performed. * -* Must be paired with ring_buffer_finish. +* Must be paired with ring_buffer_read_finish. */ void ring_buffer_read_start (struct ring_buffer_iter *iter)
@@ -4031,7 +4032,7 @@ ring_buffer_read_start(struct ring_buffer_iter *iter)EXPORT_SYMBOL_GPL (ring_buffer_read_start);/** -* ring_buffer_finish - finish reading the iterator of the buffer +* ring_buffer_read_finish - finish reading the iterator of the buffer * @iter: The iterator retrieved by ring_buffer_start * * This re-enables the recording to the buffer, and frees the
@@ -4346,6 +4347,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);/** * ring_buffer_alloc_read_page - allocate a page to read from buffer * @buffer: the buffer to allocate for. +* @cpu: the cpu buffer to allocate. * * This function is used in conjunction with ring_buffer_read_page. * When reading a full page from the ring buffer, these functions
@@ -4403,7 +4405,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);* to swap with a page in the ring buffer. * * for example: -* rpage = ring_buffer_alloc_read_page(buffer); +* rpage = ring_buffer_alloc_read_page(buffer, cpu); * if (!rpage) * return error; * ret = ring_buffer_read_page(buffer, &rpage, len, cpu, 0);
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 4/14 tracing/function: Avoid perf_trace_buf_*() if event_function.perf_events is empty
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
perf_trace_buf_prepare() + perf_trace_buf_submit(head, task => NULL) make no sense if hlist_empty(head). Change perf_ftrace_function_call() to check event_function.perf_events beforehand.
--- kernel/trace/trace_event_perf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/trace/trace_event_perf.c +4 -2
@@ -266,6 +266,10 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,struct pt_regs regs;int rctx; + head =this_cpu_ptr (event_function.perf_events); +if (hlist_empty (head)) +return ; +#define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \ sizeof(u64)) - sizeof(u32))
@@ -279,8 +283,6 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip, entry->ip = ip; entry->parent_ip = parent_ip; - - head =this_cpu_ptr (event_function.perf_events);perf_trace_buf_submit (entry,ENTRY_SIZE , rctx,0 ,1 , ®s, head,NULL );
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 5/14 tracing/syscall: Avoid perf_trace_buf_*() if sys_data->perf_events is empty
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
perf_trace_buf_prepare() + perf_trace_buf_submit(head, task => NULL) make no sense if hlist_empty(head). Change perf_syscall_enter/exit() to check sys_data->{enter,exit}_event->perf_events beforehand.
--- kernel/trace/trace_syscalls.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
kernel/trace/trace_syscalls.c +8 -4
@@ -566,6 +566,10 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)if (!sys_data)return ; + head =this_cpu_ptr (sys_data->enter_event->perf_events); +if (hlist_empty (head)) +return ; +/* get the size after alignment with the u32 buffer size field */ size =sizeof (unsigned long ) * sys_data->nb_args +sizeof (*rec); size =ALIGN (size +sizeof (u32),sizeof (u64));
@@ -583,8 +587,6 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) rec->nr = syscall_nr;syscall_get_arguments (current, regs,0 , sys_data->nb_args, (unsigned long *)&rec->args); - - head =this_cpu_ptr (sys_data->enter_event->perf_events);perf_trace_buf_submit (rec, size, rctx,0 ,1 , regs, head,NULL ); }
@@ -642,6 +644,10 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)if (!sys_data)return ; + head =this_cpu_ptr (sys_data->exit_event->perf_events); +if (hlist_empty (head)) +return ; +/* We can probably do that at build time */ size =ALIGN (sizeof (*rec) +sizeof (u32),sizeof (u64)); size -=sizeof (u32);
@@ -661,8 +667,6 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) rec->nr = syscall_nr; rec->ret =syscall_get_return_value (current, regs); - - head =this_cpu_ptr (sys_data->exit_event->perf_events);perf_trace_buf_submit (rec, size, rctx,0 ,1 , regs, head,NULL ); }
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 6/14 tracing/perf: Move the PERF_MAX_TRACE_SIZE check into perf_trace_buf_prepare()
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
Every perf_trace_buf_prepare() caller does WARN_ONCE(size > PERF_MAX_TRACE_SIZE, message) and "message" is almost the same.
Shift this WARN_ONCE() into perf_trace_buf_prepare(). This changes the meaning of _ONCE, but I think this is fine.
- 4947014 2932448 10104832 17984294 1126b26 vmlinux + 4948422 2932448 10104832 17985702 11270a6 vmlinux
on my build.
--- include/trace/ftrace.h | 4 ---- kernel/trace/trace_event_perf.c | 4 ++++ kernel/trace/trace_kprobe.c | 6 ------ kernel/trace/trace_syscalls.c | 12 ------------ kernel/trace/trace_uprobe.c | 2 -- 5 files changed, 4 insertions(+), 24 deletions(-)
include/trace/ftrace.h +0 -4
@@ -670,10 +670,6 @@ perf_trace_##call(void *__data, proto) \ sizeof(u64)); \ __entry_size -=sizeof (u32); \ \ -if (WARN_ONCE (__entry_size >PERF_MAX_TRACE_SIZE , \ -"profile buffer not large enough" )) \ -return ; \ - \ entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare( \ __entry_size, event_call->event.type, &__regs, &rctx); \if (!entry) \
kernel/trace/trace_event_perf.c +4 -0
@@ -236,6 +236,10 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,BUILD_BUG_ON (PERF_MAX_TRACE_SIZE %sizeof (unsigned long )); +if (WARN_ONCE (size >PERF_MAX_TRACE_SIZE , +"perf buffer not large enough" )) +return NULL ; + pc =preempt_count (); *rctxp =perf_swevent_get_recursion_context ();
kernel/trace/trace_kprobe.c +0 -6
@@ -1087,9 +1087,6 @@ kprobe_perf_func(struct trace_probe *tp, struct pt_regs *regs) __size =sizeof (*entry) + tp->size + dsize; size =ALIGN (__size +sizeof (u32),sizeof (u64)); size -=sizeof (u32); -if (WARN_ONCE (size >PERF_MAX_TRACE_SIZE , -"profile buffer not large enough" )) -return ; entry =perf_trace_buf_prepare (size, call->event.type, regs, &rctx);if (!entry)
@@ -1120,9 +1117,6 @@ kretprobe_perf_func(struct trace_probe *tp, struct kretprobe_instance *ri, __size =sizeof (*entry) + tp->size + dsize; size =ALIGN (__size +sizeof (u32),sizeof (u64)); size -=sizeof (u32); -if (WARN_ONCE (size >PERF_MAX_TRACE_SIZE , -"profile buffer not large enough" )) -return ; entry =perf_trace_buf_prepare (size, call->event.type, regs, &rctx);if (!entry)
kernel/trace/trace_syscalls.c +0 -12
@@ -575,10 +575,6 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) size =ALIGN (size +sizeof (u32),sizeof (u64)); size -=sizeof (u32); -if (WARN_ONCE (size >PERF_MAX_TRACE_SIZE , -"perf buffer not large enough" )) -return ; - rec = (struct syscall_trace_enter *)perf_trace_buf_prepare (size, sys_data->enter_event->event.type, regs, &rctx);if (!rec)
@@ -652,14 +648,6 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) size =ALIGN (sizeof (*rec) +sizeof (u32),sizeof (u64)); size -=sizeof (u32); -/* -* Impossible, but be paranoid with the future -* How to put this check outside runtime? -*/ -if (WARN_ONCE (size >PERF_MAX_TRACE_SIZE , -"exit event has grown above perf buffer size" )) -return ; - rec = (struct syscall_trace_exit *)perf_trace_buf_prepare (size, sys_data->exit_event->event.type, regs, &rctx);if (!rec)
kernel/trace/trace_uprobe.c +0 -2
@@ -818,8 +818,6 @@ static void uprobe_perf_print(struct trace_uprobe *tu, size =SIZEOF_TRACE_ENTRY (is_ret_probe (tu)); size =ALIGN (size + tu->size +sizeof (u32),sizeof (u64)) -sizeof (u32); -if (WARN_ONCE (size >PERF_MAX_TRACE_SIZE ,"profile buffer not large enough" )) -return ;preempt_disable (); head =this_cpu_ptr (call->perf_events);
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 7/14 tracing/kprobe: Wait for disabling all running kprobe handlers
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Wait for disabling all running kprobe handlers when a kprobe event is disabled, since the caller, trace_remove_event_call() supposes that a removing event is disabled completely by disabling the event.
With this change, ftrace can ensure that there is no running event handlers after disabling it.
--- kernel/trace/trace_kprobe.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
kernel/trace/trace_kprobe.c +17 -6
@@ -243,11 +243,11 @@ find_event_file_link(struct trace_probe *tp, struct ftrace_event_file *file)static int disable_trace_probe (struct trace_probe *tp,struct ftrace_event_file *file) { +struct event_file_link *link =NULL ; +int wait =0 ;int ret =0 ;if (file) { -struct event_file_link *link; - link =find_event_file_link (tp, file);if (!link) { ret = -EINVAL ;
@@ -255,10 +255,7 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file) }list_del_rcu (&link->list); -/* synchronize with kprobe_trace_func/kretprobe_trace_func */ -synchronize_sched (); -kfree (link); - + wait =1 ;if (!list_empty (&tp->files)) goto out;
@@ -271,8 +268,22 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)disable_kretprobe (&tp->rp); else disable_kprobe(&tp->rp.kp); + wait =1 ; } out: +if (wait) { +/* +* Synchronize with kprobe_trace_func/kretprobe_trace_func +* to ensure disabled (all running handlers are finished). +* This is not only for kfree(), but also the caller, +* trace_remove_event_call() supposes it for releasing +* event_call related objects, which will be accessed in +* the kprobe_trace_func/kretprobe_trace_func. +*/ +synchronize_sched (); +kfree (link);/* Ignored if link == NULL */ + } +return ret; }
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 8/14 tracing: Fix error handling to ensure instances can always be removed
In reply to Steven RostedtFrom: Alexander Z Lam <[email protected]>
Remove debugfs directories for tracing instances during creation if an error occurs causing the trace_array for that instance to not be added to ftrace_trace_arrays. If the directory continues to exist after the error, it cannot be removed because the respective trace_array is not in ftrace_trace_arrays.
--- kernel/trace/trace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/trace.c +3 -1
@@ -5973,8 +5973,10 @@ static int new_instance_create(const char *name) goto out_free_tr; ret =event_trace_add_tracer (tr->dir, tr); -if (ret) +if (ret) { +debugfs_remove_recursive (tr->dir); goto out_free_tr; + }init_tracer_debugfs (tr, tr->dir);
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 9/14 tracing: Miscellaneous fixes for trace_array ref counting
In reply to Steven RostedtFrom: Alexander Z Lam <[email protected]>
Some error paths did not handle ref counting properly, and some trace files need ref counting.
--- kernel/trace/trace.c | 24 ++++++++++++++++++------ kernel/trace/trace_events.c | 21 +++++++++++++++++++-- 2 files changed, 37 insertions(+), 8 deletions(-)
kernel/trace/trace.c +18 -6
@@ -3008,7 +3008,6 @@ static int tracing_release(struct inode *inode, struct file *file) iter = m->private; tr = iter->tr; -trace_array_put (tr);mutex_lock (&trace_types_lock);
@@ -3023,6 +3022,9 @@ static int tracing_release(struct inode *inode, struct file *file)if (!iter->snapshot)/* reenable tracing if it was previously enabled */ tracing_start_tr (tr); + +__trace_array_put (tr); +mutex_unlock (&trace_types_lock);mutex_destroy (&iter->mutex);
@@ -3447,6 +3449,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,static int tracing_trace_options_open (struct inode *inode,struct file *file) {struct trace_array *tr = inode->i_private; +int ret;if (tracing_disabled)return -ENODEV ;
@@ -3454,7 +3457,11 @@ static int tracing_trace_options_open(struct inode *inode, struct file *file)if (trace_array_get (tr) <0 )return -ENODEV ; -return single_open (file, tracing_trace_options_show, inode->i_private); + ret =single_open (file, tracing_trace_options_show, inode->i_private); +if (ret <0 ) +trace_array_put (tr); + +return ret; }static const struct file_operations tracing_iter_fops = {
@@ -3958,6 +3965,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) iter =kzalloc (sizeof (*iter),GFP_KERNEL );if (!iter) { ret = -ENOMEM ; +__trace_array_put (tr); goto out; }
@@ -4704,21 +4712,24 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file) ret =PTR_ERR (iter); }else {/* Writes still need the seq_file to hold the private data */ + ret = -ENOMEM ; m =kzalloc (sizeof (*m),GFP_KERNEL );if (!m) -return -ENOMEM ; + goto out; iter =kzalloc (sizeof (*iter),GFP_KERNEL );if (!iter) {kfree (m); -return -ENOMEM ; + goto out; } + ret =0 ; + iter->tr = tr; iter->trace_buffer = &tc->tr->max_buffer; iter->cpu_file = tc->cpu; m->private = iter; file->private_data = m; } - +out:if (ret <0 )trace_array_put (tr);
@@ -5328,9 +5339,10 @@ tracing_stats_read(struct file *filp, char __user *ubuf, }static const struct file_operations tracing_stats_fops = { - .open = tracing_open_generic, + .open = tracing_open_generic_tc, .read = tracing_stats_read, .llseek = generic_file_llseek, + .release = tracing_release_generic_tc, };#ifdef CONFIG_DYNAMIC_FTRACE
kernel/trace/trace_events.c +19 -2
@@ -1218,6 +1218,7 @@ show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)static int ftrace_event_avail_open (struct inode *inode,struct file *file);static int ftrace_event_set_open (struct inode *inode,struct file *file); +static int ftrace_event_release (struct inode *inode,struct file *file);static const struct seq_operations show_event_seq_ops = { .start = t_start,
@@ -1245,7 +1246,7 @@ static const struct file_operations ftrace_set_event_fops = { .read = seq_read, .write = ftrace_event_write, .llseek = seq_lseek, - .release = seq_release, + .release = ftrace_event_release, };static const struct file_operations ftrace_enable_fops = {
@@ -1323,6 +1324,15 @@ ftrace_event_open(struct inode *inode, struct file *file,return ret; } +static int ftrace_event_release (struct inode *inode,struct file *file) +{ +struct trace_array *tr = inode->i_private; + +trace_array_put (tr); + +return seq_release (inode, file); +} +static int ftrace_event_avail_open (struct inode *inode,struct file *file) {
@@ -1336,12 +1346,19 @@ ftrace_event_set_open(struct inode *inode, struct file *file) {const struct seq_operations *seq_ops = &show_set_event_seq_ops;struct trace_array *tr = inode->i_private; +int ret; + +if (trace_array_get (tr) <0 ) +return -ENODEV ;if ((file->f_mode &FMODE_WRITE ) && (file->f_flags &O_TRUNC ))ftrace_clear_events (tr); -return ftrace_event_open (inode, file, seq_ops); + ret =ftrace_event_open (inode, file, seq_ops); +if (ret <0 ) +trace_array_put (tr); +return ret; } static struct event_subsystem *
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 10/14 tracing: Add ref_data to function and fgraph tracer structs
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
The selftest for function and function graph tracers are defined as __init, as they are only executed at boot up. The "tracer" structs that are associated to those tracers are not setup as __init as they are used after boot. To stop mismatch warnings, those structures need to be annotated with __ref_data.
Currently, the tracer structures are defined to __read_mostly, as they do not really change. But in the future they should be converted to consts, but that will take a little work because they have a "next" pointer that gets updated when they are registered. That will have to wait till the next major release.
--- kernel/trace/trace.h | 9 +++++++++ kernel/trace/trace_functions.c | 2 +- kernel/trace/trace_functions_graph.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-)
kernel/trace/trace.h +9 -0
@@ -680,6 +680,15 @@ extern int trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr);extern int trace_selftest_startup_branch (struct tracer *trace,struct trace_array *tr); +/* +* Tracer data references selftest functions that only occur +* on boot up. These can be __init functions. Thus, when selftests +* are enabled, then the tracers need to reference __init functions. +*/ +#define __tracer_data __refdata +#else +/* Tracers are seldom changed. Optimize when selftests are disabled. */ +#define __tracer_data __read_mostly#endif /* CONFIG_FTRACE_STARTUP_TEST */ extern void *head_page (struct trace_array_cpu *data);
kernel/trace/trace_functions.c +1 -1
@@ -199,7 +199,7 @@ static int func_set_flag(u32 old_flags, u32 bit, int set)return 0 ; } -static struct tracer function_trace__read_mostly = +static struct tracer function_trace __tracer_data = { .name ="function" , .init = function_trace_init,
kernel/trace/trace_functions_graph.c +1 -1
@@ -1448,7 +1448,7 @@ static struct trace_event graph_trace_ret_event = { .funcs = &graph_functions }; -static struct tracer graph_trace__read_mostly = { +static struct tracer graph_trace __tracer_data = { .name ="function_graph" , .open = graph_trace_open, .pipe_open = graph_trace_open,
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 11/14 tracing: Simplify the iteration logic in f_start/f_next
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
f_next() looks overcomplicated, and it is not strictly correct even if this doesn't matter.
Say, FORMAT_FIELD_SEPERATOR should not return NULL (means EOF) if trace_get_fields() returns an empty list, we should simply advance to FORMAT_PRINTFMT as we do when we find the end of list.
1. Change f_next() to return "struct list_head *" rather than "ftrace_event_field *", and change f_show() to do list_entry().
This simplifies the code a bit, only f_show() needs to know about ftrace_event_field, and f_next() can play with ->prev directly
2. Change f_next() to not play with ->prev / return inside the switch() statement. It can simply set node = head/common_head, the prev-or-advance-to-the-next-magic below does all work.
While at it. f_start() looks overcomplicated too. I don't think *pos == 0 makes sense as a separate case, just change this code to do "while" instead of "do/while".
The patch also moves f_start() down, close to f_stop(). This is purely cosmetic, just to make the locking added by the next patch more clear/visible.
--- kernel/trace/trace_events.c | 60 ++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 38 deletions(-)
kernel/trace/trace_events.c +22 -38
@@ -826,59 +826,33 @@ enum {static void *f_next (struct seq_file *m,void *v,loff_t *pos) {struct ftrace_event_call *call = m->private; -struct ftrace_event_field *field;struct list_head *common_head = &ftrace_common_fields;struct list_head *head =trace_get_fields (call); +struct list_head *node = v; (*pos)++;switch ((unsigned long )v) {case FORMAT_HEADER : -if (unlikely (list_empty (common_head))) -return NULL ; - - field =list_entry (common_head->prev, - struct ftrace_event_field, link); -return field; + node = common_head; +break ;case FORMAT_FIELD_SEPERATOR : -if (unlikely (list_empty (head))) -return NULL ; - - field = list_entry(head->prev, struct ftrace_event_field, link); -return field; + node = head; +break ;case FORMAT_PRINTFMT :/* all done */ return NULL ; } - field = v; -if (field->link.prev == common_head) + node = node->prev; +if (node == common_head)return (void *)FORMAT_FIELD_SEPERATOR ; -else if (field->link.prev == head) +else if (node == head)return (void *)FORMAT_PRINTFMT ; - - field = list_entry(field->link.prev, struct ftrace_event_field, link); - -return field; -} - -static void *f_start (struct seq_file *m,loff_t *pos) -{ -loff_t l =0 ; -void *p; - -/* Start by showing the header */ -if (!*pos) -return (void *)FORMAT_HEADER ; - - p = (void *)FORMAT_HEADER ; -do { - p =f_next (m, p, &l); - }while (p && l < *pos); - -return p; +else +return node; }static int f_show (struct seq_file *m,void *v)
@@ -904,8 +878,7 @@ static int f_show(struct seq_file *m, void *v)return 0 ; } - field = v; - + field = list_entry(v, struct ftrace_event_field, link);/* * Smartly shows the array type(except dynamic array). * Normal:
@@ -932,6 +905,17 @@ static int f_show(struct seq_file *m, void *v)return 0 ; } +static void *f_start (struct seq_file *m,loff_t *pos) +{ +void *p = (void *)FORMAT_HEADER ; +loff_t l =0 ; + +while (l < *pos && p) + p =f_next (m, p, &l); + +return p; +} +static void f_stop (struct seq_file *m,void *p) { }
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 12/14 tracing: Do not (ab)use trace_seq in event_id_read()
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
event_id_read() has no reason to kmalloc "struct trace_seq" (more than PAGE_SIZE!), it can use a small buffer instead.
Note: "if (*ppos) return 0" looks strange and even wrong, simple_read_from_buffer() handles ppos != 0 case corrrectly.
And it seems that almost every user of trace_seq in this file should be converted too. Unless you use seq_open(), trace_seq buys nothing compared to the raw buffer, but it needs a bit more memory and code.
--- kernel/trace/trace_events.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-)
kernel/trace/trace_events.c +4 -13
@@ -947,23 +947,14 @@ static ssize_t event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { struct ftrace_event_call *call = filp->private_data; -struct trace_seq *s; -int r; +char buf[32 ]; +int len;if (*ppos)return 0 ; - s =kmalloc (sizeof (*s),GFP_KERNEL ); -if (!s) -return -ENOMEM ; - -trace_seq_init (s); -trace_seq_printf (s,"%d\n" , call->event.type); - - r =simple_read_from_buffer (ubuf, cnt, ppos, - s->buffer, s->len); -kfree (s); -return r; + len =sprintf (buf,"%d\n" , call->event.type); +return simple_read_from_buffer (ubuf, cnt, ppos, buf, len); } static ssize_t
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 13/14 tracing: Kill trace_array->waiter
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
Trivial. trace_array->waiter has no users since 6eaaa5d5 "tracing/core: use appropriate waiting on trace_pipe".
--- kernel/trace/trace.h | 1 - 1 file changed, 1 deletion(-)
kernel/trace/trace.h +0 -1
@@ -214,7 +214,6 @@ struct trace_array {struct dentry *event_dir;struct list_head systems;struct list_head events; -struct task_struct *waiter;int ref; };
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 14/14 tracing: Kill the unbalanced tr->ref++ in tracing_buffers_open()
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
tracing_buffers_open() does trace_array_get() and then it wrongly inrcements tr->ref again under trace_types_lock. This means that every caller leaks trace_array:
# cd /sys/kernel/debug/tracing/ # mkdir instances/X # true < instances/X/per_cpu/cpu0/trace_pipe_raw # rmdir instances/X rmdir: failed to remove `instances/X': Device or resource busy
--- kernel/trace/trace.c | 2 -- 1 file changed, 2 deletions(-)
kernel/trace/trace.c +0 -2
@@ -4959,8 +4959,6 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)mutex_lock (&trace_types_lock); - tr->ref++; - info->iter.tr = tr; info->iter.cpu_file = tc->cpu; info->iter.trace = tr->current_trace;
Signature · 1 line
1.7.10.4