diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -4445,11 +4445,6 @@ static int print_rec(struct seq_file *m, unsigned long ip) return ret == NULL ? -1 : 0; } #else -static inline int test_for_valid_rec(struct dyn_ftrace *rec) -{ - return 1; -} - static inline int print_rec(struct seq_file *m, unsigned long ip) { seq_printf(m, "%ps", (void *)ip); @@ -7611,6 +7606,73 @@ static void test_is_sorted(unsigned long *start, unsigned long count) } #endif +#ifdef FTRACE_MCOUNT_MAX_OFFSET +struct ftrace_mod_locs { + unsigned long *start; + unsigned long count; + unsigned long *valid; +}; + +/* Mark the locations that lie at most FTRACE_MCOUNT_MAX_OFFSET after @addr. */ +static void ftrace_mark_valid_locs(void *data, unsigned long addr) +{ + struct ftrace_mod_locs *locs = data; + unsigned long lo = 0, hi = locs->count, mid, ip; + + /* + * ftrace_call_adjust() moves a location forward by at most + * FTRACE_MCOUNT_MAX_OFFSET, so start looking that far before @addr. + */ + while (lo < hi) { + mid = lo + (hi - lo) / 2; + if (locs->start[mid] + FTRACE_MCOUNT_MAX_OFFSET < addr) + lo = mid + 1; + else + hi = mid; + } + + for (; lo < locs->count; lo++) { + if (locs->start[lo] > addr + FTRACE_MCOUNT_MAX_OFFSET) + break; + ip = ftrace_call_adjust(locs->start[lo]); + if (ip >= addr && ip - addr <= FTRACE_MCOUNT_MAX_OFFSET) + __set_bit(lo, locs->valid); + } +} + +/* + * A weak function overridden within its module keeps its mcount location but + * has no symbol. Zero such locations before they become records, as sorttable + * does for vmlinux: keep only those with a symbol at most + * FTRACE_MCOUNT_MAX_OFFSET before them. + */ +static int ftrace_zero_weak_locs(struct module *mod, unsigned long *start, + unsigned long count) +{ + struct ftrace_mod_locs locs = { .start = start, .count = count }; + unsigned long i; + + locs.valid = bitmap_zalloc(count, GFP_KERNEL); + if (!locs.valid) + return -ENOMEM; + + module_kallsyms_on_each_addr(mod, ftrace_mark_valid_locs, &locs); + + for_each_clear_bit(i, locs.valid, count) + start[i] = 0; + + bitmap_free(locs.valid); + return 0; +} +#else +static inline int ftrace_zero_weak_locs(struct module *mod, + unsigned long *start, + unsigned long count) +{ + return 0; +} +#endif + static int ftrace_process_locs(struct module *mod, unsigned long *start, unsigned long *end) @@ -7644,6 +7706,9 @@ static int ftrace_process_locs(struct module *mod, test_is_sorted(start, count); } + if (mod && ftrace_zero_weak_locs(mod, start, count)) + return -ENOMEM; + start_pg = ftrace_allocate_pages(count, &pages); if (!start_pg) return -ENOMEM; @@ -8049,13 +8114,6 @@ void ftrace_module_enable(struct module *mod) cond_resched(); - /* Weak functions should still be ignored */ - if (!test_for_valid_rec(rec)) { - /* Clear all other flags. Should not be enabled anyway */ - rec->flags = FTRACE_FL_DISABLED; - continue; - } - cnt = 0; /*