aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c105
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 */
1443static int 1443static int
1444ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) 1444ftrace_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;
2159static unsigned long ftrace_update_cnt; 2169static unsigned long ftrace_update_cnt;
2160unsigned long ftrace_update_tot_cnt; 2170unsigned long ftrace_update_tot_cnt;
2161 2171
2162static int ops_traces_mod(struct ftrace_ops *ops) 2172static 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 */
2189static inline bool
2190ops_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
2212static 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
2170static int ftrace_update_code(struct module *mod) 2225static 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
3440static 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
3377static int 3446static int
3378ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, 3447ftrace_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
4220static inline int 4287static inline int
4221ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) 4288ftrace_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();