tracing: Cleanups and fixes
Subsystems (5)
Steven Rostedt
maintainercover tracing: Cleanups and fixes
These are mostly cleanups and some minor fixes. Still working on fixing a theoretical race with trace events.
-- Steve
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
for-next
Head SHA1: cd458ba9d5a5592d37b5145e560071e91ea762ac
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 (5):
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()
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 | 32 +++++++---- kernel/trace/trace.h | 9 ++++ 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(+), 152 deletions(-)
Steven Rostedt
maintainerPATCH 1/12 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/12 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/12 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/12 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/12 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/12 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/12 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/12 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/12 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/12 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/12 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/12 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