diff --git a/[refs] b/[refs] index fbf7284098b6..81feb8e995d0 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 492f73a303b488ffd67097b2351d54aa6e6c7c73 +refs/heads/master: e4a3f541f0b67fdad98b326c851dfe7f4b6b6dad diff --git a/trunk/include/linux/ftrace.h b/trunk/include/linux/ftrace.h index f0c0e8a47ae6..9d88e1cb5dbb 100644 --- a/trunk/include/linux/ftrace.h +++ b/trunk/include/linux/ftrace.h @@ -19,8 +19,6 @@ #include -struct ftrace_hash; - #ifdef CONFIG_FUNCTION_TRACER extern int ftrace_enabled; @@ -31,6 +29,8 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); +struct ftrace_hash; + enum { FTRACE_OPS_FL_ENABLED = 1 << 0, FTRACE_OPS_FL_GLOBAL = 1 << 1, @@ -123,8 +123,7 @@ stack_trace_sysctl(struct ctl_table *table, int write, struct ftrace_func_command { struct list_head list; char *name; - int (*func)(struct ftrace_hash *hash, - char *func, char *cmd, + int (*func)(char *func, char *cmd, char *params, int enable); }; diff --git a/trunk/kernel/jump_label.c b/trunk/kernel/jump_label.c index a8ce45097f3d..fa27e750dbc0 100644 --- a/trunk/kernel/jump_label.c +++ b/trunk/kernel/jump_label.c @@ -375,19 +375,15 @@ int jump_label_text_reserved(void *start, void *end) static void jump_label_update(struct jump_label_key *key, int enable) { - struct jump_entry *entry = key->entries, *stop = __stop___jump_table; + struct jump_entry *entry = key->entries; -#ifdef CONFIG_MODULES - struct module *mod = __module_address((jump_label_t)key); + /* if there are no users, entry can be NULL */ + if (entry) + __jump_label_update(key, entry, __stop___jump_table, enable); +#ifdef CONFIG_MODULES __jump_label_mod_update(key, enable); - - if (mod) - stop = mod->jump_entries + mod->num_jump_entries; #endif - /* if there are no users, entry can be NULL */ - if (entry) - __jump_label_update(key, entry, stop, enable); } #endif diff --git a/trunk/kernel/trace/ftrace.c b/trunk/kernel/trace/ftrace.c index a0e246e2cee3..c997f7371c65 100644 --- a/trunk/kernel/trace/ftrace.c +++ b/trunk/kernel/trace/ftrace.c @@ -1732,36 +1732,10 @@ static cycle_t ftrace_update_time; static unsigned long ftrace_update_cnt; unsigned long ftrace_update_tot_cnt; -static int ops_traces_mod(struct ftrace_ops *ops) -{ - struct ftrace_hash *hash; - - hash = ops->filter_hash; - return !!(!hash || !hash->count); -} - static int ftrace_update_code(struct module *mod) { struct dyn_ftrace *p; cycle_t start, stop; - unsigned long ref = 0; - - /* - * When adding a module, we need to check if tracers are - * currently enabled and if they are set to trace all functions. - * If they are, we need to enable the module functions as well - * as update the reference counts for those function records. - */ - if (mod) { - struct ftrace_ops *ops; - - for (ops = ftrace_ops_list; - ops != &ftrace_list_end; ops = ops->next) { - if (ops->flags & FTRACE_OPS_FL_ENABLED && - ops_traces_mod(ops)) - ref++; - } - } start = ftrace_now(raw_smp_processor_id()); ftrace_update_cnt = 0; @@ -1774,7 +1748,7 @@ static int ftrace_update_code(struct module *mod) p = ftrace_new_addrs; ftrace_new_addrs = p->newlist; - p->flags = ref; + p->flags = 0L; /* * Do the initial record conversion from mcount jump @@ -1797,7 +1771,7 @@ static int ftrace_update_code(struct module *mod) * conversion puts the module to the correct state, thus * passing the ftrace_make_call check. */ - if (ftrace_start_up && ref) { + if (ftrace_start_up) { int failed = __ftrace_replace_code(p, 1); if (failed) { ftrace_bug(failed, p->ip); @@ -2421,9 +2395,10 @@ ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod) */ static int -ftrace_mod_callback(struct ftrace_hash *hash, - char *func, char *cmd, char *param, int enable) +ftrace_mod_callback(char *func, char *cmd, char *param, int enable) { + struct ftrace_ops *ops = &global_ops; + struct ftrace_hash *hash; char *mod; int ret = -EINVAL; @@ -2443,6 +2418,11 @@ ftrace_mod_callback(struct ftrace_hash *hash, if (!strlen(mod)) return ret; + if (enable) + hash = ops->filter_hash; + else + hash = ops->notrace_hash; + ret = ftrace_match_module_records(hash, func, mod); if (!ret) ret = -EINVAL; @@ -2768,7 +2748,7 @@ static int ftrace_process_regex(struct ftrace_hash *hash, mutex_lock(&ftrace_cmd_mutex); list_for_each_entry(p, &ftrace_commands, list) { if (strcmp(p->name, command) == 0) { - ret = p->func(hash, func, command, next, enable); + ret = p->func(func, command, next, enable); goto out_unlock; } } diff --git a/trunk/kernel/trace/trace.h b/trunk/kernel/trace/trace.h index 30a94c26dcb3..651f35be372a 100644 --- a/trunk/kernel/trace/trace.h +++ b/trunk/kernel/trace/trace.h @@ -278,6 +278,29 @@ struct tracer { }; +/* Only current can touch trace_recursion */ +#define trace_recursion_inc() do { (current)->trace_recursion++; } while (0) +#define trace_recursion_dec() do { (current)->trace_recursion--; } while (0) + +/* Ring buffer has the 10 LSB bits to count */ +#define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff) + +/* for function tracing recursion */ +#define TRACE_INTERNAL_BIT (1<<11) +#define TRACE_GLOBAL_BIT (1<<12) +/* + * Abuse of the trace_recursion. + * As we need a way to maintain state if we are tracing the function + * graph in irq because we want to trace a particular function that + * was called in irq context but we have irq tracing off. Since this + * can only be modified by current, we can reuse trace_recursion. + */ +#define TRACE_IRQ_BIT (1<<13) + +#define trace_recursion_set(bit) do { (current)->trace_recursion |= (bit); } while (0) +#define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(bit); } while (0) +#define trace_recursion_test(bit) ((current)->trace_recursion & (bit)) + #define TRACE_PIPE_ALL_CPU -1 int tracer_init(struct tracer *t, struct trace_array *tr); @@ -516,8 +539,18 @@ static inline int ftrace_graph_addr(unsigned long addr) return 1; for (i = 0; i < ftrace_graph_count; i++) { - if (addr == ftrace_graph_funcs[i]) + if (addr == ftrace_graph_funcs[i]) { + /* + * If no irqs are to be traced, but a set_graph_function + * is set, and called by an interrupt handler, we still + * want to trace it. + */ + if (in_irq()) + trace_recursion_set(TRACE_IRQ_BIT); + else + trace_recursion_clear(TRACE_IRQ_BIT); return 1; + } } return 0; @@ -687,7 +720,6 @@ struct event_subsystem { struct dentry *entry; struct event_filter *filter; int nr_events; - int ref_count; }; #define FILTER_PRED_INVALID ((unsigned short)-1) @@ -795,19 +827,4 @@ extern const char *__stop___trace_bprintk_fmt[]; FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print)) #include "trace_entries.h" -/* Only current can touch trace_recursion */ -#define trace_recursion_inc() do { (current)->trace_recursion++; } while (0) -#define trace_recursion_dec() do { (current)->trace_recursion--; } while (0) - -/* Ring buffer has the 10 LSB bits to count */ -#define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff) - -/* for function tracing recursion */ -#define TRACE_INTERNAL_BIT (1<<11) -#define TRACE_GLOBAL_BIT (1<<12) - -#define trace_recursion_set(bit) do { (current)->trace_recursion |= (bit); } while (0) -#define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(bit); } while (0) -#define trace_recursion_test(bit) ((current)->trace_recursion & (bit)) - #endif /* _LINUX_KERNEL_TRACE_H */ diff --git a/trunk/kernel/trace/trace_events.c b/trunk/kernel/trace/trace_events.c index 581876f9f387..4d7e1498ae91 100644 --- a/trunk/kernel/trace/trace_events.c +++ b/trunk/kernel/trace/trace_events.c @@ -244,35 +244,6 @@ static void ftrace_clear_events(void) mutex_unlock(&event_mutex); } -static void __put_system(struct event_subsystem *system) -{ - struct event_filter *filter = system->filter; - - WARN_ON_ONCE(system->ref_count == 0); - if (--system->ref_count) - return; - - if (filter) { - kfree(filter->filter_string); - kfree(filter); - } - kfree(system->name); - kfree(system); -} - -static void __get_system(struct event_subsystem *system) -{ - WARN_ON_ONCE(system->ref_count == 0); - system->ref_count++; -} - -static void put_system(struct event_subsystem *system) -{ - mutex_lock(&event_mutex); - __put_system(system); - mutex_unlock(&event_mutex); -} - /* * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. */ @@ -548,7 +519,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { const char set_to_char[4] = { '?', '0', '1', 'X' }; - struct event_subsystem *system = filp->private_data; + const char *system = filp->private_data; struct ftrace_event_call *call; char buf[2]; int set = 0; @@ -559,7 +530,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt, if (!call->name || !call->class || !call->class->reg) continue; - if (system && strcmp(call->class->system, system->name) != 0) + if (system && strcmp(call->class->system, system) != 0) continue; /* @@ -589,8 +560,7 @@ static ssize_t system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - struct event_subsystem *system = filp->private_data; - const char *name = NULL; + const char *system = filp->private_data; unsigned long val; ssize_t ret; @@ -605,14 +575,7 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, if (val != 0 && val != 1) return -EINVAL; - /* - * Opening of "enable" adds a ref count to system, - * so the name is safe to use. - */ - if (system) - name = system->name; - - ret = __ftrace_set_clr_event(NULL, name, NULL, val); + ret = __ftrace_set_clr_event(NULL, system, NULL, val); if (ret) goto out; @@ -845,52 +808,6 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, return cnt; } -static LIST_HEAD(event_subsystems); - -static int subsystem_open(struct inode *inode, struct file *filp) -{ - struct event_subsystem *system = NULL; - int ret; - - if (!inode->i_private) - goto skip_search; - - /* Make sure the system still exists */ - mutex_lock(&event_mutex); - list_for_each_entry(system, &event_subsystems, list) { - if (system == inode->i_private) { - /* Don't open systems with no events */ - if (!system->nr_events) { - system = NULL; - break; - } - __get_system(system); - break; - } - } - mutex_unlock(&event_mutex); - - if (system != inode->i_private) - return -ENODEV; - - skip_search: - ret = tracing_open_generic(inode, filp); - if (ret < 0 && system) - put_system(system); - - return ret; -} - -static int subsystem_release(struct inode *inode, struct file *file) -{ - struct event_subsystem *system = inode->i_private; - - if (system) - put_system(system); - - return 0; -} - static ssize_t subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) @@ -1028,19 +945,17 @@ static const struct file_operations ftrace_event_filter_fops = { }; static const struct file_operations ftrace_subsystem_filter_fops = { - .open = subsystem_open, + .open = tracing_open_generic, .read = subsystem_filter_read, .write = subsystem_filter_write, .llseek = default_llseek, - .release = subsystem_release, }; static const struct file_operations ftrace_system_enable_fops = { - .open = subsystem_open, + .open = tracing_open_generic, .read = system_enable_read, .write = system_enable_write, .llseek = default_llseek, - .release = subsystem_release, }; static const struct file_operations ftrace_show_header_fops = { @@ -1069,6 +984,8 @@ static struct dentry *event_trace_events_dir(void) return d_events; } +static LIST_HEAD(event_subsystems); + static struct dentry * event_subsystem_dir(const char *name, struct dentry *d_events) { @@ -1078,7 +995,6 @@ event_subsystem_dir(const char *name, struct dentry *d_events) /* First see if we did not already create this dir */ list_for_each_entry(system, &event_subsystems, list) { if (strcmp(system->name, name) == 0) { - __get_system(system); system->nr_events++; return system->entry; } @@ -1101,7 +1017,6 @@ event_subsystem_dir(const char *name, struct dentry *d_events) } system->nr_events = 1; - system->ref_count = 1; system->name = kstrdup(name, GFP_KERNEL); if (!system->name) { debugfs_remove(system->entry); @@ -1129,7 +1044,8 @@ event_subsystem_dir(const char *name, struct dentry *d_events) "'%s/filter' entry\n", name); } - trace_create_file("enable", 0644, system->entry, system, + trace_create_file("enable", 0644, system->entry, + (void *)system->name, &ftrace_system_enable_fops); return system->entry; @@ -1250,9 +1166,16 @@ static void remove_subsystem_dir(const char *name) list_for_each_entry(system, &event_subsystems, list) { if (strcmp(system->name, name) == 0) { if (!--system->nr_events) { + struct event_filter *filter = system->filter; + debugfs_remove_recursive(system->entry); list_del(&system->list); - __put_system(system); + if (filter) { + kfree(filter->filter_string); + kfree(filter); + } + kfree(system->name); + kfree(system); } break; } diff --git a/trunk/kernel/trace/trace_events_filter.c b/trunk/kernel/trace/trace_events_filter.c index 256764ecccd6..8008ddcfbf20 100644 --- a/trunk/kernel/trace/trace_events_filter.c +++ b/trunk/kernel/trace/trace_events_filter.c @@ -1886,12 +1886,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system, mutex_lock(&event_mutex); - /* Make sure the system still has events */ - if (!system->nr_events) { - err = -ENODEV; - goto out_unlock; - } - if (!strcmp(strstrip(filter_string), "0")) { filter_free_subsystem_preds(system); remove_filter_string(system->filter); diff --git a/trunk/kernel/trace/trace_functions.c b/trunk/kernel/trace/trace_functions.c index c7b0c6a7db09..8d0e1cc4e974 100644 --- a/trunk/kernel/trace/trace_functions.c +++ b/trunk/kernel/trace/trace_functions.c @@ -324,8 +324,7 @@ ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param) } static int -ftrace_trace_onoff_callback(struct ftrace_hash *hash, - char *glob, char *cmd, char *param, int enable) +ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable) { struct ftrace_probe_ops *ops; void *count = (void *)-1; diff --git a/trunk/kernel/trace/trace_functions_graph.c b/trunk/kernel/trace/trace_functions_graph.c index e8d6bb55d719..a7d2a4c653d8 100644 --- a/trunk/kernel/trace/trace_functions_graph.c +++ b/trunk/kernel/trace/trace_functions_graph.c @@ -227,7 +227,7 @@ int __trace_graph_entry(struct trace_array *tr, static inline int ftrace_graph_ignore_irqs(void) { - if (!ftrace_graph_skip_irqs) + if (!ftrace_graph_skip_irqs || trace_recursion_test(TRACE_IRQ_BIT)) return 0; return in_irq();