|
@@ -2426,6 +2426,7 @@ static const struct file_operations ftrace_notrace_fops = {
|
|
|
static DEFINE_MUTEX(graph_lock);
|
|
|
|
|
|
int ftrace_graph_count;
|
|
|
+int ftrace_graph_filter_enabled;
|
|
|
unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly;
|
|
|
|
|
|
static void *
|
|
@@ -2448,7 +2449,7 @@ static void *g_start(struct seq_file *m, loff_t *pos)
|
|
|
mutex_lock(&graph_lock);
|
|
|
|
|
|
/* Nothing, tell g_show to print all functions are enabled */
|
|
|
- if (!ftrace_graph_count && !*pos)
|
|
|
+ if (!ftrace_graph_filter_enabled && !*pos)
|
|
|
return (void *)1;
|
|
|
|
|
|
return __g_next(m, pos);
|
|
@@ -2494,6 +2495,7 @@ ftrace_graph_open(struct inode *inode, struct file *file)
|
|
|
mutex_lock(&graph_lock);
|
|
|
if ((file->f_mode & FMODE_WRITE) &&
|
|
|
(file->f_flags & O_TRUNC)) {
|
|
|
+ ftrace_graph_filter_enabled = 0;
|
|
|
ftrace_graph_count = 0;
|
|
|
memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs));
|
|
|
}
|
|
@@ -2519,7 +2521,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer)
|
|
|
struct dyn_ftrace *rec;
|
|
|
struct ftrace_page *pg;
|
|
|
int search_len;
|
|
|
- int found = 0;
|
|
|
+ int fail = 1;
|
|
|
int type, not;
|
|
|
char *search;
|
|
|
bool exists;
|
|
@@ -2530,37 +2532,51 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer)
|
|
|
|
|
|
/* decode regex */
|
|
|
type = filter_parse_regex(buffer, strlen(buffer), &search, ¬);
|
|
|
- if (not)
|
|
|
- return -EINVAL;
|
|
|
+ if (!not && *idx >= FTRACE_GRAPH_MAX_FUNCS)
|
|
|
+ return -EBUSY;
|
|
|
|
|
|
search_len = strlen(search);
|
|
|
|
|
|
mutex_lock(&ftrace_lock);
|
|
|
do_for_each_ftrace_rec(pg, rec) {
|
|
|
|
|
|
- if (*idx >= FTRACE_GRAPH_MAX_FUNCS)
|
|
|
- break;
|
|
|
-
|
|
|
if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE))
|
|
|
continue;
|
|
|
|
|
|
if (ftrace_match_record(rec, search, search_len, type)) {
|
|
|
- /* ensure it is not already in the array */
|
|
|
+ /* if it is in the array */
|
|
|
exists = false;
|
|
|
- for (i = 0; i < *idx; i++)
|
|
|
+ for (i = 0; i < *idx; i++) {
|
|
|
if (array[i] == rec->ip) {
|
|
|
exists = true;
|
|
|
break;
|
|
|
}
|
|
|
- if (!exists)
|
|
|
- array[(*idx)++] = rec->ip;
|
|
|
- found = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!not) {
|
|
|
+ fail = 0;
|
|
|
+ if (!exists) {
|
|
|
+ array[(*idx)++] = rec->ip;
|
|
|
+ if (*idx >= FTRACE_GRAPH_MAX_FUNCS)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (exists) {
|
|
|
+ array[i] = array[--(*idx)];
|
|
|
+ array[*idx] = 0;
|
|
|
+ fail = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
} while_for_each_ftrace_rec();
|
|
|
-
|
|
|
+out:
|
|
|
mutex_unlock(&ftrace_lock);
|
|
|
|
|
|
- return found ? 0 : -EINVAL;
|
|
|
+ if (fail)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ftrace_graph_filter_enabled = 1;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static ssize_t
|
|
@@ -2570,16 +2586,11 @@ ftrace_graph_write(struct file *file, const char __user *ubuf,
|
|
|
struct trace_parser parser;
|
|
|
ssize_t read, ret;
|
|
|
|
|
|
- if (!cnt || cnt < 0)
|
|
|
+ if (!cnt)
|
|
|
return 0;
|
|
|
|
|
|
mutex_lock(&graph_lock);
|
|
|
|
|
|
- if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) {
|
|
|
- ret = -EBUSY;
|
|
|
- goto out_unlock;
|
|
|
- }
|
|
|
-
|
|
|
if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) {
|
|
|
ret = -ENOMEM;
|
|
|
goto out_unlock;
|