Extend module command for function filter selection with globbing. It uses the same globbing as function filter. sh# echo '*alloc*:mod:*' > set_ftrace_filter Will trace any function with the letters 'alloc' in the name in any module but not in kernel. sh# echo '!*alloc*:mod:ipv6' >> set_ftrace_filter Will prevent from tracing functions with 'alloc' in the name from module ipv6 (do not forget to append to set_ftrace_filter file). sh# echo '*alloc*:mod:!ipv6' > set_ftrace_filter Will trace functions with 'alloc' in the name from kernel and any module except ipv6. sh# echo '*alloc*:mod:!*' > set_ftrace_filter Will trace any function with the letters 'alloc' in the name only from kernel, but not from any module. sh# echo '*:mod:!*' > set_ftrace_filter or sh# echo ':mod:!' > set_ftrace_filter Will trace every function in the kernel, but will not trace functions from any module. sh# echo '*:mod:*' > set_ftrace_filter or sh# echo ':mod:' > set_ftrace_filter As the opposite will trace all functions from all modules, but not from kernel. sh# echo '*:mod:*snd*' > set_ftrace_filter Will trace your sound drivers only (if any). Signed-off-by: Dmitry Safonov <0x7f454c46@xxxxxxxxx> --- kernel/trace/ftrace.c | 54 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6ffc1a2..a2a4e57 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -3480,19 +3480,37 @@ enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int clear_filter) } static int -ftrace_match_record(struct dyn_ftrace *rec, - char *mod, struct ftrace_glob *func_g) +ftrace_match_record(struct dyn_ftrace *rec, struct ftrace_glob *func_g, + struct ftrace_glob *mod_g, int exclude_mod) { char str[KSYM_SYMBOL_LEN]; char *modname; kallsyms_lookup(rec->ip, NULL, NULL, &modname, str); - if (mod) { - /* module lookup requires matching the module */ - if (!modname || strcmp(modname, mod)) + if (mod_g) { + int mod_matches = (modname) ? ftrace_match(modname, mod_g) : 0; + + /* blank module name to match all modules */ + if (!mod_g->len) { + /* blank module globbing: modname xor exclude_mod */ + if ((!exclude_mod) != (!modname)) + goto func_match; + return 0; + } + + /* not matching the module */ + if (!modname || !mod_matches) { + if (exclude_mod) + goto func_match; + else + return 0; + } + + if (mod_matches && exclude_mod) return 0; +func_match: /* blank search means to match all funcs in the mod */ if (!func_g->len) return 1; @@ -3507,23 +3525,31 @@ match_records(struct ftrace_hash *hash, char *func, int len, char *mod) struct ftrace_page *pg; struct dyn_ftrace *rec; struct ftrace_glob func_g = { .type = MATCH_FULL }; + struct ftrace_glob mod_g = { .type = MATCH_FULL }; + struct ftrace_glob *mod_match = (mod) ? &mod_g : NULL; int found = 0; int ret; - int clear_filter; + int clear_filter, exclude_mod = 0; - if (len) { + if (func) { func_g.type = filter_parse_regex(func, len, &func_g.search, &clear_filter); func_g.len = strlen(func_g.search); } + if (mod) { + mod_g.type = filter_parse_regex(mod, strlen(mod), + &mod_g.search, &exclude_mod); + mod_g.len = strlen(mod_g.search); + } + mutex_lock(&ftrace_lock); if (unlikely(ftrace_disabled)) goto out_unlock; do_for_each_ftrace_rec(pg, rec) { - if (ftrace_match_record(rec, mod, &func_g)) { + if (ftrace_match_record(rec, &func_g, mod_match, exclude_mod)) { ret = enter_record(hash, rec, clear_filter); if (ret < 0) { found = ret; @@ -3554,8 +3580,6 @@ static int ftrace_mod_callback(struct ftrace_hash *hash, char *func, char *cmd, char *module, int enable) { - int ret; - /* * cmd == 'mod' because we only registered this func * for the 'mod' ftrace_func_command. @@ -3564,16 +3588,12 @@ ftrace_mod_callback(struct ftrace_hash *hash, * parameter. */ - /* we must have a module name */ - if (!module || !strlen(module)) - return -EINVAL; + int ret = match_records(hash, func, strlen(func), module); - ret = match_records(hash, func, strlen(func), module); if (ret == 0) return -EINVAL; if (ret < 0) return ret; - return 0; } @@ -3724,7 +3744,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, do_for_each_ftrace_rec(pg, rec) { - if (!ftrace_match_record(rec, NULL, &func_g)) + if (!ftrace_match_record(rec, &func_g, NULL, 0)) continue; entry = kmalloc(sizeof(*entry), GFP_KERNEL); @@ -4616,7 +4636,7 @@ ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer) do_for_each_ftrace_rec(pg, rec) { - if (ftrace_match_record(rec, NULL, &func_g)) { + if (ftrace_match_record(rec, &func_g, NULL, 0)) { /* if it is in the array */ exists = false; for (i = 0; i < *idx; i++) { -- 2.5.3 -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html