diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 105 |
1 files changed, 86 insertions, 19 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 67708f46baae..a6d098c6df3f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -1441,12 +1441,22 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable, | |||
1441 | * the hashes are freed with call_rcu_sched(). | 1441 | * the hashes are freed with call_rcu_sched(). |
1442 | */ | 1442 | */ |
1443 | static int | 1443 | static int |
1444 | ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) | 1444 | ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs) |
1445 | { | 1445 | { |
1446 | struct ftrace_hash *filter_hash; | 1446 | struct ftrace_hash *filter_hash; |
1447 | struct ftrace_hash *notrace_hash; | 1447 | struct ftrace_hash *notrace_hash; |
1448 | int ret; | 1448 | int ret; |
1449 | 1449 | ||
1450 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS | ||
1451 | /* | ||
1452 | * There's a small race when adding ops that the ftrace handler | ||
1453 | * that wants regs, may be called without them. We can not | ||
1454 | * allow that handler to be called if regs is NULL. | ||
1455 | */ | ||
1456 | if (regs == NULL && (ops->flags & FTRACE_OPS_FL_SAVE_REGS)) | ||
1457 | return 0; | ||
1458 | #endif | ||
1459 | |||
1450 | filter_hash = rcu_dereference_raw_notrace(ops->filter_hash); | 1460 | filter_hash = rcu_dereference_raw_notrace(ops->filter_hash); |
1451 | notrace_hash = rcu_dereference_raw_notrace(ops->notrace_hash); | 1461 | notrace_hash = rcu_dereference_raw_notrace(ops->notrace_hash); |
1452 | 1462 | ||
@@ -2159,12 +2169,57 @@ static cycle_t ftrace_update_time; | |||
2159 | static unsigned long ftrace_update_cnt; | 2169 | static unsigned long ftrace_update_cnt; |
2160 | unsigned long ftrace_update_tot_cnt; | 2170 | unsigned long ftrace_update_tot_cnt; |
2161 | 2171 | ||
2162 | static int ops_traces_mod(struct ftrace_ops *ops) | 2172 | static inline int ops_traces_mod(struct ftrace_ops *ops) |
2163 | { | 2173 | { |
2164 | struct ftrace_hash *hash; | 2174 | /* |
2175 | * Filter_hash being empty will default to trace module. | ||
2176 | * But notrace hash requires a test of individual module functions. | ||
2177 | */ | ||
2178 | return ftrace_hash_empty(ops->filter_hash) && | ||
2179 | ftrace_hash_empty(ops->notrace_hash); | ||
2180 | } | ||
2181 | |||
2182 | /* | ||
2183 | * Check if the current ops references the record. | ||
2184 | * | ||
2185 | * If the ops traces all functions, then it was already accounted for. | ||
2186 | * If the ops does not trace the current record function, skip it. | ||
2187 | * If the ops ignores the function via notrace filter, skip it. | ||
2188 | */ | ||
2189 | static inline bool | ||
2190 | ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec) | ||
2191 | { | ||
2192 | /* If ops isn't enabled, ignore it */ | ||
2193 | if (!(ops->flags & FTRACE_OPS_FL_ENABLED)) | ||
2194 | return 0; | ||
2195 | |||
2196 | /* If ops traces all mods, we already accounted for it */ | ||
2197 | if (ops_traces_mod(ops)) | ||
2198 | return 0; | ||
2199 | |||
2200 | /* The function must be in the filter */ | ||
2201 | if (!ftrace_hash_empty(ops->filter_hash) && | ||
2202 | !ftrace_lookup_ip(ops->filter_hash, rec->ip)) | ||
2203 | return 0; | ||
2204 | |||
2205 | /* If in notrace hash, we ignore it too */ | ||
2206 | if (ftrace_lookup_ip(ops->notrace_hash, rec->ip)) | ||
2207 | return 0; | ||
2165 | 2208 | ||
2166 | hash = ops->filter_hash; | 2209 | return 1; |
2167 | return ftrace_hash_empty(hash); | 2210 | } |
2211 | |||
2212 | static int referenced_filters(struct dyn_ftrace *rec) | ||
2213 | { | ||
2214 | struct ftrace_ops *ops; | ||
2215 | int cnt = 0; | ||
2216 | |||
2217 | for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) { | ||
2218 | if (ops_references_rec(ops, rec)) | ||
2219 | cnt++; | ||
2220 | } | ||
2221 | |||
2222 | return cnt; | ||
2168 | } | 2223 | } |
2169 | 2224 | ||
2170 | static int ftrace_update_code(struct module *mod) | 2225 | static int ftrace_update_code(struct module *mod) |
@@ -2173,6 +2228,7 @@ static int ftrace_update_code(struct module *mod) | |||
2173 | struct dyn_ftrace *p; | 2228 | struct dyn_ftrace *p; |
2174 | cycle_t start, stop; | 2229 | cycle_t start, stop; |
2175 | unsigned long ref = 0; | 2230 | unsigned long ref = 0; |
2231 | bool test = false; | ||
2176 | int i; | 2232 | int i; |
2177 | 2233 | ||
2178 | /* | 2234 | /* |
@@ -2186,9 +2242,12 @@ static int ftrace_update_code(struct module *mod) | |||
2186 | 2242 | ||
2187 | for (ops = ftrace_ops_list; | 2243 | for (ops = ftrace_ops_list; |
2188 | ops != &ftrace_list_end; ops = ops->next) { | 2244 | ops != &ftrace_list_end; ops = ops->next) { |
2189 | if (ops->flags & FTRACE_OPS_FL_ENABLED && | 2245 | if (ops->flags & FTRACE_OPS_FL_ENABLED) { |
2190 | ops_traces_mod(ops)) | 2246 | if (ops_traces_mod(ops)) |
2191 | ref++; | 2247 | ref++; |
2248 | else | ||
2249 | test = true; | ||
2250 | } | ||
2192 | } | 2251 | } |
2193 | } | 2252 | } |
2194 | 2253 | ||
@@ -2198,12 +2257,16 @@ static int ftrace_update_code(struct module *mod) | |||
2198 | for (pg = ftrace_new_pgs; pg; pg = pg->next) { | 2257 | for (pg = ftrace_new_pgs; pg; pg = pg->next) { |
2199 | 2258 | ||
2200 | for (i = 0; i < pg->index; i++) { | 2259 | for (i = 0; i < pg->index; i++) { |
2260 | int cnt = ref; | ||
2261 | |||
2201 | /* If something went wrong, bail without enabling anything */ | 2262 | /* If something went wrong, bail without enabling anything */ |
2202 | if (unlikely(ftrace_disabled)) | 2263 | if (unlikely(ftrace_disabled)) |
2203 | return -1; | 2264 | return -1; |
2204 | 2265 | ||
2205 | p = &pg->records[i]; | 2266 | p = &pg->records[i]; |
2206 | p->flags = ref; | 2267 | if (test) |
2268 | cnt += referenced_filters(p); | ||
2269 | p->flags = cnt; | ||
2207 | 2270 | ||
2208 | /* | 2271 | /* |
2209 | * Do the initial record conversion from mcount jump | 2272 | * Do the initial record conversion from mcount jump |
@@ -2223,7 +2286,7 @@ static int ftrace_update_code(struct module *mod) | |||
2223 | * conversion puts the module to the correct state, thus | 2286 | * conversion puts the module to the correct state, thus |
2224 | * passing the ftrace_make_call check. | 2287 | * passing the ftrace_make_call check. |
2225 | */ | 2288 | */ |
2226 | if (ftrace_start_up && ref) { | 2289 | if (ftrace_start_up && cnt) { |
2227 | int failed = __ftrace_replace_code(p, 1); | 2290 | int failed = __ftrace_replace_code(p, 1); |
2228 | if (failed) | 2291 | if (failed) |
2229 | ftrace_bug(failed, p->ip); | 2292 | ftrace_bug(failed, p->ip); |
@@ -3374,6 +3437,12 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove) | |||
3374 | return add_hash_entry(hash, ip); | 3437 | return add_hash_entry(hash, ip); |
3375 | } | 3438 | } |
3376 | 3439 | ||
3440 | static void ftrace_ops_update_code(struct ftrace_ops *ops) | ||
3441 | { | ||
3442 | if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) | ||
3443 | ftrace_run_update_code(FTRACE_UPDATE_CALLS); | ||
3444 | } | ||
3445 | |||
3377 | static int | 3446 | static int |
3378 | ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | 3447 | ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, |
3379 | unsigned long ip, int remove, int reset, int enable) | 3448 | unsigned long ip, int remove, int reset, int enable) |
@@ -3416,9 +3485,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
3416 | 3485 | ||
3417 | mutex_lock(&ftrace_lock); | 3486 | mutex_lock(&ftrace_lock); |
3418 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); | 3487 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); |
3419 | if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED | 3488 | if (!ret) |
3420 | && ftrace_enabled) | 3489 | ftrace_ops_update_code(ops); |
3421 | ftrace_run_update_code(FTRACE_UPDATE_CALLS); | ||
3422 | 3490 | ||
3423 | mutex_unlock(&ftrace_lock); | 3491 | mutex_unlock(&ftrace_lock); |
3424 | 3492 | ||
@@ -3645,9 +3713,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file) | |||
3645 | mutex_lock(&ftrace_lock); | 3713 | mutex_lock(&ftrace_lock); |
3646 | ret = ftrace_hash_move(iter->ops, filter_hash, | 3714 | ret = ftrace_hash_move(iter->ops, filter_hash, |
3647 | orig_hash, iter->hash); | 3715 | orig_hash, iter->hash); |
3648 | if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED) | 3716 | if (!ret) |
3649 | && ftrace_enabled) | 3717 | ftrace_ops_update_code(iter->ops); |
3650 | ftrace_run_update_code(FTRACE_UPDATE_CALLS); | ||
3651 | 3718 | ||
3652 | mutex_unlock(&ftrace_lock); | 3719 | mutex_unlock(&ftrace_lock); |
3653 | } | 3720 | } |
@@ -4218,7 +4285,7 @@ static inline void ftrace_startup_enable(int command) { } | |||
4218 | # define ftrace_shutdown_sysctl() do { } while (0) | 4285 | # define ftrace_shutdown_sysctl() do { } while (0) |
4219 | 4286 | ||
4220 | static inline int | 4287 | static inline int |
4221 | ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) | 4288 | ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs) |
4222 | { | 4289 | { |
4223 | return 1; | 4290 | return 1; |
4224 | } | 4291 | } |
@@ -4241,7 +4308,7 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip, | |||
4241 | do_for_each_ftrace_op(op, ftrace_control_list) { | 4308 | do_for_each_ftrace_op(op, ftrace_control_list) { |
4242 | if (!(op->flags & FTRACE_OPS_FL_STUB) && | 4309 | if (!(op->flags & FTRACE_OPS_FL_STUB) && |
4243 | !ftrace_function_local_disabled(op) && | 4310 | !ftrace_function_local_disabled(op) && |
4244 | ftrace_ops_test(op, ip)) | 4311 | ftrace_ops_test(op, ip, regs)) |
4245 | op->func(ip, parent_ip, op, regs); | 4312 | op->func(ip, parent_ip, op, regs); |
4246 | } while_for_each_ftrace_op(op); | 4313 | } while_for_each_ftrace_op(op); |
4247 | trace_recursion_clear(TRACE_CONTROL_BIT); | 4314 | trace_recursion_clear(TRACE_CONTROL_BIT); |
@@ -4274,7 +4341,7 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, | |||
4274 | */ | 4341 | */ |
4275 | preempt_disable_notrace(); | 4342 | preempt_disable_notrace(); |
4276 | do_for_each_ftrace_op(op, ftrace_ops_list) { | 4343 | do_for_each_ftrace_op(op, ftrace_ops_list) { |
4277 | if (ftrace_ops_test(op, ip)) | 4344 | if (ftrace_ops_test(op, ip, regs)) |
4278 | op->func(ip, parent_ip, op, regs); | 4345 | op->func(ip, parent_ip, op, regs); |
4279 | } while_for_each_ftrace_op(op); | 4346 | } while_for_each_ftrace_op(op); |
4280 | preempt_enable_notrace(); | 4347 | preempt_enable_notrace(); |