diff --git a/[refs] b/[refs] index baae00dd0175..e74316c1f1b8 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: fee039a1d05c6e0f71b0fe270d847742a02d56c4 +refs/heads/master: 1a17662ea033674a58bad3603531b0b5d42572f6 diff --git a/trunk/arch/x86/kernel/ftrace.c b/trunk/arch/x86/kernel/ftrace.c index 57b33edb7ce3..1d0d7f42efe3 100644 --- a/trunk/arch/x86/kernel/ftrace.c +++ b/trunk/arch/x86/kernel/ftrace.c @@ -79,11 +79,11 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) * * 1) Put the instruction pointer into the IP buffer * and the new code into the "code" buffer. - * 2) Wait for any running NMIs to finish and set a flag that says - * we are modifying code, it is done in an atomic operation. - * 3) Write the code - * 4) clear the flag. - * 5) Wait for any running NMIs to finish. + * 2) Set a flag that says we are modifying code + * 3) Wait for any running NMIs to finish. + * 4) Write the code + * 5) clear the flag. + * 6) Wait for any running NMIs to finish. * * If an NMI is executed, the first thing it does is to call * "ftrace_nmi_enter". This will check if the flag is set to write @@ -95,9 +95,9 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) * are the same as what exists. */ -#define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */ static atomic_t nmi_running = ATOMIC_INIT(0); static int mod_code_status; /* holds return value of text write */ +static int mod_code_write; /* set when NMI should do the write */ static void *mod_code_ip; /* holds the IP to write to */ static void *mod_code_newcode; /* holds the text to write to the IP */ @@ -114,20 +114,6 @@ int ftrace_arch_read_dyn_info(char *buf, int size) return r; } -static void clear_mod_flag(void) -{ - int old = atomic_read(&nmi_running); - - for (;;) { - int new = old & ~MOD_CODE_WRITE_FLAG; - - if (old == new) - break; - - old = atomic_cmpxchg(&nmi_running, old, new); - } -} - static void ftrace_mod_code(void) { /* @@ -141,39 +127,27 @@ static void ftrace_mod_code(void) /* if we fail, then kill any new writers */ if (mod_code_status) - clear_mod_flag(); + mod_code_write = 0; } void ftrace_nmi_enter(void) { - if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) { - smp_rmb(); + atomic_inc(&nmi_running); + /* Must have nmi_running seen before reading write flag */ + smp_mb(); + if (mod_code_write) { ftrace_mod_code(); atomic_inc(&nmi_update_count); } - /* Must have previous changes seen before executions */ - smp_mb(); } void ftrace_nmi_exit(void) { /* Finish all executions before clearing nmi_running */ - smp_mb(); + smp_wmb(); atomic_dec(&nmi_running); } -static void wait_for_nmi_and_set_mod_flag(void) -{ - if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG)) - return; - - do { - cpu_relax(); - } while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG)); - - nmi_wait_count++; -} - static void wait_for_nmi(void) { if (!atomic_read(&nmi_running)) @@ -193,9 +167,14 @@ do_ftrace_mod_code(unsigned long ip, void *new_code) mod_code_newcode = new_code; /* The buffers need to be visible before we let NMIs write them */ + smp_wmb(); + + mod_code_write = 1; + + /* Make sure write bit is visible before we wait on NMIs */ smp_mb(); - wait_for_nmi_and_set_mod_flag(); + wait_for_nmi(); /* Make sure all running NMIs have finished before we write the code */ smp_mb(); @@ -203,9 +182,13 @@ do_ftrace_mod_code(unsigned long ip, void *new_code) ftrace_mod_code(); /* Make sure the write happens before clearing the bit */ + smp_wmb(); + + mod_code_write = 0; + + /* make sure NMIs see the cleared bit */ smp_mb(); - clear_mod_flag(); wait_for_nmi(); return mod_code_status; diff --git a/trunk/arch/x86/kernel/kprobes.c b/trunk/arch/x86/kernel/kprobes.c index 759095d53a06..4558dd3918cf 100644 --- a/trunk/arch/x86/kernel/kprobes.c +++ b/trunk/arch/x86/kernel/kprobes.c @@ -638,13 +638,13 @@ static void __used __kprobes kretprobe_trampoline_holder(void) #else " pushf\n" /* - * Skip cs, ip, orig_ax and gs. + * Skip cs, ip, orig_ax. * trampoline_handler() will plug in these values */ - " subl $16, %esp\n" + " subl $12, %esp\n" " pushl %fs\n" - " pushl %es\n" " pushl %ds\n" + " pushl %es\n" " pushl %eax\n" " pushl %ebp\n" " pushl %edi\n" @@ -655,10 +655,10 @@ static void __used __kprobes kretprobe_trampoline_holder(void) " movl %esp, %eax\n" " call trampoline_handler\n" /* Move flags to cs */ - " movl 56(%esp), %edx\n" - " movl %edx, 52(%esp)\n" + " movl 52(%esp), %edx\n" + " movl %edx, 48(%esp)\n" /* Replace saved flags with true return address. */ - " movl %eax, 56(%esp)\n" + " movl %eax, 52(%esp)\n" " popl %ebx\n" " popl %ecx\n" " popl %edx\n" @@ -666,8 +666,8 @@ static void __used __kprobes kretprobe_trampoline_holder(void) " popl %edi\n" " popl %ebp\n" " popl %eax\n" - /* Skip ds, es, fs, gs, orig_ax and ip */ - " addl $24, %esp\n" + /* Skip ip, orig_ax, es, ds, fs */ + " addl $20, %esp\n" " popf\n" #endif " ret\n"); @@ -691,7 +691,6 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) regs->cs = __KERNEL_CS; #else regs->cs = __KERNEL_CS | get_kernel_rpl(); - regs->gs = 0; #endif regs->ip = trampoline_address; regs->orig_ax = ~0UL; diff --git a/trunk/kernel/extable.c b/trunk/kernel/extable.c index 25d39b0c3a1b..0df6253730be 100644 --- a/trunk/kernel/extable.c +++ b/trunk/kernel/extable.c @@ -15,21 +15,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include -#include #include - -#include +#include #include - -/* - * mutex protecting text section modification (dynamic code patching). - * some users need to sleep (allocating memory...) while they hold this lock. - * - * NOT exported to modules - patching kernel text is a really delicate matter. - */ -DEFINE_MUTEX(text_mutex); +#include extern struct exception_table_entry __start___ex_table[]; extern struct exception_table_entry __stop___ex_table[]; diff --git a/trunk/kernel/trace/Makefile b/trunk/kernel/trace/Makefile index 0e45c206c2f9..c3feea01c3e0 100644 --- a/trunk/kernel/trace/Makefile +++ b/trunk/kernel/trace/Makefile @@ -44,6 +44,5 @@ obj-$(CONFIG_EVENT_TRACER) += trace_events.o obj-$(CONFIG_EVENT_TRACER) += events.o obj-$(CONFIG_EVENT_TRACER) += trace_export.o obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o -obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o libftrace-y := ftrace.o diff --git a/trunk/kernel/trace/blktrace.c b/trunk/kernel/trace/blktrace.c index b171778e3863..fb3bc53835dd 100644 --- a/trunk/kernel/trace/blktrace.c +++ b/trunk/kernel/trace/blktrace.c @@ -432,7 +432,7 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, if (!blk_tree_root) { blk_tree_root = debugfs_create_dir("block", NULL); if (!blk_tree_root) - return -ENOMEM; + goto err; } dir = debugfs_create_dir(buts->name, blk_tree_root); diff --git a/trunk/kernel/trace/events.c b/trunk/kernel/trace/events.c index 246f2aa6dc46..9fc918da404f 100644 --- a/trunk/kernel/trace/events.c +++ b/trunk/kernel/trace/events.c @@ -12,3 +12,4 @@ #include "trace_events_stage_2.h" #include "trace_events_stage_3.h" +#include diff --git a/trunk/kernel/trace/ring_buffer.c b/trunk/kernel/trace/ring_buffer.c index 808b14bbf076..384ca5d9d729 100644 --- a/trunk/kernel/trace/ring_buffer.c +++ b/trunk/kernel/trace/ring_buffer.c @@ -535,8 +535,8 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer) extern int ring_buffer_page_too_big(void); #ifdef CONFIG_HOTPLUG_CPU -static int rb_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu); +static int __cpuinit rb_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu); #endif /** @@ -2784,8 +2784,8 @@ static __init int rb_init_debugfs(void) fs_initcall(rb_init_debugfs); #ifdef CONFIG_HOTPLUG_CPU -static int rb_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +static int __cpuinit rb_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) { struct ring_buffer *buffer = container_of(self, struct ring_buffer, cpu_notify); diff --git a/trunk/kernel/trace/trace.c b/trunk/kernel/trace/trace.c index e6fac0ffe6f0..c95b7292be70 100644 --- a/trunk/kernel/trace/trace.c +++ b/trunk/kernel/trace/trace.c @@ -1201,7 +1201,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace) * trace_vbprintk - write binary msg to tracing buffer * */ -int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) +int trace_vbprintk(unsigned long ip, int depth, const char *fmt, va_list args) { static raw_spinlock_t trace_buf_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; @@ -1243,6 +1243,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) goto out_unlock; entry = ring_buffer_event_data(event); entry->ip = ip; + entry->depth = depth; entry->fmt = fmt; memcpy(entry->buf, trace_buf, sizeof(u32) * len); @@ -1260,7 +1261,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) } EXPORT_SYMBOL_GPL(trace_vbprintk); -int trace_vprintk(unsigned long ip, const char *fmt, va_list args) +int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args) { static raw_spinlock_t trace_buf_lock = __RAW_SPIN_LOCK_UNLOCKED; static char trace_buf[TRACE_BUF_SIZE]; @@ -1297,6 +1298,7 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) goto out_unlock; entry = ring_buffer_event_data(event); entry->ip = ip; + entry->depth = depth; memcpy(&entry->buf, trace_buf, len); entry->buf[len] = 0; @@ -1699,6 +1701,38 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter) return TRACE_TYPE_HANDLED; } +static enum print_line_t print_bprintk_msg_only(struct trace_iterator *iter) +{ + struct trace_seq *s = &iter->seq; + struct trace_entry *entry = iter->ent; + struct bprint_entry *field; + int ret; + + trace_assign_type(field, entry); + + ret = trace_seq_bprintf(s, field->fmt, field->buf); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t print_printk_msg_only(struct trace_iterator *iter) +{ + struct trace_seq *s = &iter->seq; + struct trace_entry *entry = iter->ent; + struct print_entry *field; + int ret; + + trace_assign_type(field, entry); + + ret = trace_seq_printf(s, "%s", field->buf); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + static enum print_line_t print_bin_fmt(struct trace_iterator *iter) { struct trace_seq *s = &iter->seq; @@ -1760,12 +1794,12 @@ static enum print_line_t print_trace_line(struct trace_iterator *iter) if (iter->ent->type == TRACE_BPRINT && trace_flags & TRACE_ITER_PRINTK && trace_flags & TRACE_ITER_PRINTK_MSGONLY) - return trace_print_bprintk_msg_only(iter); + return print_bprintk_msg_only(iter); if (iter->ent->type == TRACE_PRINT && trace_flags & TRACE_ITER_PRINTK && trace_flags & TRACE_ITER_PRINTK_MSGONLY) - return trace_print_printk_msg_only(iter); + return print_printk_msg_only(iter); if (trace_flags & TRACE_ITER_BIN) return print_bin_fmt(iter); @@ -1914,14 +1948,9 @@ int tracing_open_generic(struct inode *inode, struct file *filp) static int tracing_release(struct inode *inode, struct file *file) { struct seq_file *m = (struct seq_file *)file->private_data; - struct trace_iterator *iter; + struct trace_iterator *iter = m->private; int cpu; - if (!(file->f_mode & FMODE_READ)) - return 0; - - iter = m->private; - mutex_lock(&trace_types_lock); for_each_tracing_cpu(cpu) { if (iter->buffer_iter[cpu]) @@ -1947,24 +1976,12 @@ static int tracing_open(struct inode *inode, struct file *file) struct trace_iterator *iter; int ret = 0; - /* If this file was open for write, then erase contents */ - if ((file->f_mode & FMODE_WRITE) && - !(file->f_flags & O_APPEND)) { - long cpu = (long) inode->i_private; - - if (cpu == TRACE_PIPE_ALL_CPU) - tracing_reset_online_cpus(&global_trace); - else - tracing_reset(&global_trace, cpu); - } + iter = __tracing_open(inode, file); + if (IS_ERR(iter)) + ret = PTR_ERR(iter); + else if (trace_flags & TRACE_ITER_LATENCY_FMT) + iter->iter_flags |= TRACE_FILE_LAT_FMT; - if (file->f_mode & FMODE_READ) { - iter = __tracing_open(inode, file); - if (IS_ERR(iter)) - ret = PTR_ERR(iter); - else if (trace_flags & TRACE_ITER_LATENCY_FMT) - iter->iter_flags |= TRACE_FILE_LAT_FMT; - } return ret; } @@ -2039,17 +2056,9 @@ static int show_traces_open(struct inode *inode, struct file *file) return ret; } -static ssize_t -tracing_write_stub(struct file *filp, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - return count; -} - static const struct file_operations tracing_fops = { .open = tracing_open, .read = seq_read, - .write = tracing_write_stub, .llseek = seq_lseek, .release = tracing_release, }; @@ -3145,7 +3154,7 @@ static int mark_printk(const char *fmt, ...) int ret; va_list args; va_start(args, fmt); - ret = trace_vprintk(0, fmt, args); + ret = trace_vprintk(0, -1, fmt, args); va_end(args); return ret; } @@ -3574,7 +3583,7 @@ static void tracing_init_debugfs_percpu(long cpu) pr_warning("Could not create debugfs 'trace_pipe' entry\n"); /* per cpu trace */ - entry = debugfs_create_file("trace", 0644, d_cpu, + entry = debugfs_create_file("trace", 0444, d_cpu, (void *) cpu, &tracing_fops); if (!entry) pr_warning("Could not create debugfs 'trace' entry\n"); @@ -3888,7 +3897,7 @@ static __init int tracer_init_debugfs(void) if (!entry) pr_warning("Could not create debugfs 'tracing_cpumask' entry\n"); - entry = debugfs_create_file("trace", 0644, d_tracer, + entry = debugfs_create_file("trace", 0444, d_tracer, (void *) TRACE_PIPE_ALL_CPU, &tracing_fops); if (!entry) pr_warning("Could not create debugfs 'trace' entry\n"); @@ -4018,12 +4027,11 @@ trace_printk_seq(struct trace_seq *s) trace_seq_init(s); } -static void __ftrace_dump(bool disable_tracing) +void ftrace_dump(void) { static DEFINE_SPINLOCK(ftrace_dump_lock); /* use static because iter can be a bit big for the stack */ static struct trace_iterator iter; - unsigned int old_userobj; static int dump_ran; unsigned long flags; int cnt = 0, cpu; @@ -4035,17 +4043,14 @@ static void __ftrace_dump(bool disable_tracing) dump_ran = 1; + /* No turning back! */ tracing_off(); - - if (disable_tracing) - ftrace_kill(); + ftrace_kill(); for_each_tracing_cpu(cpu) { atomic_inc(&global_trace.data[cpu]->disabled); } - old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ; - /* don't look at user memory in panic mode */ trace_flags &= ~TRACE_ITER_SYM_USEROBJ; @@ -4090,26 +4095,10 @@ static void __ftrace_dump(bool disable_tracing) else printk(KERN_TRACE "---------------------------------\n"); - /* Re-enable tracing if requested */ - if (!disable_tracing) { - trace_flags |= old_userobj; - - for_each_tracing_cpu(cpu) { - atomic_dec(&global_trace.data[cpu]->disabled); - } - tracing_on(); - } - out: spin_unlock_irqrestore(&ftrace_dump_lock, flags); } -/* By default: disable tracing after the dump */ -void ftrace_dump(void) -{ - __ftrace_dump(true); -} - __init static int tracer_alloc_buffers(void) { struct trace_array_cpu *data; diff --git a/trunk/kernel/trace/trace.h b/trunk/kernel/trace/trace.h index 7cfb741be200..38276d1638e3 100644 --- a/trunk/kernel/trace/trace.h +++ b/trunk/kernel/trace/trace.h @@ -123,6 +123,7 @@ struct userstack_entry { struct bprint_entry { struct trace_entry ent; unsigned long ip; + int depth; const char *fmt; u32 buf[]; }; @@ -130,6 +131,7 @@ struct bprint_entry { struct print_entry { struct trace_entry ent; unsigned long ip; + int depth; char buf[]; }; @@ -596,9 +598,9 @@ extern int trace_selftest_startup_branch(struct tracer *trace, extern void *head_page(struct trace_array_cpu *data); extern long ns2usecs(cycle_t nsec); extern int -trace_vbprintk(unsigned long ip, const char *fmt, va_list args); +trace_vbprintk(unsigned long ip, int depth, const char *fmt, va_list args); extern int -trace_vprintk(unsigned long ip, const char *fmt, va_list args); +trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args); extern unsigned long trace_flags; @@ -785,23 +787,12 @@ struct ftrace_event_call { int id; int (*raw_init)(void); int (*show_format)(struct trace_seq *s); - -#ifdef CONFIG_EVENT_PROFILE - atomic_t profile_count; - int (*profile_enable)(struct ftrace_event_call *); - void (*profile_disable)(struct ftrace_event_call *); -#endif }; void event_trace_printk(unsigned long ip, const char *fmt, ...); extern struct ftrace_event_call __start_ftrace_events[]; extern struct ftrace_event_call __stop_ftrace_events[]; -#define for_each_event(event) \ - for (event = __start_ftrace_events; \ - (unsigned long)event < (unsigned long)__stop_ftrace_events; \ - event++) - extern const char *__start___trace_bprintk_fmt[]; extern const char *__stop___trace_bprintk_fmt[]; diff --git a/trunk/kernel/trace/trace_event_profile.c b/trunk/kernel/trace/trace_event_profile.c deleted file mode 100644 index 22cba9970776..000000000000 --- a/trunk/kernel/trace/trace_event_profile.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * trace event based perf counter profiling - * - * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra - * - */ - -#include "trace.h" - -int ftrace_profile_enable(int event_id) -{ - struct ftrace_event_call *event; - - for_each_event(event) { - if (event->id == event_id) - return event->profile_enable(event); - } - - return -EINVAL; -} - -void ftrace_profile_disable(int event_id) -{ - struct ftrace_event_call *event; - - for_each_event(event) { - if (event->id == event_id) - return event->profile_disable(event); - } -} - diff --git a/trunk/kernel/trace/trace_event_types.h b/trunk/kernel/trace/trace_event_types.h index fd78bee71dd7..019915063fe6 100644 --- a/trunk/kernel/trace/trace_event_types.h +++ b/trunk/kernel/trace/trace_event_types.h @@ -105,6 +105,7 @@ TRACE_EVENT_FORMAT(user_stack, TRACE_USER_STACK, userstack_entry, ignore, TRACE_EVENT_FORMAT(bprint, TRACE_BPRINT, bprint_entry, ignore, TRACE_STRUCT( TRACE_FIELD(unsigned long, ip, ip) + TRACE_FIELD(unsigned int, depth, depth) TRACE_FIELD(char *, fmt, fmt) TRACE_FIELD_ZERO_CHAR(buf) ), @@ -114,6 +115,7 @@ TRACE_EVENT_FORMAT(bprint, TRACE_BPRINT, bprint_entry, ignore, TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore, TRACE_STRUCT( TRACE_FIELD(unsigned long, ip, ip) + TRACE_FIELD(unsigned int, depth, depth) TRACE_FIELD_ZERO_CHAR(buf) ), TP_RAW_FMT("%08lx (%d) fmt:%p %s") diff --git a/trunk/kernel/trace/trace_events.c b/trunk/kernel/trace/trace_events.c index 3047b56f6637..c88227b3b9db 100644 --- a/trunk/kernel/trace/trace_events.c +++ b/trunk/kernel/trace/trace_events.c @@ -19,6 +19,11 @@ static DEFINE_MUTEX(event_mutex); +#define events_for_each(event) \ + for (event = __start_ftrace_events; \ + (unsigned long)event < (unsigned long)__stop_ftrace_events; \ + event++) + static void ftrace_clear_events(void) { struct ftrace_event_call *call = (void *)__start_ftrace_events; @@ -85,7 +90,7 @@ static int ftrace_set_clr_event(char *buf, int set) } mutex_lock(&event_mutex); - for_each_event(call) { + events_for_each(call) { if (!call->name || !call->regfunc) continue; @@ -407,29 +412,6 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt, return r; } -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; - - 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->id); - - r = simple_read_from_buffer(ubuf, cnt, ppos, - s->buffer, s->len); - kfree(s); - return r; -} - static const struct seq_operations show_event_seq_ops = { .start = t_start, .next = t_next, @@ -470,11 +452,6 @@ static const struct file_operations ftrace_event_format_fops = { .read = event_format_read, }; -static const struct file_operations ftrace_event_id_fops = { - .open = tracing_open_generic, - .read = event_id_read, -}; - static struct dentry *event_trace_events_dir(void) { static struct dentry *d_tracer; @@ -573,14 +550,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) "'%s/enable' entry\n", call->name); } - if (call->id) { - entry = debugfs_create_file("id", 0444, call->dir, call, - &ftrace_event_id_fops); - if (!entry) - pr_warning("Could not create debugfs '%s/id' entry\n", - call->name); - } - /* A trace may not want to export its format */ if (!call->show_format) return 0; @@ -623,7 +592,7 @@ static __init int event_trace_init(void) if (!d_events) return 0; - for_each_event(call) { + events_for_each(call) { /* The linker may leave blanks */ if (!call->name) continue; diff --git a/trunk/kernel/trace/trace_events_stage_3.h b/trunk/kernel/trace/trace_events_stage_3.h index 6b3261ca988c..ae2e323df0c7 100644 --- a/trunk/kernel/trace/trace_events_stage_3.h +++ b/trunk/kernel/trace/trace_events_stage_3.h @@ -109,40 +109,6 @@ #undef TP_FMT #define TP_FMT(fmt, args...) fmt "\n", ##args -#ifdef CONFIG_EVENT_PROFILE -#define _TRACE_PROFILE(call, proto, args) \ -static void ftrace_profile_##call(proto) \ -{ \ - extern void perf_tpcounter_event(int); \ - perf_tpcounter_event(event_##call.id); \ -} \ - \ -static int ftrace_profile_enable_##call(struct ftrace_event_call *call) \ -{ \ - int ret = 0; \ - \ - if (!atomic_inc_return(&call->profile_count)) \ - ret = register_trace_##call(ftrace_profile_##call); \ - \ - return ret; \ -} \ - \ -static void ftrace_profile_disable_##call(struct ftrace_event_call *call) \ -{ \ - if (atomic_add_negative(-1, &call->profile_count)) \ - unregister_trace_##call(ftrace_profile_##call); \ -} - -#define _TRACE_PROFILE_INIT(call) \ - .profile_count = ATOMIC_INIT(-1), \ - .profile_enable = ftrace_profile_enable_##call, \ - .profile_disable = ftrace_profile_disable_##call, - -#else -#define _TRACE_PROFILE(call, proto, args) -#define _TRACE_PROFILE_INIT(call) -#endif - #define _TRACE_FORMAT(call, proto, args, fmt) \ static void ftrace_event_##call(proto) \ { \ @@ -164,33 +130,18 @@ static void ftrace_unreg_event_##call(void) \ { \ unregister_trace_##call(ftrace_event_##call); \ } \ - \ -static struct ftrace_event_call event_##call; \ - \ -static int ftrace_init_event_##call(void) \ -{ \ - int id; \ - \ - id = register_ftrace_event(NULL); \ - if (!id) \ - return -ENODEV; \ - event_##call.id = id; \ - return 0; \ -} + #undef TRACE_FORMAT #define TRACE_FORMAT(call, proto, args, fmt) \ _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ -_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ static struct ftrace_event_call __used \ __attribute__((__aligned__(4))) \ __attribute__((section("_ftrace_events"))) event_##call = { \ .name = #call, \ .system = __stringify(TRACE_SYSTEM), \ - .raw_init = ftrace_init_event_##call, \ .regfunc = ftrace_reg_event_##call, \ .unregfunc = ftrace_unreg_event_##call, \ - _TRACE_PROFILE_INIT(call) \ } #undef __entry @@ -198,7 +149,6 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ #undef TRACE_EVENT #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ -_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ \ static struct ftrace_event_call event_##call; \ \ @@ -264,11 +214,4 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ .regfunc = ftrace_raw_reg_event_##call, \ .unregfunc = ftrace_raw_unreg_event_##call, \ .show_format = ftrace_format_##call, \ - _TRACE_PROFILE_INIT(call) \ } - -#include - -#undef _TRACE_PROFILE -#undef _TRACE_PROFILE_INIT - diff --git a/trunk/kernel/trace/trace_functions_graph.c b/trunk/kernel/trace/trace_functions_graph.c index e876816fa8e7..6004ccac2dd7 100644 --- a/trunk/kernel/trace/trace_functions_graph.c +++ b/trunk/kernel/trace/trace_functions_graph.c @@ -14,11 +14,6 @@ #include "trace.h" #include "trace_output.h" -struct fgraph_data { - pid_t last_pid; - int depth; -}; - #define TRACE_GRAPH_INDENT 2 /* Flag options */ @@ -236,16 +231,16 @@ print_graph_proc(struct trace_seq *s, pid_t pid) /* If the pid changed since the last trace, output this event */ static enum print_line_t -verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data) +verif_pid(struct trace_seq *s, pid_t pid, int cpu, pid_t *last_pids_cpu) { pid_t prev_pid; pid_t *last_pid; int ret; - if (!data) + if (!last_pids_cpu) return TRACE_TYPE_HANDLED; - last_pid = &(per_cpu_ptr(data, cpu)->last_pid); + last_pid = per_cpu_ptr(last_pids_cpu, cpu); if (*last_pid == pid) return TRACE_TYPE_HANDLED; @@ -476,7 +471,6 @@ print_graph_entry_leaf(struct trace_iterator *iter, struct ftrace_graph_ent_entry *entry, struct ftrace_graph_ret_entry *ret_entry, struct trace_seq *s) { - struct fgraph_data *data = iter->private; struct ftrace_graph_ret *graph_ret; struct ftrace_graph_ent *call; unsigned long long duration; @@ -487,18 +481,6 @@ print_graph_entry_leaf(struct trace_iterator *iter, call = &entry->graph_ent; duration = graph_ret->rettime - graph_ret->calltime; - if (data) { - int cpu = iter->cpu; - int *depth = &(per_cpu_ptr(data, cpu)->depth); - - /* - * Comments display at + 1 to depth. Since - * this is a leaf function, keep the comments - * equal to this depth. - */ - *depth = call->depth - 1; - } - /* Overhead */ ret = print_graph_overhead(duration, s); if (!ret) @@ -530,21 +512,12 @@ print_graph_entry_leaf(struct trace_iterator *iter, } static enum print_line_t -print_graph_entry_nested(struct trace_iterator *iter, - struct ftrace_graph_ent_entry *entry, - struct trace_seq *s, int cpu) +print_graph_entry_nested(struct ftrace_graph_ent_entry *entry, + struct trace_seq *s, pid_t pid, int cpu) { - struct ftrace_graph_ent *call = &entry->graph_ent; - struct fgraph_data *data = iter->private; - int ret; int i; - - if (data) { - int cpu = iter->cpu; - int *depth = &(per_cpu_ptr(data, cpu)->depth); - - *depth = call->depth; - } + int ret; + struct ftrace_graph_ent *call = &entry->graph_ent; /* No overhead */ ret = print_graph_overhead(-1, s); @@ -581,24 +554,24 @@ print_graph_entry_nested(struct trace_iterator *iter, } static enum print_line_t -print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, - int type, unsigned long addr) +print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, + struct trace_iterator *iter) { - struct fgraph_data *data = iter->private; - struct trace_entry *ent = iter->ent; - int cpu = iter->cpu; int ret; + int cpu = iter->cpu; + pid_t *last_entry = iter->private; + struct trace_entry *ent = iter->ent; + struct ftrace_graph_ent *call = &field->graph_ent; + struct ftrace_graph_ret_entry *leaf_ret; /* Pid */ - if (verif_pid(s, ent->pid, cpu, data) == TRACE_TYPE_PARTIAL_LINE) + if (verif_pid(s, ent->pid, cpu, last_entry) == TRACE_TYPE_PARTIAL_LINE) return TRACE_TYPE_PARTIAL_LINE; - if (type) { - /* Interrupt */ - ret = print_graph_irq(iter, addr, type, cpu, ent->pid); - if (ret == TRACE_TYPE_PARTIAL_LINE) - return TRACE_TYPE_PARTIAL_LINE; - } + /* Interrupt */ + ret = print_graph_irq(iter, call->func, TRACE_GRAPH_ENT, cpu, ent->pid); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; /* Absolute time */ if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { @@ -625,25 +598,11 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, return TRACE_TYPE_PARTIAL_LINE; } - return 0; -} - -static enum print_line_t -print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, - struct trace_iterator *iter) -{ - int cpu = iter->cpu; - struct ftrace_graph_ent *call = &field->graph_ent; - struct ftrace_graph_ret_entry *leaf_ret; - - if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func)) - return TRACE_TYPE_PARTIAL_LINE; - leaf_ret = get_return_for_leaf(iter, field); if (leaf_ret) return print_graph_entry_leaf(iter, field, leaf_ret, s); else - return print_graph_entry_nested(iter, field, s, cpu); + return print_graph_entry_nested(field, s, iter->ent->pid, cpu); } @@ -651,27 +610,40 @@ static enum print_line_t print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, struct trace_entry *ent, struct trace_iterator *iter) { - unsigned long long duration = trace->rettime - trace->calltime; - struct fgraph_data *data = iter->private; - pid_t pid = ent->pid; - int cpu = iter->cpu; - int ret; int i; + int ret; + int cpu = iter->cpu; + pid_t *last_pid = iter->private, pid = ent->pid; + unsigned long long duration = trace->rettime - trace->calltime; - if (data) { - int cpu = iter->cpu; - int *depth = &(per_cpu_ptr(data, cpu)->depth); + /* Pid */ + if (verif_pid(s, pid, cpu, last_pid) == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; - /* - * Comments display at + 1 to depth. This is the - * return from a function, we now want the comments - * to display at the same level of the bracket. - */ - *depth = trace->depth - 1; + /* Absolute time */ + if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { + ret = print_graph_abs_time(iter->ts, s); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; } - if (print_graph_prologue(iter, s, 0, 0)) - return TRACE_TYPE_PARTIAL_LINE; + /* Cpu */ + if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { + ret = print_graph_cpu(s, cpu); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; + } + + /* Proc */ + if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) { + ret = print_graph_proc(s, ent->pid); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; + + ret = trace_seq_printf(s, " | "); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + } /* Overhead */ ret = print_graph_overhead(duration, s); @@ -712,22 +684,43 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, } static enum print_line_t -print_graph_comment(struct trace_seq *s, struct trace_entry *ent, - struct trace_iterator *iter) +print_graph_comment(struct bprint_entry *trace, struct trace_seq *s, + struct trace_entry *ent, struct trace_iterator *iter) { - unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); - struct fgraph_data *data = iter->private; - struct trace_event *event; - int depth = 0; - int ret; int i; + int ret; + int cpu = iter->cpu; + pid_t *last_pid = iter->private; - if (data) - depth = per_cpu_ptr(data, iter->cpu)->depth; - - if (print_graph_prologue(iter, s, 0, 0)) + /* Pid */ + if (verif_pid(s, ent->pid, cpu, last_pid) == TRACE_TYPE_PARTIAL_LINE) return TRACE_TYPE_PARTIAL_LINE; + /* Absolute time */ + if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { + ret = print_graph_abs_time(iter->ts, s); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + } + + /* Cpu */ + if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { + ret = print_graph_cpu(s, cpu); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; + } + + /* Proc */ + if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) { + ret = print_graph_proc(s, ent->pid); + if (ret == TRACE_TYPE_PARTIAL_LINE) + return TRACE_TYPE_PARTIAL_LINE; + + ret = trace_seq_printf(s, " | "); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + } + /* No overhead */ ret = print_graph_overhead(-1, s); if (!ret) @@ -741,8 +734,8 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, } /* Indentation */ - if (depth > 0) - for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++) { + if (trace->depth > 0) + for (i = 0; i < (trace->depth + 1) * TRACE_GRAPH_INDENT; i++) { ret = trace_seq_printf(s, " "); if (!ret) return TRACE_TYPE_PARTIAL_LINE; @@ -753,26 +746,9 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, if (!ret) return TRACE_TYPE_PARTIAL_LINE; - switch (iter->ent->type) { - case TRACE_BPRINT: - ret = trace_print_bprintk_msg_only(iter); - if (ret != TRACE_TYPE_HANDLED) - return ret; - break; - case TRACE_PRINT: - ret = trace_print_printk_msg_only(iter); - if (ret != TRACE_TYPE_HANDLED) - return ret; - break; - default: - event = ftrace_find_event(ent->type); - if (!event) - return TRACE_TYPE_UNHANDLED; - - ret = event->trace(iter, sym_flags); - if (ret != TRACE_TYPE_HANDLED) - return ret; - } + ret = trace_seq_bprintf(s, trace->fmt, trace->buf); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; /* Strip ending newline */ if (s->buffer[s->len - 1] == '\n') { @@ -791,8 +767,8 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, enum print_line_t print_graph_function(struct trace_iterator *iter) { - struct trace_entry *entry = iter->ent; struct trace_seq *s = &iter->seq; + struct trace_entry *entry = iter->ent; switch (entry->type) { case TRACE_GRAPH_ENT: { @@ -805,11 +781,14 @@ print_graph_function(struct trace_iterator *iter) trace_assign_type(field, entry); return print_graph_return(&field->ret, s, entry, iter); } + case TRACE_BPRINT: { + struct bprint_entry *field; + trace_assign_type(field, entry); + return print_graph_comment(field, s, entry, iter); + } default: - return print_graph_comment(s, entry, iter); + return TRACE_TYPE_UNHANDLED; } - - return TRACE_TYPE_HANDLED; } static void print_graph_headers(struct seq_file *s) @@ -841,21 +820,19 @@ static void print_graph_headers(struct seq_file *s) static void graph_trace_open(struct trace_iterator *iter) { - /* pid and depth on the last trace processed */ - struct fgraph_data *data = alloc_percpu(struct fgraph_data); + /* pid on the last trace processed */ + pid_t *last_pid = alloc_percpu(pid_t); int cpu; - if (!data) + if (!last_pid) pr_warning("function graph tracer: not enough memory\n"); else for_each_possible_cpu(cpu) { - pid_t *pid = &(per_cpu_ptr(data, cpu)->last_pid); - int *depth = &(per_cpu_ptr(data, cpu)->depth); + pid_t *pid = per_cpu_ptr(last_pid, cpu); *pid = -1; - *depth = 0; } - iter->private = data; + iter->private = last_pid; } static void graph_trace_close(struct trace_iterator *iter) diff --git a/trunk/kernel/trace/trace_mmiotrace.c b/trunk/kernel/trace/trace_mmiotrace.c index 8e37fcddd8b4..f095916e477f 100644 --- a/trunk/kernel/trace/trace_mmiotrace.c +++ b/trunk/kernel/trace/trace_mmiotrace.c @@ -359,5 +359,5 @@ void mmio_trace_mapping(struct mmiotrace_map *map) int mmio_trace_printk(const char *fmt, va_list args) { - return trace_vprintk(0, fmt, args); + return trace_vprintk(0, -1, fmt, args); } diff --git a/trunk/kernel/trace/trace_output.c b/trunk/kernel/trace/trace_output.c index 19261fdd2455..6a4c9dea191e 100644 --- a/trunk/kernel/trace/trace_output.c +++ b/trunk/kernel/trace/trace_output.c @@ -19,38 +19,6 @@ static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly; static int next_event_type = __TRACE_LAST_TYPE + 1; -enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter) -{ - struct trace_seq *s = &iter->seq; - struct trace_entry *entry = iter->ent; - struct bprint_entry *field; - int ret; - - trace_assign_type(field, entry); - - ret = trace_seq_bprintf(s, field->fmt, field->buf); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - - return TRACE_TYPE_HANDLED; -} - -enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter) -{ - struct trace_seq *s = &iter->seq; - struct trace_entry *entry = iter->ent; - struct print_entry *field; - int ret; - - trace_assign_type(field, entry); - - ret = trace_seq_printf(s, "%s", field->buf); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - - return TRACE_TYPE_HANDLED; -} - /** * trace_seq_printf - sequence printing of trace information * @s: trace sequence descriptor @@ -481,11 +449,6 @@ int register_ftrace_event(struct trace_event *event) mutex_lock(&trace_event_mutex); - if (!event) { - ret = next_event_type++; - goto out; - } - if (!event->type) event->type = next_event_type++; else if (event->type > __TRACE_LAST_TYPE) { diff --git a/trunk/kernel/trace/trace_output.h b/trunk/kernel/trace/trace_output.h index 35c422fb51a9..3b90e6ade1aa 100644 --- a/trunk/kernel/trace/trace_output.h +++ b/trunk/kernel/trace/trace_output.h @@ -15,11 +15,6 @@ struct trace_event { trace_print_func binary; }; -extern enum print_line_t -trace_print_bprintk_msg_only(struct trace_iterator *iter); -extern enum print_line_t -trace_print_printk_msg_only(struct trace_iterator *iter); - extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); extern int diff --git a/trunk/kernel/trace/trace_printk.c b/trunk/kernel/trace/trace_printk.c index eb81556107fe..486785214e3e 100644 --- a/trunk/kernel/trace/trace_printk.c +++ b/trunk/kernel/trace/trace_printk.c @@ -112,7 +112,7 @@ int __trace_bprintk(unsigned long ip, const char *fmt, ...) return 0; va_start(ap, fmt); - ret = trace_vbprintk(ip, fmt, ap); + ret = trace_vbprintk(ip, task_curr_ret_stack(current), fmt, ap); va_end(ap); return ret; } @@ -126,7 +126,7 @@ int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap) if (!(trace_flags & TRACE_ITER_PRINTK)) return 0; - return trace_vbprintk(ip, fmt, ap); + return trace_vbprintk(ip, task_curr_ret_stack(current), fmt, ap); } EXPORT_SYMBOL_GPL(__ftrace_vbprintk); @@ -139,7 +139,7 @@ int __trace_printk(unsigned long ip, const char *fmt, ...) return 0; va_start(ap, fmt); - ret = trace_vprintk(ip, fmt, ap); + ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap); va_end(ap); return ret; } @@ -150,7 +150,7 @@ int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap) if (!(trace_flags & TRACE_ITER_PRINTK)) return 0; - return trace_vprintk(ip, fmt, ap); + return trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap); } EXPORT_SYMBOL_GPL(__ftrace_vprintk); diff --git a/trunk/kernel/trace/trace_selftest.c b/trunk/kernel/trace/trace_selftest.c index 08f4eb2763d1..38856ba78a92 100644 --- a/trunk/kernel/trace/trace_selftest.c +++ b/trunk/kernel/trace/trace_selftest.c @@ -248,28 +248,6 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) #ifdef CONFIG_FUNCTION_GRAPH_TRACER - -/* Maximum number of functions to trace before diagnosing a hang */ -#define GRAPH_MAX_FUNC_TEST 100000000 - -static void __ftrace_dump(bool disable_tracing); -static unsigned int graph_hang_thresh; - -/* Wrap the real function entry probe to avoid possible hanging */ -static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace) -{ - /* This is harmlessly racy, we want to approximately detect a hang */ - if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) { - ftrace_graph_stop(); - printk(KERN_WARNING "BUG: Function graph tracer hang!\n"); - if (ftrace_dump_on_oops) - __ftrace_dump(false); - return 0; - } - - return trace_graph_entry(trace); -} - /* * Pretty much the same than for the function tracer from which the selftest * has been borrowed. @@ -281,29 +259,15 @@ trace_selftest_startup_function_graph(struct tracer *trace, int ret; unsigned long count; - /* - * Simulate the init() callback but we attach a watchdog callback - * to detect and recover from possible hangs - */ - tracing_reset_online_cpus(tr); - ret = register_ftrace_graph(&trace_graph_return, - &trace_graph_entry_watchdog); + ret = tracer_init(trace, tr); if (ret) { warn_failed_init_tracer(trace, ret); goto out; } - tracing_start_cmdline_record(); /* Sleep for a 1/10 of a second */ msleep(100); - /* Have we just recovered from a hang? */ - if (graph_hang_thresh > GRAPH_MAX_FUNC_TEST) { - tracing_selftest_disabled = true; - ret = -1; - goto out; - } - tracing_stop(); /* check the trace buffer */ diff --git a/trunk/mm/memory.c b/trunk/mm/memory.c index dfc9e4ea4e8b..05fab3bc5b4b 100644 --- a/trunk/mm/memory.c +++ b/trunk/mm/memory.c @@ -101,6 +101,14 @@ int randomize_va_space __read_mostly = 2; #endif +/* + * mutex protecting text section modification (dynamic code patching). + * some users need to sleep (allocating memory...) while they hold this lock. + * + * NOT exported to modules - patching kernel text is a really delicate matter. + */ +DEFINE_MUTEX(text_mutex); + static int __init disable_randmaps(char *s) { randomize_va_space = 0;