diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 101 |
1 files changed, 61 insertions, 40 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 3718d55fb4c3..25edd5cc5935 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -291,7 +291,9 @@ function_stat_next(void *v, int idx) | |||
291 | pg = (struct ftrace_profile_page *)((unsigned long)rec & PAGE_MASK); | 291 | pg = (struct ftrace_profile_page *)((unsigned long)rec & PAGE_MASK); |
292 | 292 | ||
293 | again: | 293 | again: |
294 | rec++; | 294 | if (idx != 0) |
295 | rec++; | ||
296 | |||
295 | if ((void *)rec >= (void *)&pg->records[pg->index]) { | 297 | if ((void *)rec >= (void *)&pg->records[pg->index]) { |
296 | pg = pg->next; | 298 | pg = pg->next; |
297 | if (!pg) | 299 | if (!pg) |
@@ -766,7 +768,7 @@ static struct tracer_stat function_stats __initdata = { | |||
766 | .stat_show = function_stat_show | 768 | .stat_show = function_stat_show |
767 | }; | 769 | }; |
768 | 770 | ||
769 | static void ftrace_profile_debugfs(struct dentry *d_tracer) | 771 | static __init void ftrace_profile_debugfs(struct dentry *d_tracer) |
770 | { | 772 | { |
771 | struct ftrace_profile_stat *stat; | 773 | struct ftrace_profile_stat *stat; |
772 | struct dentry *entry; | 774 | struct dentry *entry; |
@@ -784,7 +786,6 @@ static void ftrace_profile_debugfs(struct dentry *d_tracer) | |||
784 | * The files created are permanent, if something happens | 786 | * The files created are permanent, if something happens |
785 | * we still do not free memory. | 787 | * we still do not free memory. |
786 | */ | 788 | */ |
787 | kfree(stat); | ||
788 | WARN(1, | 789 | WARN(1, |
789 | "Could not allocate stat file for cpu %d\n", | 790 | "Could not allocate stat file for cpu %d\n", |
790 | cpu); | 791 | cpu); |
@@ -811,7 +812,7 @@ static void ftrace_profile_debugfs(struct dentry *d_tracer) | |||
811 | } | 812 | } |
812 | 813 | ||
813 | #else /* CONFIG_FUNCTION_PROFILER */ | 814 | #else /* CONFIG_FUNCTION_PROFILER */ |
814 | static void ftrace_profile_debugfs(struct dentry *d_tracer) | 815 | static __init void ftrace_profile_debugfs(struct dentry *d_tracer) |
815 | { | 816 | { |
816 | } | 817 | } |
817 | #endif /* CONFIG_FUNCTION_PROFILER */ | 818 | #endif /* CONFIG_FUNCTION_PROFILER */ |
@@ -1417,10 +1418,20 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) | |||
1417 | { | 1418 | { |
1418 | struct ftrace_iterator *iter = m->private; | 1419 | struct ftrace_iterator *iter = m->private; |
1419 | void *p = NULL; | 1420 | void *p = NULL; |
1421 | loff_t l; | ||
1422 | |||
1423 | if (!(iter->flags & FTRACE_ITER_HASH)) | ||
1424 | *pos = 0; | ||
1420 | 1425 | ||
1421 | iter->flags |= FTRACE_ITER_HASH; | 1426 | iter->flags |= FTRACE_ITER_HASH; |
1422 | 1427 | ||
1423 | return t_hash_next(m, p, pos); | 1428 | iter->hidx = 0; |
1429 | for (l = 0; l <= *pos; ) { | ||
1430 | p = t_hash_next(m, p, &l); | ||
1431 | if (!p) | ||
1432 | break; | ||
1433 | } | ||
1434 | return p; | ||
1424 | } | 1435 | } |
1425 | 1436 | ||
1426 | static int t_hash_show(struct seq_file *m, void *v) | 1437 | static int t_hash_show(struct seq_file *m, void *v) |
@@ -1467,8 +1478,6 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1467 | iter->pg = iter->pg->next; | 1478 | iter->pg = iter->pg->next; |
1468 | iter->idx = 0; | 1479 | iter->idx = 0; |
1469 | goto retry; | 1480 | goto retry; |
1470 | } else { | ||
1471 | iter->idx = -1; | ||
1472 | } | 1481 | } |
1473 | } else { | 1482 | } else { |
1474 | rec = &iter->pg->records[iter->idx++]; | 1483 | rec = &iter->pg->records[iter->idx++]; |
@@ -1497,6 +1506,7 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1497 | { | 1506 | { |
1498 | struct ftrace_iterator *iter = m->private; | 1507 | struct ftrace_iterator *iter = m->private; |
1499 | void *p = NULL; | 1508 | void *p = NULL; |
1509 | loff_t l; | ||
1500 | 1510 | ||
1501 | mutex_lock(&ftrace_lock); | 1511 | mutex_lock(&ftrace_lock); |
1502 | /* | 1512 | /* |
@@ -1508,23 +1518,21 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1508 | if (*pos > 0) | 1518 | if (*pos > 0) |
1509 | return t_hash_start(m, pos); | 1519 | return t_hash_start(m, pos); |
1510 | iter->flags |= FTRACE_ITER_PRINTALL; | 1520 | iter->flags |= FTRACE_ITER_PRINTALL; |
1511 | (*pos)++; | ||
1512 | return iter; | 1521 | return iter; |
1513 | } | 1522 | } |
1514 | 1523 | ||
1515 | if (iter->flags & FTRACE_ITER_HASH) | 1524 | if (iter->flags & FTRACE_ITER_HASH) |
1516 | return t_hash_start(m, pos); | 1525 | return t_hash_start(m, pos); |
1517 | 1526 | ||
1518 | if (*pos > 0) { | 1527 | iter->pg = ftrace_pages_start; |
1519 | if (iter->idx < 0) | 1528 | iter->idx = 0; |
1520 | return p; | 1529 | for (l = 0; l <= *pos; ) { |
1521 | (*pos)--; | 1530 | p = t_next(m, p, &l); |
1522 | iter->idx--; | 1531 | if (!p) |
1532 | break; | ||
1523 | } | 1533 | } |
1524 | 1534 | ||
1525 | p = t_next(m, p, pos); | 1535 | if (!p && iter->flags & FTRACE_ITER_FILTER) |
1526 | |||
1527 | if (!p) | ||
1528 | return t_hash_start(m, pos); | 1536 | return t_hash_start(m, pos); |
1529 | 1537 | ||
1530 | return p; | 1538 | return p; |
@@ -1654,7 +1662,7 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable) | |||
1654 | 1662 | ||
1655 | mutex_lock(&ftrace_regex_lock); | 1663 | mutex_lock(&ftrace_regex_lock); |
1656 | if ((file->f_mode & FMODE_WRITE) && | 1664 | if ((file->f_mode & FMODE_WRITE) && |
1657 | !(file->f_flags & O_APPEND)) | 1665 | (file->f_flags & O_TRUNC)) |
1658 | ftrace_filter_reset(enable); | 1666 | ftrace_filter_reset(enable); |
1659 | 1667 | ||
1660 | if (file->f_mode & FMODE_READ) { | 1668 | if (file->f_mode & FMODE_READ) { |
@@ -2270,7 +2278,11 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
2270 | read++; | 2278 | read++; |
2271 | cnt--; | 2279 | cnt--; |
2272 | 2280 | ||
2273 | if (!(iter->flags & ~FTRACE_ITER_CONT)) { | 2281 | /* |
2282 | * If the parser haven't finished with the last write, | ||
2283 | * continue reading the user input without skipping spaces. | ||
2284 | */ | ||
2285 | if (!(iter->flags & FTRACE_ITER_CONT)) { | ||
2274 | /* skip white space */ | 2286 | /* skip white space */ |
2275 | while (cnt && isspace(ch)) { | 2287 | while (cnt && isspace(ch)) { |
2276 | ret = get_user(ch, ubuf++); | 2288 | ret = get_user(ch, ubuf++); |
@@ -2280,8 +2292,9 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
2280 | cnt--; | 2292 | cnt--; |
2281 | } | 2293 | } |
2282 | 2294 | ||
2295 | /* only spaces were written */ | ||
2283 | if (isspace(ch)) { | 2296 | if (isspace(ch)) { |
2284 | file->f_pos += read; | 2297 | *ppos += read; |
2285 | ret = read; | 2298 | ret = read; |
2286 | goto out; | 2299 | goto out; |
2287 | } | 2300 | } |
@@ -2311,12 +2324,12 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
2311 | if (ret) | 2324 | if (ret) |
2312 | goto out; | 2325 | goto out; |
2313 | iter->buffer_idx = 0; | 2326 | iter->buffer_idx = 0; |
2314 | } else | 2327 | } else { |
2315 | iter->flags |= FTRACE_ITER_CONT; | 2328 | iter->flags |= FTRACE_ITER_CONT; |
2329 | iter->buffer[iter->buffer_idx++] = ch; | ||
2330 | } | ||
2316 | 2331 | ||
2317 | 2332 | *ppos += read; | |
2318 | file->f_pos += read; | ||
2319 | |||
2320 | ret = read; | 2333 | ret = read; |
2321 | out: | 2334 | out: |
2322 | mutex_unlock(&ftrace_regex_lock); | 2335 | mutex_unlock(&ftrace_regex_lock); |
@@ -2500,32 +2513,31 @@ int ftrace_graph_count; | |||
2500 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | 2513 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; |
2501 | 2514 | ||
2502 | static void * | 2515 | static void * |
2503 | g_next(struct seq_file *m, void *v, loff_t *pos) | 2516 | __g_next(struct seq_file *m, loff_t *pos) |
2504 | { | 2517 | { |
2505 | unsigned long *array = m->private; | 2518 | unsigned long *array = m->private; |
2506 | int index = *pos; | ||
2507 | 2519 | ||
2508 | (*pos)++; | 2520 | if (*pos >= ftrace_graph_count) |
2509 | |||
2510 | if (index >= ftrace_graph_count) | ||
2511 | return NULL; | 2521 | return NULL; |
2522 | return &array[*pos]; | ||
2523 | } | ||
2512 | 2524 | ||
2513 | return &array[index]; | 2525 | static void * |
2526 | g_next(struct seq_file *m, void *v, loff_t *pos) | ||
2527 | { | ||
2528 | (*pos)++; | ||
2529 | return __g_next(m, pos); | ||
2514 | } | 2530 | } |
2515 | 2531 | ||
2516 | static void *g_start(struct seq_file *m, loff_t *pos) | 2532 | static void *g_start(struct seq_file *m, loff_t *pos) |
2517 | { | 2533 | { |
2518 | void *p = NULL; | ||
2519 | |||
2520 | mutex_lock(&graph_lock); | 2534 | mutex_lock(&graph_lock); |
2521 | 2535 | ||
2522 | /* Nothing, tell g_show to print all functions are enabled */ | 2536 | /* Nothing, tell g_show to print all functions are enabled */ |
2523 | if (!ftrace_graph_count && !*pos) | 2537 | if (!ftrace_graph_count && !*pos) |
2524 | return (void *)1; | 2538 | return (void *)1; |
2525 | 2539 | ||
2526 | p = g_next(m, p, pos); | 2540 | return __g_next(m, pos); |
2527 | |||
2528 | return p; | ||
2529 | } | 2541 | } |
2530 | 2542 | ||
2531 | static void g_stop(struct seq_file *m, void *p) | 2543 | static void g_stop(struct seq_file *m, void *p) |
@@ -2570,7 +2582,7 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
2570 | 2582 | ||
2571 | mutex_lock(&graph_lock); | 2583 | mutex_lock(&graph_lock); |
2572 | if ((file->f_mode & FMODE_WRITE) && | 2584 | if ((file->f_mode & FMODE_WRITE) && |
2573 | !(file->f_flags & O_APPEND)) { | 2585 | (file->f_flags & O_TRUNC)) { |
2574 | ftrace_graph_count = 0; | 2586 | ftrace_graph_count = 0; |
2575 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | 2587 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); |
2576 | } | 2588 | } |
@@ -2589,6 +2601,14 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
2589 | } | 2601 | } |
2590 | 2602 | ||
2591 | static int | 2603 | static int |
2604 | ftrace_graph_release(struct inode *inode, struct file *file) | ||
2605 | { | ||
2606 | if (file->f_mode & FMODE_READ) | ||
2607 | seq_release(inode, file); | ||
2608 | return 0; | ||
2609 | } | ||
2610 | |||
2611 | static int | ||
2592 | ftrace_set_func(unsigned long *array, int *idx, char *buffer) | 2612 | ftrace_set_func(unsigned long *array, int *idx, char *buffer) |
2593 | { | 2613 | { |
2594 | struct dyn_ftrace *rec; | 2614 | struct dyn_ftrace *rec; |
@@ -2717,9 +2737,10 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
2717 | } | 2737 | } |
2718 | 2738 | ||
2719 | static const struct file_operations ftrace_graph_fops = { | 2739 | static const struct file_operations ftrace_graph_fops = { |
2720 | .open = ftrace_graph_open, | 2740 | .open = ftrace_graph_open, |
2721 | .read = seq_read, | 2741 | .read = seq_read, |
2722 | .write = ftrace_graph_write, | 2742 | .write = ftrace_graph_write, |
2743 | .release = ftrace_graph_release, | ||
2723 | }; | 2744 | }; |
2724 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 2745 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
2725 | 2746 | ||
@@ -3152,10 +3173,10 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, | |||
3152 | 3173 | ||
3153 | ret = proc_dointvec(table, write, file, buffer, lenp, ppos); | 3174 | ret = proc_dointvec(table, write, file, buffer, lenp, ppos); |
3154 | 3175 | ||
3155 | if (ret || !write || (last_ftrace_enabled == ftrace_enabled)) | 3176 | if (ret || !write || (last_ftrace_enabled == !!ftrace_enabled)) |
3156 | goto out; | 3177 | goto out; |
3157 | 3178 | ||
3158 | last_ftrace_enabled = ftrace_enabled; | 3179 | last_ftrace_enabled = !!ftrace_enabled; |
3159 | 3180 | ||
3160 | if (ftrace_enabled) { | 3181 | if (ftrace_enabled) { |
3161 | 3182 | ||