diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 321 |
1 files changed, 190 insertions, 131 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1e6640f80454..f3dadae83883 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -22,12 +22,13 @@ | |||
22 | #include <linux/hardirq.h> | 22 | #include <linux/hardirq.h> |
23 | #include <linux/kthread.h> | 23 | #include <linux/kthread.h> |
24 | #include <linux/uaccess.h> | 24 | #include <linux/uaccess.h> |
25 | #include <linux/kprobes.h> | ||
26 | #include <linux/ftrace.h> | 25 | #include <linux/ftrace.h> |
27 | #include <linux/sysctl.h> | 26 | #include <linux/sysctl.h> |
27 | #include <linux/slab.h> | ||
28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/hash.h> | 30 | #include <linux/hash.h> |
31 | #include <linux/rcupdate.h> | ||
31 | 32 | ||
32 | #include <trace/events/sched.h> | 33 | #include <trace/events/sched.h> |
33 | 34 | ||
@@ -85,22 +86,22 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | |||
85 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; | 86 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; |
86 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; | 87 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; |
87 | 88 | ||
88 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 89 | /* |
89 | static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); | 90 | * Traverse the ftrace_list, invoking all entries. The reason that we |
90 | #endif | 91 | * can use rcu_dereference_raw() is that elements removed from this list |
91 | 92 | * are simply leaked, so there is no need to interact with a grace-period | |
93 | * mechanism. The rcu_dereference_raw() calls are needed to handle | ||
94 | * concurrent insertions into the ftrace_list. | ||
95 | * | ||
96 | * Silly Alpha and silly pointer-speculation compiler optimizations! | ||
97 | */ | ||
92 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) | 98 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) |
93 | { | 99 | { |
94 | struct ftrace_ops *op = ftrace_list; | 100 | struct ftrace_ops *op = rcu_dereference_raw(ftrace_list); /*see above*/ |
95 | |||
96 | /* in case someone actually ports this to alpha! */ | ||
97 | read_barrier_depends(); | ||
98 | 101 | ||
99 | while (op != &ftrace_list_end) { | 102 | while (op != &ftrace_list_end) { |
100 | /* silly alpha */ | ||
101 | read_barrier_depends(); | ||
102 | op->func(ip, parent_ip); | 103 | op->func(ip, parent_ip); |
103 | op = op->next; | 104 | op = rcu_dereference_raw(op->next); /*see above*/ |
104 | }; | 105 | }; |
105 | } | 106 | } |
106 | 107 | ||
@@ -155,8 +156,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
155 | * the ops->next pointer is valid before another CPU sees | 156 | * the ops->next pointer is valid before another CPU sees |
156 | * the ops pointer included into the ftrace_list. | 157 | * the ops pointer included into the ftrace_list. |
157 | */ | 158 | */ |
158 | smp_wmb(); | 159 | rcu_assign_pointer(ftrace_list, ops); |
159 | ftrace_list = ops; | ||
160 | 160 | ||
161 | if (ftrace_enabled) { | 161 | if (ftrace_enabled) { |
162 | ftrace_func_t func; | 162 | ftrace_func_t func; |
@@ -264,6 +264,7 @@ struct ftrace_profile { | |||
264 | unsigned long counter; | 264 | unsigned long counter; |
265 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 265 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
266 | unsigned long long time; | 266 | unsigned long long time; |
267 | unsigned long long time_squared; | ||
267 | #endif | 268 | #endif |
268 | }; | 269 | }; |
269 | 270 | ||
@@ -366,9 +367,9 @@ static int function_stat_headers(struct seq_file *m) | |||
366 | { | 367 | { |
367 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 368 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
368 | seq_printf(m, " Function " | 369 | seq_printf(m, " Function " |
369 | "Hit Time Avg\n" | 370 | "Hit Time Avg s^2\n" |
370 | " -------- " | 371 | " -------- " |
371 | "--- ---- ---\n"); | 372 | "--- ---- --- ---\n"); |
372 | #else | 373 | #else |
373 | seq_printf(m, " Function Hit\n" | 374 | seq_printf(m, " Function Hit\n" |
374 | " -------- ---\n"); | 375 | " -------- ---\n"); |
@@ -380,11 +381,19 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
380 | { | 381 | { |
381 | struct ftrace_profile *rec = v; | 382 | struct ftrace_profile *rec = v; |
382 | char str[KSYM_SYMBOL_LEN]; | 383 | char str[KSYM_SYMBOL_LEN]; |
384 | int ret = 0; | ||
383 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 385 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
384 | static DEFINE_MUTEX(mutex); | ||
385 | static struct trace_seq s; | 386 | static struct trace_seq s; |
386 | unsigned long long avg; | 387 | unsigned long long avg; |
388 | unsigned long long stddev; | ||
387 | #endif | 389 | #endif |
390 | mutex_lock(&ftrace_profile_lock); | ||
391 | |||
392 | /* we raced with function_profile_reset() */ | ||
393 | if (unlikely(rec->counter == 0)) { | ||
394 | ret = -EBUSY; | ||
395 | goto out; | ||
396 | } | ||
388 | 397 | ||
389 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | 398 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); |
390 | seq_printf(m, " %-30.30s %10lu", str, rec->counter); | 399 | seq_printf(m, " %-30.30s %10lu", str, rec->counter); |
@@ -394,17 +403,31 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
394 | avg = rec->time; | 403 | avg = rec->time; |
395 | do_div(avg, rec->counter); | 404 | do_div(avg, rec->counter); |
396 | 405 | ||
397 | mutex_lock(&mutex); | 406 | /* Sample standard deviation (s^2) */ |
407 | if (rec->counter <= 1) | ||
408 | stddev = 0; | ||
409 | else { | ||
410 | stddev = rec->time_squared - rec->counter * avg * avg; | ||
411 | /* | ||
412 | * Divide only 1000 for ns^2 -> us^2 conversion. | ||
413 | * trace_print_graph_duration will divide 1000 again. | ||
414 | */ | ||
415 | do_div(stddev, (rec->counter - 1) * 1000); | ||
416 | } | ||
417 | |||
398 | trace_seq_init(&s); | 418 | trace_seq_init(&s); |
399 | trace_print_graph_duration(rec->time, &s); | 419 | trace_print_graph_duration(rec->time, &s); |
400 | trace_seq_puts(&s, " "); | 420 | trace_seq_puts(&s, " "); |
401 | trace_print_graph_duration(avg, &s); | 421 | trace_print_graph_duration(avg, &s); |
422 | trace_seq_puts(&s, " "); | ||
423 | trace_print_graph_duration(stddev, &s); | ||
402 | trace_print_seq(m, &s); | 424 | trace_print_seq(m, &s); |
403 | mutex_unlock(&mutex); | ||
404 | #endif | 425 | #endif |
405 | seq_putc(m, '\n'); | 426 | seq_putc(m, '\n'); |
427 | out: | ||
428 | mutex_unlock(&ftrace_profile_lock); | ||
406 | 429 | ||
407 | return 0; | 430 | return ret; |
408 | } | 431 | } |
409 | 432 | ||
410 | static void ftrace_profile_reset(struct ftrace_profile_stat *stat) | 433 | static void ftrace_profile_reset(struct ftrace_profile_stat *stat) |
@@ -650,6 +673,10 @@ static void profile_graph_return(struct ftrace_graph_ret *trace) | |||
650 | if (!stat->hash || !ftrace_profile_enabled) | 673 | if (!stat->hash || !ftrace_profile_enabled) |
651 | goto out; | 674 | goto out; |
652 | 675 | ||
676 | /* If the calltime was zero'd ignore it */ | ||
677 | if (!trace->calltime) | ||
678 | goto out; | ||
679 | |||
653 | calltime = trace->rettime - trace->calltime; | 680 | calltime = trace->rettime - trace->calltime; |
654 | 681 | ||
655 | if (!(trace_flags & TRACE_ITER_GRAPH_TIME)) { | 682 | if (!(trace_flags & TRACE_ITER_GRAPH_TIME)) { |
@@ -668,8 +695,10 @@ static void profile_graph_return(struct ftrace_graph_ret *trace) | |||
668 | } | 695 | } |
669 | 696 | ||
670 | rec = ftrace_find_profiled_func(stat, trace->func); | 697 | rec = ftrace_find_profiled_func(stat, trace->func); |
671 | if (rec) | 698 | if (rec) { |
672 | rec->time += calltime; | 699 | rec->time += calltime; |
700 | rec->time_squared += calltime * calltime; | ||
701 | } | ||
673 | 702 | ||
674 | out: | 703 | out: |
675 | local_irq_restore(flags); | 704 | local_irq_restore(flags); |
@@ -771,6 +800,7 @@ static const struct file_operations ftrace_profile_fops = { | |||
771 | .open = tracing_open_generic, | 800 | .open = tracing_open_generic, |
772 | .read = ftrace_profile_read, | 801 | .read = ftrace_profile_read, |
773 | .write = ftrace_profile_write, | 802 | .write = ftrace_profile_write, |
803 | .llseek = default_llseek, | ||
774 | }; | 804 | }; |
775 | 805 | ||
776 | /* used to initialize the real stat files */ | 806 | /* used to initialize the real stat files */ |
@@ -855,10 +885,8 @@ enum { | |||
855 | FTRACE_ENABLE_CALLS = (1 << 0), | 885 | FTRACE_ENABLE_CALLS = (1 << 0), |
856 | FTRACE_DISABLE_CALLS = (1 << 1), | 886 | FTRACE_DISABLE_CALLS = (1 << 1), |
857 | FTRACE_UPDATE_TRACE_FUNC = (1 << 2), | 887 | FTRACE_UPDATE_TRACE_FUNC = (1 << 2), |
858 | FTRACE_ENABLE_MCOUNT = (1 << 3), | 888 | FTRACE_START_FUNC_RET = (1 << 3), |
859 | FTRACE_DISABLE_MCOUNT = (1 << 4), | 889 | FTRACE_STOP_FUNC_RET = (1 << 4), |
860 | FTRACE_START_FUNC_RET = (1 << 5), | ||
861 | FTRACE_STOP_FUNC_RET = (1 << 6), | ||
862 | }; | 890 | }; |
863 | 891 | ||
864 | static int ftrace_filtered; | 892 | static int ftrace_filtered; |
@@ -898,36 +926,6 @@ static struct dyn_ftrace *ftrace_free_records; | |||
898 | } \ | 926 | } \ |
899 | } | 927 | } |
900 | 928 | ||
901 | #ifdef CONFIG_KPROBES | ||
902 | |||
903 | static int frozen_record_count; | ||
904 | |||
905 | static inline void freeze_record(struct dyn_ftrace *rec) | ||
906 | { | ||
907 | if (!(rec->flags & FTRACE_FL_FROZEN)) { | ||
908 | rec->flags |= FTRACE_FL_FROZEN; | ||
909 | frozen_record_count++; | ||
910 | } | ||
911 | } | ||
912 | |||
913 | static inline void unfreeze_record(struct dyn_ftrace *rec) | ||
914 | { | ||
915 | if (rec->flags & FTRACE_FL_FROZEN) { | ||
916 | rec->flags &= ~FTRACE_FL_FROZEN; | ||
917 | frozen_record_count--; | ||
918 | } | ||
919 | } | ||
920 | |||
921 | static inline int record_frozen(struct dyn_ftrace *rec) | ||
922 | { | ||
923 | return rec->flags & FTRACE_FL_FROZEN; | ||
924 | } | ||
925 | #else | ||
926 | # define freeze_record(rec) ({ 0; }) | ||
927 | # define unfreeze_record(rec) ({ 0; }) | ||
928 | # define record_frozen(rec) ({ 0; }) | ||
929 | #endif /* CONFIG_KPROBES */ | ||
930 | |||
931 | static void ftrace_free_rec(struct dyn_ftrace *rec) | 929 | static void ftrace_free_rec(struct dyn_ftrace *rec) |
932 | { | 930 | { |
933 | rec->freelist = ftrace_free_records; | 931 | rec->freelist = ftrace_free_records; |
@@ -1025,6 +1023,21 @@ static void ftrace_bug(int failed, unsigned long ip) | |||
1025 | } | 1023 | } |
1026 | 1024 | ||
1027 | 1025 | ||
1026 | /* Return 1 if the address range is reserved for ftrace */ | ||
1027 | int ftrace_text_reserved(void *start, void *end) | ||
1028 | { | ||
1029 | struct dyn_ftrace *rec; | ||
1030 | struct ftrace_page *pg; | ||
1031 | |||
1032 | do_for_each_ftrace_rec(pg, rec) { | ||
1033 | if (rec->ip <= (unsigned long)end && | ||
1034 | rec->ip + MCOUNT_INSN_SIZE > (unsigned long)start) | ||
1035 | return 1; | ||
1036 | } while_for_each_ftrace_rec(); | ||
1037 | return 0; | ||
1038 | } | ||
1039 | |||
1040 | |||
1028 | static int | 1041 | static int |
1029 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | 1042 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) |
1030 | { | 1043 | { |
@@ -1076,14 +1089,6 @@ static void ftrace_replace_code(int enable) | |||
1076 | !(rec->flags & FTRACE_FL_CONVERTED)) | 1089 | !(rec->flags & FTRACE_FL_CONVERTED)) |
1077 | continue; | 1090 | continue; |
1078 | 1091 | ||
1079 | /* ignore updates to this record's mcount site */ | ||
1080 | if (get_kprobe((void *)rec->ip)) { | ||
1081 | freeze_record(rec); | ||
1082 | continue; | ||
1083 | } else { | ||
1084 | unfreeze_record(rec); | ||
1085 | } | ||
1086 | |||
1087 | failed = __ftrace_replace_code(rec, enable); | 1092 | failed = __ftrace_replace_code(rec, enable); |
1088 | if (failed) { | 1093 | if (failed) { |
1089 | rec->flags |= FTRACE_FL_FAILED; | 1094 | rec->flags |= FTRACE_FL_FAILED; |
@@ -1220,8 +1225,6 @@ static void ftrace_shutdown(int command) | |||
1220 | 1225 | ||
1221 | static void ftrace_startup_sysctl(void) | 1226 | static void ftrace_startup_sysctl(void) |
1222 | { | 1227 | { |
1223 | int command = FTRACE_ENABLE_MCOUNT; | ||
1224 | |||
1225 | if (unlikely(ftrace_disabled)) | 1228 | if (unlikely(ftrace_disabled)) |
1226 | return; | 1229 | return; |
1227 | 1230 | ||
@@ -1229,23 +1232,17 @@ static void ftrace_startup_sysctl(void) | |||
1229 | saved_ftrace_func = NULL; | 1232 | saved_ftrace_func = NULL; |
1230 | /* ftrace_start_up is true if we want ftrace running */ | 1233 | /* ftrace_start_up is true if we want ftrace running */ |
1231 | if (ftrace_start_up) | 1234 | if (ftrace_start_up) |
1232 | command |= FTRACE_ENABLE_CALLS; | 1235 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); |
1233 | |||
1234 | ftrace_run_update_code(command); | ||
1235 | } | 1236 | } |
1236 | 1237 | ||
1237 | static void ftrace_shutdown_sysctl(void) | 1238 | static void ftrace_shutdown_sysctl(void) |
1238 | { | 1239 | { |
1239 | int command = FTRACE_DISABLE_MCOUNT; | ||
1240 | |||
1241 | if (unlikely(ftrace_disabled)) | 1240 | if (unlikely(ftrace_disabled)) |
1242 | return; | 1241 | return; |
1243 | 1242 | ||
1244 | /* ftrace_start_up is true if ftrace is running */ | 1243 | /* ftrace_start_up is true if ftrace is running */ |
1245 | if (ftrace_start_up) | 1244 | if (ftrace_start_up) |
1246 | command |= FTRACE_DISABLE_CALLS; | 1245 | ftrace_run_update_code(FTRACE_DISABLE_CALLS); |
1247 | |||
1248 | ftrace_run_update_code(command); | ||
1249 | } | 1246 | } |
1250 | 1247 | ||
1251 | static cycle_t ftrace_update_time; | 1248 | static cycle_t ftrace_update_time; |
@@ -1362,24 +1359,29 @@ enum { | |||
1362 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1359 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
1363 | 1360 | ||
1364 | struct ftrace_iterator { | 1361 | struct ftrace_iterator { |
1365 | struct ftrace_page *pg; | 1362 | loff_t pos; |
1366 | int hidx; | 1363 | loff_t func_pos; |
1367 | int idx; | 1364 | struct ftrace_page *pg; |
1368 | unsigned flags; | 1365 | struct dyn_ftrace *func; |
1369 | struct trace_parser parser; | 1366 | struct ftrace_func_probe *probe; |
1367 | struct trace_parser parser; | ||
1368 | int hidx; | ||
1369 | int idx; | ||
1370 | unsigned flags; | ||
1370 | }; | 1371 | }; |
1371 | 1372 | ||
1372 | static void * | 1373 | static void * |
1373 | t_hash_next(struct seq_file *m, void *v, loff_t *pos) | 1374 | t_hash_next(struct seq_file *m, loff_t *pos) |
1374 | { | 1375 | { |
1375 | struct ftrace_iterator *iter = m->private; | 1376 | struct ftrace_iterator *iter = m->private; |
1376 | struct hlist_node *hnd = v; | 1377 | struct hlist_node *hnd = NULL; |
1377 | struct hlist_head *hhd; | 1378 | struct hlist_head *hhd; |
1378 | 1379 | ||
1379 | WARN_ON(!(iter->flags & FTRACE_ITER_HASH)); | ||
1380 | |||
1381 | (*pos)++; | 1380 | (*pos)++; |
1381 | iter->pos = *pos; | ||
1382 | 1382 | ||
1383 | if (iter->probe) | ||
1384 | hnd = &iter->probe->node; | ||
1383 | retry: | 1385 | retry: |
1384 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) | 1386 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) |
1385 | return NULL; | 1387 | return NULL; |
@@ -1402,7 +1404,12 @@ t_hash_next(struct seq_file *m, void *v, loff_t *pos) | |||
1402 | } | 1404 | } |
1403 | } | 1405 | } |
1404 | 1406 | ||
1405 | return hnd; | 1407 | if (WARN_ON_ONCE(!hnd)) |
1408 | return NULL; | ||
1409 | |||
1410 | iter->probe = hlist_entry(hnd, struct ftrace_func_probe, node); | ||
1411 | |||
1412 | return iter; | ||
1406 | } | 1413 | } |
1407 | 1414 | ||
1408 | static void *t_hash_start(struct seq_file *m, loff_t *pos) | 1415 | static void *t_hash_start(struct seq_file *m, loff_t *pos) |
@@ -1411,26 +1418,32 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) | |||
1411 | void *p = NULL; | 1418 | void *p = NULL; |
1412 | loff_t l; | 1419 | loff_t l; |
1413 | 1420 | ||
1414 | if (!(iter->flags & FTRACE_ITER_HASH)) | 1421 | if (iter->func_pos > *pos) |
1415 | *pos = 0; | 1422 | return NULL; |
1416 | |||
1417 | iter->flags |= FTRACE_ITER_HASH; | ||
1418 | 1423 | ||
1419 | iter->hidx = 0; | 1424 | iter->hidx = 0; |
1420 | for (l = 0; l <= *pos; ) { | 1425 | for (l = 0; l <= (*pos - iter->func_pos); ) { |
1421 | p = t_hash_next(m, p, &l); | 1426 | p = t_hash_next(m, &l); |
1422 | if (!p) | 1427 | if (!p) |
1423 | break; | 1428 | break; |
1424 | } | 1429 | } |
1425 | return p; | 1430 | if (!p) |
1431 | return NULL; | ||
1432 | |||
1433 | /* Only set this if we have an item */ | ||
1434 | iter->flags |= FTRACE_ITER_HASH; | ||
1435 | |||
1436 | return iter; | ||
1426 | } | 1437 | } |
1427 | 1438 | ||
1428 | static int t_hash_show(struct seq_file *m, void *v) | 1439 | static int |
1440 | t_hash_show(struct seq_file *m, struct ftrace_iterator *iter) | ||
1429 | { | 1441 | { |
1430 | struct ftrace_func_probe *rec; | 1442 | struct ftrace_func_probe *rec; |
1431 | struct hlist_node *hnd = v; | ||
1432 | 1443 | ||
1433 | rec = hlist_entry(hnd, struct ftrace_func_probe, node); | 1444 | rec = iter->probe; |
1445 | if (WARN_ON_ONCE(!rec)) | ||
1446 | return -EIO; | ||
1434 | 1447 | ||
1435 | if (rec->ops->print) | 1448 | if (rec->ops->print) |
1436 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); | 1449 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); |
@@ -1451,12 +1464,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1451 | struct dyn_ftrace *rec = NULL; | 1464 | struct dyn_ftrace *rec = NULL; |
1452 | 1465 | ||
1453 | if (iter->flags & FTRACE_ITER_HASH) | 1466 | if (iter->flags & FTRACE_ITER_HASH) |
1454 | return t_hash_next(m, v, pos); | 1467 | return t_hash_next(m, pos); |
1455 | 1468 | ||
1456 | (*pos)++; | 1469 | (*pos)++; |
1470 | iter->pos = *pos; | ||
1457 | 1471 | ||
1458 | if (iter->flags & FTRACE_ITER_PRINTALL) | 1472 | if (iter->flags & FTRACE_ITER_PRINTALL) |
1459 | return NULL; | 1473 | return t_hash_start(m, pos); |
1460 | 1474 | ||
1461 | retry: | 1475 | retry: |
1462 | if (iter->idx >= iter->pg->index) { | 1476 | if (iter->idx >= iter->pg->index) { |
@@ -1485,7 +1499,20 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1485 | } | 1499 | } |
1486 | } | 1500 | } |
1487 | 1501 | ||
1488 | return rec; | 1502 | if (!rec) |
1503 | return t_hash_start(m, pos); | ||
1504 | |||
1505 | iter->func_pos = *pos; | ||
1506 | iter->func = rec; | ||
1507 | |||
1508 | return iter; | ||
1509 | } | ||
1510 | |||
1511 | static void reset_iter_read(struct ftrace_iterator *iter) | ||
1512 | { | ||
1513 | iter->pos = 0; | ||
1514 | iter->func_pos = 0; | ||
1515 | iter->flags &= ~(FTRACE_ITER_PRINTALL & FTRACE_ITER_HASH); | ||
1489 | } | 1516 | } |
1490 | 1517 | ||
1491 | static void *t_start(struct seq_file *m, loff_t *pos) | 1518 | static void *t_start(struct seq_file *m, loff_t *pos) |
@@ -1496,6 +1523,12 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1496 | 1523 | ||
1497 | mutex_lock(&ftrace_lock); | 1524 | mutex_lock(&ftrace_lock); |
1498 | /* | 1525 | /* |
1526 | * If an lseek was done, then reset and start from beginning. | ||
1527 | */ | ||
1528 | if (*pos < iter->pos) | ||
1529 | reset_iter_read(iter); | ||
1530 | |||
1531 | /* | ||
1499 | * For set_ftrace_filter reading, if we have the filter | 1532 | * For set_ftrace_filter reading, if we have the filter |
1500 | * off, we can short cut and just print out that all | 1533 | * off, we can short cut and just print out that all |
1501 | * functions are enabled. | 1534 | * functions are enabled. |
@@ -1504,12 +1537,19 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1504 | if (*pos > 0) | 1537 | if (*pos > 0) |
1505 | return t_hash_start(m, pos); | 1538 | return t_hash_start(m, pos); |
1506 | iter->flags |= FTRACE_ITER_PRINTALL; | 1539 | iter->flags |= FTRACE_ITER_PRINTALL; |
1540 | /* reset in case of seek/pread */ | ||
1541 | iter->flags &= ~FTRACE_ITER_HASH; | ||
1507 | return iter; | 1542 | return iter; |
1508 | } | 1543 | } |
1509 | 1544 | ||
1510 | if (iter->flags & FTRACE_ITER_HASH) | 1545 | if (iter->flags & FTRACE_ITER_HASH) |
1511 | return t_hash_start(m, pos); | 1546 | return t_hash_start(m, pos); |
1512 | 1547 | ||
1548 | /* | ||
1549 | * Unfortunately, we need to restart at ftrace_pages_start | ||
1550 | * every time we let go of the ftrace_mutex. This is because | ||
1551 | * those pointers can change without the lock. | ||
1552 | */ | ||
1513 | iter->pg = ftrace_pages_start; | 1553 | iter->pg = ftrace_pages_start; |
1514 | iter->idx = 0; | 1554 | iter->idx = 0; |
1515 | for (l = 0; l <= *pos; ) { | 1555 | for (l = 0; l <= *pos; ) { |
@@ -1518,10 +1558,14 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1518 | break; | 1558 | break; |
1519 | } | 1559 | } |
1520 | 1560 | ||
1521 | if (!p && iter->flags & FTRACE_ITER_FILTER) | 1561 | if (!p) { |
1522 | return t_hash_start(m, pos); | 1562 | if (iter->flags & FTRACE_ITER_FILTER) |
1563 | return t_hash_start(m, pos); | ||
1564 | |||
1565 | return NULL; | ||
1566 | } | ||
1523 | 1567 | ||
1524 | return p; | 1568 | return iter; |
1525 | } | 1569 | } |
1526 | 1570 | ||
1527 | static void t_stop(struct seq_file *m, void *p) | 1571 | static void t_stop(struct seq_file *m, void *p) |
@@ -1532,16 +1576,18 @@ static void t_stop(struct seq_file *m, void *p) | |||
1532 | static int t_show(struct seq_file *m, void *v) | 1576 | static int t_show(struct seq_file *m, void *v) |
1533 | { | 1577 | { |
1534 | struct ftrace_iterator *iter = m->private; | 1578 | struct ftrace_iterator *iter = m->private; |
1535 | struct dyn_ftrace *rec = v; | 1579 | struct dyn_ftrace *rec; |
1536 | 1580 | ||
1537 | if (iter->flags & FTRACE_ITER_HASH) | 1581 | if (iter->flags & FTRACE_ITER_HASH) |
1538 | return t_hash_show(m, v); | 1582 | return t_hash_show(m, iter); |
1539 | 1583 | ||
1540 | if (iter->flags & FTRACE_ITER_PRINTALL) { | 1584 | if (iter->flags & FTRACE_ITER_PRINTALL) { |
1541 | seq_printf(m, "#### all functions enabled ####\n"); | 1585 | seq_printf(m, "#### all functions enabled ####\n"); |
1542 | return 0; | 1586 | return 0; |
1543 | } | 1587 | } |
1544 | 1588 | ||
1589 | rec = iter->func; | ||
1590 | |||
1545 | if (!rec) | 1591 | if (!rec) |
1546 | return 0; | 1592 | return 0; |
1547 | 1593 | ||
@@ -1593,8 +1639,8 @@ ftrace_failures_open(struct inode *inode, struct file *file) | |||
1593 | 1639 | ||
1594 | ret = ftrace_avail_open(inode, file); | 1640 | ret = ftrace_avail_open(inode, file); |
1595 | if (!ret) { | 1641 | if (!ret) { |
1596 | m = (struct seq_file *)file->private_data; | 1642 | m = file->private_data; |
1597 | iter = (struct ftrace_iterator *)m->private; | 1643 | iter = m->private; |
1598 | iter->flags = FTRACE_ITER_FAILURES; | 1644 | iter->flags = FTRACE_ITER_FAILURES; |
1599 | } | 1645 | } |
1600 | 1646 | ||
@@ -1884,7 +1930,6 @@ function_trace_probe_call(unsigned long ip, unsigned long parent_ip) | |||
1884 | struct hlist_head *hhd; | 1930 | struct hlist_head *hhd; |
1885 | struct hlist_node *n; | 1931 | struct hlist_node *n; |
1886 | unsigned long key; | 1932 | unsigned long key; |
1887 | int resched; | ||
1888 | 1933 | ||
1889 | key = hash_long(ip, FTRACE_HASH_BITS); | 1934 | key = hash_long(ip, FTRACE_HASH_BITS); |
1890 | 1935 | ||
@@ -1898,12 +1943,12 @@ function_trace_probe_call(unsigned long ip, unsigned long parent_ip) | |||
1898 | * period. This syncs the hash iteration and freeing of items | 1943 | * period. This syncs the hash iteration and freeing of items |
1899 | * on the hash. rcu_read_lock is too dangerous here. | 1944 | * on the hash. rcu_read_lock is too dangerous here. |
1900 | */ | 1945 | */ |
1901 | resched = ftrace_preempt_disable(); | 1946 | preempt_disable_notrace(); |
1902 | hlist_for_each_entry_rcu(entry, n, hhd, node) { | 1947 | hlist_for_each_entry_rcu(entry, n, hhd, node) { |
1903 | if (entry->ip == ip) | 1948 | if (entry->ip == ip) |
1904 | entry->ops->func(ip, parent_ip, &entry->data); | 1949 | entry->ops->func(ip, parent_ip, &entry->data); |
1905 | } | 1950 | } |
1906 | ftrace_preempt_enable(resched); | 1951 | preempt_enable_notrace(); |
1907 | } | 1952 | } |
1908 | 1953 | ||
1909 | static struct ftrace_ops trace_probe_ops __read_mostly = | 1954 | static struct ftrace_ops trace_probe_ops __read_mostly = |
@@ -2300,6 +2345,8 @@ __setup("ftrace_filter=", set_ftrace_filter); | |||
2300 | 2345 | ||
2301 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 2346 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
2302 | static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; | 2347 | static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; |
2348 | static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); | ||
2349 | |||
2303 | static int __init set_graph_function(char *str) | 2350 | static int __init set_graph_function(char *str) |
2304 | { | 2351 | { |
2305 | strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); | 2352 | strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); |
@@ -2426,6 +2473,7 @@ static const struct file_operations ftrace_notrace_fops = { | |||
2426 | static DEFINE_MUTEX(graph_lock); | 2473 | static DEFINE_MUTEX(graph_lock); |
2427 | 2474 | ||
2428 | int ftrace_graph_count; | 2475 | int ftrace_graph_count; |
2476 | int ftrace_graph_filter_enabled; | ||
2429 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | 2477 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; |
2430 | 2478 | ||
2431 | static void * | 2479 | static void * |
@@ -2448,7 +2496,7 @@ static void *g_start(struct seq_file *m, loff_t *pos) | |||
2448 | mutex_lock(&graph_lock); | 2496 | mutex_lock(&graph_lock); |
2449 | 2497 | ||
2450 | /* Nothing, tell g_show to print all functions are enabled */ | 2498 | /* Nothing, tell g_show to print all functions are enabled */ |
2451 | if (!ftrace_graph_count && !*pos) | 2499 | if (!ftrace_graph_filter_enabled && !*pos) |
2452 | return (void *)1; | 2500 | return (void *)1; |
2453 | 2501 | ||
2454 | return __g_next(m, pos); | 2502 | return __g_next(m, pos); |
@@ -2494,6 +2542,7 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
2494 | mutex_lock(&graph_lock); | 2542 | mutex_lock(&graph_lock); |
2495 | if ((file->f_mode & FMODE_WRITE) && | 2543 | if ((file->f_mode & FMODE_WRITE) && |
2496 | (file->f_flags & O_TRUNC)) { | 2544 | (file->f_flags & O_TRUNC)) { |
2545 | ftrace_graph_filter_enabled = 0; | ||
2497 | ftrace_graph_count = 0; | 2546 | ftrace_graph_count = 0; |
2498 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | 2547 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); |
2499 | } | 2548 | } |
@@ -2519,7 +2568,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2519 | struct dyn_ftrace *rec; | 2568 | struct dyn_ftrace *rec; |
2520 | struct ftrace_page *pg; | 2569 | struct ftrace_page *pg; |
2521 | int search_len; | 2570 | int search_len; |
2522 | int found = 0; | 2571 | int fail = 1; |
2523 | int type, not; | 2572 | int type, not; |
2524 | char *search; | 2573 | char *search; |
2525 | bool exists; | 2574 | bool exists; |
@@ -2530,37 +2579,51 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2530 | 2579 | ||
2531 | /* decode regex */ | 2580 | /* decode regex */ |
2532 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); | 2581 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
2533 | if (not) | 2582 | if (!not && *idx >= FTRACE_GRAPH_MAX_FUNCS) |
2534 | return -EINVAL; | 2583 | return -EBUSY; |
2535 | 2584 | ||
2536 | search_len = strlen(search); | 2585 | search_len = strlen(search); |
2537 | 2586 | ||
2538 | mutex_lock(&ftrace_lock); | 2587 | mutex_lock(&ftrace_lock); |
2539 | do_for_each_ftrace_rec(pg, rec) { | 2588 | do_for_each_ftrace_rec(pg, rec) { |
2540 | 2589 | ||
2541 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | ||
2542 | break; | ||
2543 | |||
2544 | if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) | 2590 | if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) |
2545 | continue; | 2591 | continue; |
2546 | 2592 | ||
2547 | if (ftrace_match_record(rec, search, search_len, type)) { | 2593 | if (ftrace_match_record(rec, search, search_len, type)) { |
2548 | /* ensure it is not already in the array */ | 2594 | /* if it is in the array */ |
2549 | exists = false; | 2595 | exists = false; |
2550 | for (i = 0; i < *idx; i++) | 2596 | for (i = 0; i < *idx; i++) { |
2551 | if (array[i] == rec->ip) { | 2597 | if (array[i] == rec->ip) { |
2552 | exists = true; | 2598 | exists = true; |
2553 | break; | 2599 | break; |
2554 | } | 2600 | } |
2555 | if (!exists) | 2601 | } |
2556 | array[(*idx)++] = rec->ip; | 2602 | |
2557 | found = 1; | 2603 | if (!not) { |
2604 | fail = 0; | ||
2605 | if (!exists) { | ||
2606 | array[(*idx)++] = rec->ip; | ||
2607 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | ||
2608 | goto out; | ||
2609 | } | ||
2610 | } else { | ||
2611 | if (exists) { | ||
2612 | array[i] = array[--(*idx)]; | ||
2613 | array[*idx] = 0; | ||
2614 | fail = 0; | ||
2615 | } | ||
2616 | } | ||
2558 | } | 2617 | } |
2559 | } while_for_each_ftrace_rec(); | 2618 | } while_for_each_ftrace_rec(); |
2560 | 2619 | out: | |
2561 | mutex_unlock(&ftrace_lock); | 2620 | mutex_unlock(&ftrace_lock); |
2562 | 2621 | ||
2563 | return found ? 0 : -EINVAL; | 2622 | if (fail) |
2623 | return -EINVAL; | ||
2624 | |||
2625 | ftrace_graph_filter_enabled = 1; | ||
2626 | return 0; | ||
2564 | } | 2627 | } |
2565 | 2628 | ||
2566 | static ssize_t | 2629 | static ssize_t |
@@ -2570,16 +2633,11 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
2570 | struct trace_parser parser; | 2633 | struct trace_parser parser; |
2571 | ssize_t read, ret; | 2634 | ssize_t read, ret; |
2572 | 2635 | ||
2573 | if (!cnt || cnt < 0) | 2636 | if (!cnt) |
2574 | return 0; | 2637 | return 0; |
2575 | 2638 | ||
2576 | mutex_lock(&graph_lock); | 2639 | mutex_lock(&graph_lock); |
2577 | 2640 | ||
2578 | if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) { | ||
2579 | ret = -EBUSY; | ||
2580 | goto out_unlock; | ||
2581 | } | ||
2582 | |||
2583 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { | 2641 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { |
2584 | ret = -ENOMEM; | 2642 | ret = -ENOMEM; |
2585 | goto out_unlock; | 2643 | goto out_unlock; |
@@ -2612,6 +2670,7 @@ static const struct file_operations ftrace_graph_fops = { | |||
2612 | .read = seq_read, | 2670 | .read = seq_read, |
2613 | .write = ftrace_graph_write, | 2671 | .write = ftrace_graph_write, |
2614 | .release = ftrace_graph_release, | 2672 | .release = ftrace_graph_release, |
2673 | .llseek = seq_lseek, | ||
2615 | }; | 2674 | }; |
2616 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 2675 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
2617 | 2676 | ||
@@ -3222,8 +3281,8 @@ free: | |||
3222 | } | 3281 | } |
3223 | 3282 | ||
3224 | static void | 3283 | static void |
3225 | ftrace_graph_probe_sched_switch(struct rq *__rq, struct task_struct *prev, | 3284 | ftrace_graph_probe_sched_switch(void *ignore, |
3226 | struct task_struct *next) | 3285 | struct task_struct *prev, struct task_struct *next) |
3227 | { | 3286 | { |
3228 | unsigned long long timestamp; | 3287 | unsigned long long timestamp; |
3229 | int index; | 3288 | int index; |
@@ -3277,7 +3336,7 @@ static int start_graph_tracing(void) | |||
3277 | } while (ret == -EAGAIN); | 3336 | } while (ret == -EAGAIN); |
3278 | 3337 | ||
3279 | if (!ret) { | 3338 | if (!ret) { |
3280 | ret = register_trace_sched_switch(ftrace_graph_probe_sched_switch); | 3339 | ret = register_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); |
3281 | if (ret) | 3340 | if (ret) |
3282 | pr_info("ftrace_graph: Couldn't activate tracepoint" | 3341 | pr_info("ftrace_graph: Couldn't activate tracepoint" |
3283 | " probe to kernel_sched_switch\n"); | 3342 | " probe to kernel_sched_switch\n"); |
@@ -3349,11 +3408,11 @@ void unregister_ftrace_graph(void) | |||
3349 | goto out; | 3408 | goto out; |
3350 | 3409 | ||
3351 | ftrace_graph_active--; | 3410 | ftrace_graph_active--; |
3352 | unregister_trace_sched_switch(ftrace_graph_probe_sched_switch); | ||
3353 | ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; | 3411 | ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; |
3354 | ftrace_graph_entry = ftrace_graph_entry_stub; | 3412 | ftrace_graph_entry = ftrace_graph_entry_stub; |
3355 | ftrace_shutdown(FTRACE_STOP_FUNC_RET); | 3413 | ftrace_shutdown(FTRACE_STOP_FUNC_RET); |
3356 | unregister_pm_notifier(&ftrace_suspend_notifier); | 3414 | unregister_pm_notifier(&ftrace_suspend_notifier); |
3415 | unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); | ||
3357 | 3416 | ||
3358 | out: | 3417 | out: |
3359 | mutex_unlock(&ftrace_lock); | 3418 | mutex_unlock(&ftrace_lock); |
@@ -3364,6 +3423,7 @@ void ftrace_graph_init_task(struct task_struct *t) | |||
3364 | { | 3423 | { |
3365 | /* Make sure we do not use the parent ret_stack */ | 3424 | /* Make sure we do not use the parent ret_stack */ |
3366 | t->ret_stack = NULL; | 3425 | t->ret_stack = NULL; |
3426 | t->curr_ret_stack = -1; | ||
3367 | 3427 | ||
3368 | if (ftrace_graph_active) { | 3428 | if (ftrace_graph_active) { |
3369 | struct ftrace_ret_stack *ret_stack; | 3429 | struct ftrace_ret_stack *ret_stack; |
@@ -3373,7 +3433,6 @@ void ftrace_graph_init_task(struct task_struct *t) | |||
3373 | GFP_KERNEL); | 3433 | GFP_KERNEL); |
3374 | if (!ret_stack) | 3434 | if (!ret_stack) |
3375 | return; | 3435 | return; |
3376 | t->curr_ret_stack = -1; | ||
3377 | atomic_set(&t->tracing_graph_pause, 0); | 3436 | atomic_set(&t->tracing_graph_pause, 0); |
3378 | atomic_set(&t->trace_overrun, 0); | 3437 | atomic_set(&t->trace_overrun, 0); |
3379 | t->ftrace_timestamp = 0; | 3438 | t->ftrace_timestamp = 0; |