diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1e6640f80454..d996353473fd 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -2426,6 +2426,7 @@ static const struct file_operations ftrace_notrace_fops = { | |||
2426 | static DEFINE_MUTEX(graph_lock); | 2426 | static DEFINE_MUTEX(graph_lock); |
2427 | 2427 | ||
2428 | int ftrace_graph_count; | 2428 | int ftrace_graph_count; |
2429 | int ftrace_graph_filter_enabled; | ||
2429 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | 2430 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; |
2430 | 2431 | ||
2431 | static void * | 2432 | static void * |
@@ -2448,7 +2449,7 @@ static void *g_start(struct seq_file *m, loff_t *pos) | |||
2448 | mutex_lock(&graph_lock); | 2449 | mutex_lock(&graph_lock); |
2449 | 2450 | ||
2450 | /* Nothing, tell g_show to print all functions are enabled */ | 2451 | /* Nothing, tell g_show to print all functions are enabled */ |
2451 | if (!ftrace_graph_count && !*pos) | 2452 | if (!ftrace_graph_filter_enabled && !*pos) |
2452 | return (void *)1; | 2453 | return (void *)1; |
2453 | 2454 | ||
2454 | return __g_next(m, pos); | 2455 | return __g_next(m, pos); |
@@ -2494,6 +2495,7 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
2494 | mutex_lock(&graph_lock); | 2495 | mutex_lock(&graph_lock); |
2495 | if ((file->f_mode & FMODE_WRITE) && | 2496 | if ((file->f_mode & FMODE_WRITE) && |
2496 | (file->f_flags & O_TRUNC)) { | 2497 | (file->f_flags & O_TRUNC)) { |
2498 | ftrace_graph_filter_enabled = 0; | ||
2497 | ftrace_graph_count = 0; | 2499 | ftrace_graph_count = 0; |
2498 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | 2500 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); |
2499 | } | 2501 | } |
@@ -2519,7 +2521,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2519 | struct dyn_ftrace *rec; | 2521 | struct dyn_ftrace *rec; |
2520 | struct ftrace_page *pg; | 2522 | struct ftrace_page *pg; |
2521 | int search_len; | 2523 | int search_len; |
2522 | int found = 0; | 2524 | int fail = 1; |
2523 | int type, not; | 2525 | int type, not; |
2524 | char *search; | 2526 | char *search; |
2525 | bool exists; | 2527 | bool exists; |
@@ -2530,37 +2532,51 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2530 | 2532 | ||
2531 | /* decode regex */ | 2533 | /* decode regex */ |
2532 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); | 2534 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
2533 | if (not) | 2535 | if (!not && *idx >= FTRACE_GRAPH_MAX_FUNCS) |
2534 | return -EINVAL; | 2536 | return -EBUSY; |
2535 | 2537 | ||
2536 | search_len = strlen(search); | 2538 | search_len = strlen(search); |
2537 | 2539 | ||
2538 | mutex_lock(&ftrace_lock); | 2540 | mutex_lock(&ftrace_lock); |
2539 | do_for_each_ftrace_rec(pg, rec) { | 2541 | do_for_each_ftrace_rec(pg, rec) { |
2540 | 2542 | ||
2541 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | ||
2542 | break; | ||
2543 | |||
2544 | if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) | 2543 | if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) |
2545 | continue; | 2544 | continue; |
2546 | 2545 | ||
2547 | if (ftrace_match_record(rec, search, search_len, type)) { | 2546 | if (ftrace_match_record(rec, search, search_len, type)) { |
2548 | /* ensure it is not already in the array */ | 2547 | /* if it is in the array */ |
2549 | exists = false; | 2548 | exists = false; |
2550 | for (i = 0; i < *idx; i++) | 2549 | for (i = 0; i < *idx; i++) { |
2551 | if (array[i] == rec->ip) { | 2550 | if (array[i] == rec->ip) { |
2552 | exists = true; | 2551 | exists = true; |
2553 | break; | 2552 | break; |
2554 | } | 2553 | } |
2555 | if (!exists) | 2554 | } |
2556 | array[(*idx)++] = rec->ip; | 2555 | |
2557 | found = 1; | 2556 | if (!not) { |
2557 | fail = 0; | ||
2558 | if (!exists) { | ||
2559 | array[(*idx)++] = rec->ip; | ||
2560 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | ||
2561 | goto out; | ||
2562 | } | ||
2563 | } else { | ||
2564 | if (exists) { | ||
2565 | array[i] = array[--(*idx)]; | ||
2566 | array[*idx] = 0; | ||
2567 | fail = 0; | ||
2568 | } | ||
2569 | } | ||
2558 | } | 2570 | } |
2559 | } while_for_each_ftrace_rec(); | 2571 | } while_for_each_ftrace_rec(); |
2560 | 2572 | out: | |
2561 | mutex_unlock(&ftrace_lock); | 2573 | mutex_unlock(&ftrace_lock); |
2562 | 2574 | ||
2563 | return found ? 0 : -EINVAL; | 2575 | if (fail) |
2576 | return -EINVAL; | ||
2577 | |||
2578 | ftrace_graph_filter_enabled = 1; | ||
2579 | return 0; | ||
2564 | } | 2580 | } |
2565 | 2581 | ||
2566 | static ssize_t | 2582 | static ssize_t |
@@ -2570,16 +2586,11 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
2570 | struct trace_parser parser; | 2586 | struct trace_parser parser; |
2571 | ssize_t read, ret; | 2587 | ssize_t read, ret; |
2572 | 2588 | ||
2573 | if (!cnt || cnt < 0) | 2589 | if (!cnt) |
2574 | return 0; | 2590 | return 0; |
2575 | 2591 | ||
2576 | mutex_lock(&graph_lock); | 2592 | mutex_lock(&graph_lock); |
2577 | 2593 | ||
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)) { | 2594 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { |
2584 | ret = -ENOMEM; | 2595 | ret = -ENOMEM; |
2585 | goto out_unlock; | 2596 | goto out_unlock; |