Loading include/linux/ftrace.h +4 −3 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ #include <asm/ftrace.h> struct ftrace_hash; #ifdef CONFIG_FUNCTION_TRACER extern int ftrace_enabled; Loading @@ -29,8 +31,6 @@ 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, Loading Loading @@ -123,7 +123,8 @@ stack_trace_sysctl(struct ctl_table *table, int write, struct ftrace_func_command { struct list_head list; char *name; int (*func)(char *func, char *cmd, int (*func)(struct ftrace_hash *hash, char *func, char *cmd, char *params, int enable); }; Loading kernel/jump_label.c +9 −5 Original line number Diff line number Diff line Loading @@ -375,15 +375,19 @@ 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; /* if there are no users, entry can be NULL */ if (entry) __jump_label_update(key, entry, __stop___jump_table, enable); struct jump_entry *entry = key->entries, *stop = __stop___jump_table; #ifdef CONFIG_MODULES struct module *mod = __module_address((jump_label_t)key); __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 kernel/trace/ftrace.c +31 −11 Original line number Diff line number Diff line Loading @@ -1732,10 +1732,36 @@ 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; Loading @@ -1748,7 +1774,7 @@ static int ftrace_update_code(struct module *mod) p = ftrace_new_addrs; ftrace_new_addrs = p->newlist; p->flags = 0L; p->flags = ref; /* * Do the initial record conversion from mcount jump Loading @@ -1771,7 +1797,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) { if (ftrace_start_up && ref) { int failed = __ftrace_replace_code(p, 1); if (failed) { ftrace_bug(failed, p->ip); Loading Loading @@ -2395,10 +2421,9 @@ ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod) */ static int ftrace_mod_callback(char *func, char *cmd, char *param, int enable) ftrace_mod_callback(struct ftrace_hash *hash, char *func, char *cmd, char *param, int enable) { struct ftrace_ops *ops = &global_ops; struct ftrace_hash *hash; char *mod; int ret = -EINVAL; Loading @@ -2418,11 +2443,6 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable) 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; Loading Loading @@ -2748,7 +2768,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(func, command, next, enable); ret = p->func(hash, func, command, next, enable); goto out_unlock; } } Loading kernel/trace/trace.h +1 −0 Original line number Diff line number Diff line Loading @@ -687,6 +687,7 @@ struct event_subsystem { struct dentry *entry; struct event_filter *filter; int nr_events; int ref_count; }; #define FILTER_PRED_INVALID ((unsigned short)-1) Loading kernel/trace/trace_events.c +95 −18 Original line number Diff line number Diff line Loading @@ -244,6 +244,35 @@ 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. */ Loading Loading @@ -519,7 +548,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' }; const char *system = filp->private_data; struct event_subsystem *system = filp->private_data; struct ftrace_event_call *call; char buf[2]; int set = 0; Loading @@ -530,7 +559,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) != 0) if (system && strcmp(call->class->system, system->name) != 0) continue; /* Loading Loading @@ -560,7 +589,8 @@ static ssize_t system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { const char *system = filp->private_data; struct event_subsystem *system = filp->private_data; const char *name = NULL; unsigned long val; ssize_t ret; Loading @@ -575,7 +605,14 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, if (val != 0 && val != 1) return -EINVAL; ret = __ftrace_set_clr_event(NULL, system, NULL, val); /* * 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); if (ret) goto out; Loading Loading @@ -808,6 +845,52 @@ 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) Loading Loading @@ -945,17 +1028,19 @@ static const struct file_operations ftrace_event_filter_fops = { }; static const struct file_operations ftrace_subsystem_filter_fops = { .open = tracing_open_generic, .open = subsystem_open, .read = subsystem_filter_read, .write = subsystem_filter_write, .llseek = default_llseek, .release = subsystem_release, }; static const struct file_operations ftrace_system_enable_fops = { .open = tracing_open_generic, .open = subsystem_open, .read = system_enable_read, .write = system_enable_write, .llseek = default_llseek, .release = subsystem_release, }; static const struct file_operations ftrace_show_header_fops = { Loading Loading @@ -984,8 +1069,6 @@ 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) { Loading @@ -995,6 +1078,7 @@ 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; } Loading @@ -1017,6 +1101,7 @@ 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); Loading Loading @@ -1044,8 +1129,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events) "'%s/filter' entry\n", name); } trace_create_file("enable", 0644, system->entry, (void *)system->name, trace_create_file("enable", 0644, system->entry, system, &ftrace_system_enable_fops); return system->entry; Loading Loading @@ -1166,16 +1250,9 @@ 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); if (filter) { kfree(filter->filter_string); kfree(filter); } kfree(system->name); kfree(system); __put_system(system); } break; } Loading Loading
include/linux/ftrace.h +4 −3 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ #include <asm/ftrace.h> struct ftrace_hash; #ifdef CONFIG_FUNCTION_TRACER extern int ftrace_enabled; Loading @@ -29,8 +31,6 @@ 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, Loading Loading @@ -123,7 +123,8 @@ stack_trace_sysctl(struct ctl_table *table, int write, struct ftrace_func_command { struct list_head list; char *name; int (*func)(char *func, char *cmd, int (*func)(struct ftrace_hash *hash, char *func, char *cmd, char *params, int enable); }; Loading
kernel/jump_label.c +9 −5 Original line number Diff line number Diff line Loading @@ -375,15 +375,19 @@ 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; /* if there are no users, entry can be NULL */ if (entry) __jump_label_update(key, entry, __stop___jump_table, enable); struct jump_entry *entry = key->entries, *stop = __stop___jump_table; #ifdef CONFIG_MODULES struct module *mod = __module_address((jump_label_t)key); __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
kernel/trace/ftrace.c +31 −11 Original line number Diff line number Diff line Loading @@ -1732,10 +1732,36 @@ 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; Loading @@ -1748,7 +1774,7 @@ static int ftrace_update_code(struct module *mod) p = ftrace_new_addrs; ftrace_new_addrs = p->newlist; p->flags = 0L; p->flags = ref; /* * Do the initial record conversion from mcount jump Loading @@ -1771,7 +1797,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) { if (ftrace_start_up && ref) { int failed = __ftrace_replace_code(p, 1); if (failed) { ftrace_bug(failed, p->ip); Loading Loading @@ -2395,10 +2421,9 @@ ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod) */ static int ftrace_mod_callback(char *func, char *cmd, char *param, int enable) ftrace_mod_callback(struct ftrace_hash *hash, char *func, char *cmd, char *param, int enable) { struct ftrace_ops *ops = &global_ops; struct ftrace_hash *hash; char *mod; int ret = -EINVAL; Loading @@ -2418,11 +2443,6 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable) 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; Loading Loading @@ -2748,7 +2768,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(func, command, next, enable); ret = p->func(hash, func, command, next, enable); goto out_unlock; } } Loading
kernel/trace/trace.h +1 −0 Original line number Diff line number Diff line Loading @@ -687,6 +687,7 @@ struct event_subsystem { struct dentry *entry; struct event_filter *filter; int nr_events; int ref_count; }; #define FILTER_PRED_INVALID ((unsigned short)-1) Loading
kernel/trace/trace_events.c +95 −18 Original line number Diff line number Diff line Loading @@ -244,6 +244,35 @@ 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. */ Loading Loading @@ -519,7 +548,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' }; const char *system = filp->private_data; struct event_subsystem *system = filp->private_data; struct ftrace_event_call *call; char buf[2]; int set = 0; Loading @@ -530,7 +559,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) != 0) if (system && strcmp(call->class->system, system->name) != 0) continue; /* Loading Loading @@ -560,7 +589,8 @@ static ssize_t system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { const char *system = filp->private_data; struct event_subsystem *system = filp->private_data; const char *name = NULL; unsigned long val; ssize_t ret; Loading @@ -575,7 +605,14 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, if (val != 0 && val != 1) return -EINVAL; ret = __ftrace_set_clr_event(NULL, system, NULL, val); /* * 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); if (ret) goto out; Loading Loading @@ -808,6 +845,52 @@ 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) Loading Loading @@ -945,17 +1028,19 @@ static const struct file_operations ftrace_event_filter_fops = { }; static const struct file_operations ftrace_subsystem_filter_fops = { .open = tracing_open_generic, .open = subsystem_open, .read = subsystem_filter_read, .write = subsystem_filter_write, .llseek = default_llseek, .release = subsystem_release, }; static const struct file_operations ftrace_system_enable_fops = { .open = tracing_open_generic, .open = subsystem_open, .read = system_enable_read, .write = system_enable_write, .llseek = default_llseek, .release = subsystem_release, }; static const struct file_operations ftrace_show_header_fops = { Loading Loading @@ -984,8 +1069,6 @@ 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) { Loading @@ -995,6 +1078,7 @@ 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; } Loading @@ -1017,6 +1101,7 @@ 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); Loading Loading @@ -1044,8 +1129,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events) "'%s/filter' entry\n", name); } trace_create_file("enable", 0644, system->entry, (void *)system->name, trace_create_file("enable", 0644, system->entry, system, &ftrace_system_enable_fops); return system->entry; Loading Loading @@ -1166,16 +1250,9 @@ 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); if (filter) { kfree(filter->filter_string); kfree(filter); } kfree(system->name); kfree(system); __put_system(system); } break; } Loading