diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
| -rw-r--r-- | kernel/trace/ftrace.c | 307 |
1 files changed, 82 insertions, 225 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 25edd5cc5935..46592feab5a6 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -1016,71 +1016,35 @@ static int | |||
| 1016 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | 1016 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) |
| 1017 | { | 1017 | { |
| 1018 | unsigned long ftrace_addr; | 1018 | unsigned long ftrace_addr; |
| 1019 | unsigned long ip, fl; | 1019 | unsigned long flag = 0UL; |
| 1020 | 1020 | ||
| 1021 | ftrace_addr = (unsigned long)FTRACE_ADDR; | 1021 | ftrace_addr = (unsigned long)FTRACE_ADDR; |
| 1022 | 1022 | ||
| 1023 | ip = rec->ip; | ||
| 1024 | |||
| 1025 | /* | 1023 | /* |
| 1026 | * If this record is not to be traced and | 1024 | * If this record is not to be traced or we want to disable it, |
| 1027 | * it is not enabled then do nothing. | 1025 | * then disable it. |
| 1028 | * | 1026 | * |
| 1029 | * If this record is not to be traced and | 1027 | * If we want to enable it and filtering is off, then enable it. |
| 1030 | * it is enabled then disable it. | ||
| 1031 | * | 1028 | * |
| 1029 | * If we want to enable it and filtering is on, enable it only if | ||
| 1030 | * it's filtered | ||
| 1032 | */ | 1031 | */ |
| 1033 | if (rec->flags & FTRACE_FL_NOTRACE) { | 1032 | if (enable && !(rec->flags & FTRACE_FL_NOTRACE)) { |
| 1034 | if (rec->flags & FTRACE_FL_ENABLED) | 1033 | if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER)) |
| 1035 | rec->flags &= ~FTRACE_FL_ENABLED; | 1034 | flag = FTRACE_FL_ENABLED; |
| 1036 | else | 1035 | } |
| 1037 | return 0; | ||
| 1038 | |||
| 1039 | } else if (ftrace_filtered && enable) { | ||
| 1040 | /* | ||
| 1041 | * Filtering is on: | ||
| 1042 | */ | ||
| 1043 | |||
| 1044 | fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED); | ||
| 1045 | |||
| 1046 | /* Record is filtered and enabled, do nothing */ | ||
| 1047 | if (fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) | ||
| 1048 | return 0; | ||
| 1049 | |||
| 1050 | /* Record is not filtered or enabled, do nothing */ | ||
| 1051 | if (!fl) | ||
| 1052 | return 0; | ||
| 1053 | |||
| 1054 | /* Record is not filtered but enabled, disable it */ | ||
| 1055 | if (fl == FTRACE_FL_ENABLED) | ||
| 1056 | rec->flags &= ~FTRACE_FL_ENABLED; | ||
| 1057 | else | ||
| 1058 | /* Otherwise record is filtered but not enabled, enable it */ | ||
| 1059 | rec->flags |= FTRACE_FL_ENABLED; | ||
| 1060 | } else { | ||
| 1061 | /* Disable or not filtered */ | ||
| 1062 | |||
| 1063 | if (enable) { | ||
| 1064 | /* if record is enabled, do nothing */ | ||
| 1065 | if (rec->flags & FTRACE_FL_ENABLED) | ||
| 1066 | return 0; | ||
| 1067 | |||
| 1068 | rec->flags |= FTRACE_FL_ENABLED; | ||
| 1069 | |||
| 1070 | } else { | ||
| 1071 | 1036 | ||
| 1072 | /* if record is not enabled, do nothing */ | 1037 | /* If the state of this record hasn't changed, then do nothing */ |
| 1073 | if (!(rec->flags & FTRACE_FL_ENABLED)) | 1038 | if ((rec->flags & FTRACE_FL_ENABLED) == flag) |
| 1074 | return 0; | 1039 | return 0; |
| 1075 | 1040 | ||
| 1076 | rec->flags &= ~FTRACE_FL_ENABLED; | 1041 | if (flag) { |
| 1077 | } | 1042 | rec->flags |= FTRACE_FL_ENABLED; |
| 1043 | return ftrace_make_call(rec, ftrace_addr); | ||
| 1078 | } | 1044 | } |
| 1079 | 1045 | ||
| 1080 | if (rec->flags & FTRACE_FL_ENABLED) | 1046 | rec->flags &= ~FTRACE_FL_ENABLED; |
| 1081 | return ftrace_make_call(rec, ftrace_addr); | 1047 | return ftrace_make_nop(NULL, rec, ftrace_addr); |
| 1082 | else | ||
| 1083 | return ftrace_make_nop(NULL, rec, ftrace_addr); | ||
| 1084 | } | 1048 | } |
| 1085 | 1049 | ||
| 1086 | static void ftrace_replace_code(int enable) | 1050 | static void ftrace_replace_code(int enable) |
| @@ -1359,11 +1323,10 @@ static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) | |||
| 1359 | 1323 | ||
| 1360 | enum { | 1324 | enum { |
| 1361 | FTRACE_ITER_FILTER = (1 << 0), | 1325 | FTRACE_ITER_FILTER = (1 << 0), |
| 1362 | FTRACE_ITER_CONT = (1 << 1), | 1326 | FTRACE_ITER_NOTRACE = (1 << 1), |
| 1363 | FTRACE_ITER_NOTRACE = (1 << 2), | 1327 | FTRACE_ITER_FAILURES = (1 << 2), |
| 1364 | FTRACE_ITER_FAILURES = (1 << 3), | 1328 | FTRACE_ITER_PRINTALL = (1 << 3), |
| 1365 | FTRACE_ITER_PRINTALL = (1 << 4), | 1329 | FTRACE_ITER_HASH = (1 << 4), |
| 1366 | FTRACE_ITER_HASH = (1 << 5), | ||
| 1367 | }; | 1330 | }; |
| 1368 | 1331 | ||
| 1369 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1332 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
| @@ -1373,9 +1336,7 @@ struct ftrace_iterator { | |||
| 1373 | int hidx; | 1336 | int hidx; |
| 1374 | int idx; | 1337 | int idx; |
| 1375 | unsigned flags; | 1338 | unsigned flags; |
| 1376 | unsigned char buffer[FTRACE_BUFF_MAX+1]; | 1339 | struct trace_parser parser; |
| 1377 | unsigned buffer_idx; | ||
| 1378 | unsigned filtered; | ||
| 1379 | }; | 1340 | }; |
| 1380 | 1341 | ||
| 1381 | static void * | 1342 | static void * |
| @@ -1438,18 +1399,13 @@ static int t_hash_show(struct seq_file *m, void *v) | |||
| 1438 | { | 1399 | { |
| 1439 | struct ftrace_func_probe *rec; | 1400 | struct ftrace_func_probe *rec; |
| 1440 | struct hlist_node *hnd = v; | 1401 | struct hlist_node *hnd = v; |
| 1441 | char str[KSYM_SYMBOL_LEN]; | ||
| 1442 | 1402 | ||
| 1443 | rec = hlist_entry(hnd, struct ftrace_func_probe, node); | 1403 | rec = hlist_entry(hnd, struct ftrace_func_probe, node); |
| 1444 | 1404 | ||
| 1445 | if (rec->ops->print) | 1405 | if (rec->ops->print) |
| 1446 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); | 1406 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); |
| 1447 | 1407 | ||
| 1448 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | 1408 | seq_printf(m, "%ps:%ps", (void *)rec->ip, (void *)rec->ops->func); |
| 1449 | seq_printf(m, "%s:", str); | ||
| 1450 | |||
| 1451 | kallsyms_lookup((unsigned long)rec->ops->func, NULL, NULL, NULL, str); | ||
| 1452 | seq_printf(m, "%s", str); | ||
| 1453 | 1409 | ||
| 1454 | if (rec->data) | 1410 | if (rec->data) |
| 1455 | seq_printf(m, ":%p", rec->data); | 1411 | seq_printf(m, ":%p", rec->data); |
| @@ -1547,7 +1503,6 @@ static int t_show(struct seq_file *m, void *v) | |||
| 1547 | { | 1503 | { |
| 1548 | struct ftrace_iterator *iter = m->private; | 1504 | struct ftrace_iterator *iter = m->private; |
| 1549 | struct dyn_ftrace *rec = v; | 1505 | struct dyn_ftrace *rec = v; |
| 1550 | char str[KSYM_SYMBOL_LEN]; | ||
| 1551 | 1506 | ||
| 1552 | if (iter->flags & FTRACE_ITER_HASH) | 1507 | if (iter->flags & FTRACE_ITER_HASH) |
| 1553 | return t_hash_show(m, v); | 1508 | return t_hash_show(m, v); |
| @@ -1560,14 +1515,12 @@ static int t_show(struct seq_file *m, void *v) | |||
| 1560 | if (!rec) | 1515 | if (!rec) |
| 1561 | return 0; | 1516 | return 0; |
| 1562 | 1517 | ||
| 1563 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | 1518 | seq_printf(m, "%ps\n", (void *)rec->ip); |
| 1564 | |||
| 1565 | seq_printf(m, "%s\n", str); | ||
| 1566 | 1519 | ||
| 1567 | return 0; | 1520 | return 0; |
| 1568 | } | 1521 | } |
| 1569 | 1522 | ||
| 1570 | static struct seq_operations show_ftrace_seq_ops = { | 1523 | static const struct seq_operations show_ftrace_seq_ops = { |
| 1571 | .start = t_start, | 1524 | .start = t_start, |
| 1572 | .next = t_next, | 1525 | .next = t_next, |
| 1573 | .stop = t_stop, | 1526 | .stop = t_stop, |
| @@ -1601,17 +1554,6 @@ ftrace_avail_open(struct inode *inode, struct file *file) | |||
| 1601 | return ret; | 1554 | return ret; |
| 1602 | } | 1555 | } |
| 1603 | 1556 | ||
| 1604 | int ftrace_avail_release(struct inode *inode, struct file *file) | ||
| 1605 | { | ||
| 1606 | struct seq_file *m = (struct seq_file *)file->private_data; | ||
| 1607 | struct ftrace_iterator *iter = m->private; | ||
| 1608 | |||
| 1609 | seq_release(inode, file); | ||
| 1610 | kfree(iter); | ||
| 1611 | |||
| 1612 | return 0; | ||
| 1613 | } | ||
| 1614 | |||
| 1615 | static int | 1557 | static int |
| 1616 | ftrace_failures_open(struct inode *inode, struct file *file) | 1558 | ftrace_failures_open(struct inode *inode, struct file *file) |
| 1617 | { | 1559 | { |
| @@ -1660,6 +1602,11 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable) | |||
| 1660 | if (!iter) | 1602 | if (!iter) |
| 1661 | return -ENOMEM; | 1603 | return -ENOMEM; |
| 1662 | 1604 | ||
| 1605 | if (trace_parser_get_init(&iter->parser, FTRACE_BUFF_MAX)) { | ||
| 1606 | kfree(iter); | ||
| 1607 | return -ENOMEM; | ||
| 1608 | } | ||
| 1609 | |||
| 1663 | mutex_lock(&ftrace_regex_lock); | 1610 | mutex_lock(&ftrace_regex_lock); |
| 1664 | if ((file->f_mode & FMODE_WRITE) && | 1611 | if ((file->f_mode & FMODE_WRITE) && |
| 1665 | (file->f_flags & O_TRUNC)) | 1612 | (file->f_flags & O_TRUNC)) |
| @@ -1674,8 +1621,10 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable) | |||
| 1674 | if (!ret) { | 1621 | if (!ret) { |
| 1675 | struct seq_file *m = file->private_data; | 1622 | struct seq_file *m = file->private_data; |
| 1676 | m->private = iter; | 1623 | m->private = iter; |
| 1677 | } else | 1624 | } else { |
| 1625 | trace_parser_put(&iter->parser); | ||
| 1678 | kfree(iter); | 1626 | kfree(iter); |
| 1627 | } | ||
| 1679 | } else | 1628 | } else |
| 1680 | file->private_data = iter; | 1629 | file->private_data = iter; |
| 1681 | mutex_unlock(&ftrace_regex_lock); | 1630 | mutex_unlock(&ftrace_regex_lock); |
| @@ -2115,9 +2064,9 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
| 2115 | int i, len = 0; | 2064 | int i, len = 0; |
| 2116 | char *search; | 2065 | char *search; |
| 2117 | 2066 | ||
| 2118 | if (glob && (strcmp(glob, "*") || !strlen(glob))) | 2067 | if (glob && (strcmp(glob, "*") == 0 || !strlen(glob))) |
| 2119 | glob = NULL; | 2068 | glob = NULL; |
| 2120 | else { | 2069 | else if (glob) { |
| 2121 | int not; | 2070 | int not; |
| 2122 | 2071 | ||
| 2123 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 2072 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); |
| @@ -2252,11 +2201,10 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
| 2252 | size_t cnt, loff_t *ppos, int enable) | 2201 | size_t cnt, loff_t *ppos, int enable) |
| 2253 | { | 2202 | { |
| 2254 | struct ftrace_iterator *iter; | 2203 | struct ftrace_iterator *iter; |
| 2255 | char ch; | 2204 | struct trace_parser *parser; |
| 2256 | size_t read = 0; | 2205 | ssize_t ret, read; |
| 2257 | ssize_t ret; | ||
| 2258 | 2206 | ||
| 2259 | if (!cnt || cnt < 0) | 2207 | if (!cnt) |
| 2260 | return 0; | 2208 | return 0; |
| 2261 | 2209 | ||
| 2262 | mutex_lock(&ftrace_regex_lock); | 2210 | mutex_lock(&ftrace_regex_lock); |
| @@ -2267,73 +2215,23 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
| 2267 | } else | 2215 | } else |
| 2268 | iter = file->private_data; | 2216 | iter = file->private_data; |
| 2269 | 2217 | ||
| 2270 | if (!*ppos) { | 2218 | parser = &iter->parser; |
| 2271 | iter->flags &= ~FTRACE_ITER_CONT; | 2219 | read = trace_get_user(parser, ubuf, cnt, ppos); |
| 2272 | iter->buffer_idx = 0; | ||
| 2273 | } | ||
| 2274 | 2220 | ||
| 2275 | ret = get_user(ch, ubuf++); | 2221 | if (read >= 0 && trace_parser_loaded(parser) && |
| 2276 | if (ret) | 2222 | !trace_parser_cont(parser)) { |
| 2277 | goto out; | 2223 | ret = ftrace_process_regex(parser->buffer, |
| 2278 | read++; | 2224 | parser->idx, enable); |
| 2279 | cnt--; | ||
| 2280 | |||
| 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)) { | ||
| 2286 | /* skip white space */ | ||
| 2287 | while (cnt && isspace(ch)) { | ||
| 2288 | ret = get_user(ch, ubuf++); | ||
| 2289 | if (ret) | ||
| 2290 | goto out; | ||
| 2291 | read++; | ||
| 2292 | cnt--; | ||
| 2293 | } | ||
| 2294 | |||
| 2295 | /* only spaces were written */ | ||
| 2296 | if (isspace(ch)) { | ||
| 2297 | *ppos += read; | ||
| 2298 | ret = read; | ||
| 2299 | goto out; | ||
| 2300 | } | ||
| 2301 | |||
| 2302 | iter->buffer_idx = 0; | ||
| 2303 | } | ||
| 2304 | |||
| 2305 | while (cnt && !isspace(ch)) { | ||
| 2306 | if (iter->buffer_idx < FTRACE_BUFF_MAX) | ||
| 2307 | iter->buffer[iter->buffer_idx++] = ch; | ||
| 2308 | else { | ||
| 2309 | ret = -EINVAL; | ||
| 2310 | goto out; | ||
| 2311 | } | ||
| 2312 | ret = get_user(ch, ubuf++); | ||
| 2313 | if (ret) | 2225 | if (ret) |
| 2314 | goto out; | 2226 | goto out; |
| 2315 | read++; | ||
| 2316 | cnt--; | ||
| 2317 | } | ||
| 2318 | 2227 | ||
| 2319 | if (isspace(ch)) { | 2228 | trace_parser_clear(parser); |
| 2320 | iter->filtered++; | ||
| 2321 | iter->buffer[iter->buffer_idx] = 0; | ||
| 2322 | ret = ftrace_process_regex(iter->buffer, | ||
| 2323 | iter->buffer_idx, enable); | ||
| 2324 | if (ret) | ||
| 2325 | goto out; | ||
| 2326 | iter->buffer_idx = 0; | ||
| 2327 | } else { | ||
| 2328 | iter->flags |= FTRACE_ITER_CONT; | ||
| 2329 | iter->buffer[iter->buffer_idx++] = ch; | ||
| 2330 | } | 2229 | } |
| 2331 | 2230 | ||
| 2332 | *ppos += read; | ||
| 2333 | ret = read; | 2231 | ret = read; |
| 2334 | out: | ||
| 2335 | mutex_unlock(&ftrace_regex_lock); | ||
| 2336 | 2232 | ||
| 2233 | mutex_unlock(&ftrace_regex_lock); | ||
| 2234 | out: | ||
| 2337 | return ret; | 2235 | return ret; |
| 2338 | } | 2236 | } |
| 2339 | 2237 | ||
| @@ -2438,6 +2336,7 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
| 2438 | { | 2336 | { |
| 2439 | struct seq_file *m = (struct seq_file *)file->private_data; | 2337 | struct seq_file *m = (struct seq_file *)file->private_data; |
| 2440 | struct ftrace_iterator *iter; | 2338 | struct ftrace_iterator *iter; |
| 2339 | struct trace_parser *parser; | ||
| 2441 | 2340 | ||
| 2442 | mutex_lock(&ftrace_regex_lock); | 2341 | mutex_lock(&ftrace_regex_lock); |
| 2443 | if (file->f_mode & FMODE_READ) { | 2342 | if (file->f_mode & FMODE_READ) { |
| @@ -2447,10 +2346,10 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
| 2447 | } else | 2346 | } else |
| 2448 | iter = file->private_data; | 2347 | iter = file->private_data; |
| 2449 | 2348 | ||
| 2450 | if (iter->buffer_idx) { | 2349 | parser = &iter->parser; |
| 2451 | iter->filtered++; | 2350 | if (trace_parser_loaded(parser)) { |
| 2452 | iter->buffer[iter->buffer_idx] = 0; | 2351 | parser->buffer[parser->idx] = 0; |
| 2453 | ftrace_match_records(iter->buffer, iter->buffer_idx, enable); | 2352 | ftrace_match_records(parser->buffer, parser->idx, enable); |
| 2454 | } | 2353 | } |
| 2455 | 2354 | ||
| 2456 | mutex_lock(&ftrace_lock); | 2355 | mutex_lock(&ftrace_lock); |
| @@ -2458,7 +2357,9 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
| 2458 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); | 2357 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); |
| 2459 | mutex_unlock(&ftrace_lock); | 2358 | mutex_unlock(&ftrace_lock); |
| 2460 | 2359 | ||
| 2360 | trace_parser_put(parser); | ||
| 2461 | kfree(iter); | 2361 | kfree(iter); |
| 2362 | |||
| 2462 | mutex_unlock(&ftrace_regex_lock); | 2363 | mutex_unlock(&ftrace_regex_lock); |
| 2463 | return 0; | 2364 | return 0; |
| 2464 | } | 2365 | } |
| @@ -2479,14 +2380,14 @@ static const struct file_operations ftrace_avail_fops = { | |||
| 2479 | .open = ftrace_avail_open, | 2380 | .open = ftrace_avail_open, |
| 2480 | .read = seq_read, | 2381 | .read = seq_read, |
| 2481 | .llseek = seq_lseek, | 2382 | .llseek = seq_lseek, |
| 2482 | .release = ftrace_avail_release, | 2383 | .release = seq_release_private, |
| 2483 | }; | 2384 | }; |
| 2484 | 2385 | ||
| 2485 | static const struct file_operations ftrace_failures_fops = { | 2386 | static const struct file_operations ftrace_failures_fops = { |
| 2486 | .open = ftrace_failures_open, | 2387 | .open = ftrace_failures_open, |
| 2487 | .read = seq_read, | 2388 | .read = seq_read, |
| 2488 | .llseek = seq_lseek, | 2389 | .llseek = seq_lseek, |
| 2489 | .release = ftrace_avail_release, | 2390 | .release = seq_release_private, |
| 2490 | }; | 2391 | }; |
| 2491 | 2392 | ||
| 2492 | static const struct file_operations ftrace_filter_fops = { | 2393 | static const struct file_operations ftrace_filter_fops = { |
| @@ -2515,11 +2416,9 @@ unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | |||
| 2515 | static void * | 2416 | static void * |
| 2516 | __g_next(struct seq_file *m, loff_t *pos) | 2417 | __g_next(struct seq_file *m, loff_t *pos) |
| 2517 | { | 2418 | { |
| 2518 | unsigned long *array = m->private; | ||
| 2519 | |||
| 2520 | if (*pos >= ftrace_graph_count) | 2419 | if (*pos >= ftrace_graph_count) |
| 2521 | return NULL; | 2420 | return NULL; |
| 2522 | return &array[*pos]; | 2421 | return &ftrace_graph_funcs[*pos]; |
| 2523 | } | 2422 | } |
| 2524 | 2423 | ||
| 2525 | static void * | 2424 | static void * |
| @@ -2548,7 +2447,6 @@ static void g_stop(struct seq_file *m, void *p) | |||
| 2548 | static int g_show(struct seq_file *m, void *v) | 2447 | static int g_show(struct seq_file *m, void *v) |
| 2549 | { | 2448 | { |
| 2550 | unsigned long *ptr = v; | 2449 | unsigned long *ptr = v; |
| 2551 | char str[KSYM_SYMBOL_LEN]; | ||
| 2552 | 2450 | ||
| 2553 | if (!ptr) | 2451 | if (!ptr) |
| 2554 | return 0; | 2452 | return 0; |
| @@ -2558,14 +2456,12 @@ static int g_show(struct seq_file *m, void *v) | |||
| 2558 | return 0; | 2456 | return 0; |
| 2559 | } | 2457 | } |
| 2560 | 2458 | ||
| 2561 | kallsyms_lookup(*ptr, NULL, NULL, NULL, str); | 2459 | seq_printf(m, "%ps\n", (void *)*ptr); |
| 2562 | |||
| 2563 | seq_printf(m, "%s\n", str); | ||
| 2564 | 2460 | ||
| 2565 | return 0; | 2461 | return 0; |
| 2566 | } | 2462 | } |
| 2567 | 2463 | ||
| 2568 | static struct seq_operations ftrace_graph_seq_ops = { | 2464 | static const struct seq_operations ftrace_graph_seq_ops = { |
| 2569 | .start = g_start, | 2465 | .start = g_start, |
| 2570 | .next = g_next, | 2466 | .next = g_next, |
| 2571 | .stop = g_stop, | 2467 | .stop = g_stop, |
| @@ -2586,16 +2482,10 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
| 2586 | ftrace_graph_count = 0; | 2482 | ftrace_graph_count = 0; |
| 2587 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | 2483 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); |
| 2588 | } | 2484 | } |
| 2485 | mutex_unlock(&graph_lock); | ||
| 2589 | 2486 | ||
| 2590 | if (file->f_mode & FMODE_READ) { | 2487 | if (file->f_mode & FMODE_READ) |
| 2591 | ret = seq_open(file, &ftrace_graph_seq_ops); | 2488 | ret = seq_open(file, &ftrace_graph_seq_ops); |
| 2592 | if (!ret) { | ||
| 2593 | struct seq_file *m = file->private_data; | ||
| 2594 | m->private = ftrace_graph_funcs; | ||
| 2595 | } | ||
| 2596 | } else | ||
| 2597 | file->private_data = ftrace_graph_funcs; | ||
| 2598 | mutex_unlock(&graph_lock); | ||
| 2599 | 2489 | ||
| 2600 | return ret; | 2490 | return ret; |
| 2601 | } | 2491 | } |
| @@ -2663,12 +2553,8 @@ static ssize_t | |||
| 2663 | ftrace_graph_write(struct file *file, const char __user *ubuf, | 2553 | ftrace_graph_write(struct file *file, const char __user *ubuf, |
| 2664 | size_t cnt, loff_t *ppos) | 2554 | size_t cnt, loff_t *ppos) |
| 2665 | { | 2555 | { |
| 2666 | unsigned char buffer[FTRACE_BUFF_MAX+1]; | 2556 | struct trace_parser parser; |
| 2667 | unsigned long *array; | 2557 | ssize_t read, ret; |
| 2668 | size_t read = 0; | ||
| 2669 | ssize_t ret; | ||
| 2670 | int index = 0; | ||
| 2671 | char ch; | ||
| 2672 | 2558 | ||
| 2673 | if (!cnt || cnt < 0) | 2559 | if (!cnt || cnt < 0) |
| 2674 | return 0; | 2560 | return 0; |
| @@ -2677,60 +2563,31 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
| 2677 | 2563 | ||
| 2678 | if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) { | 2564 | if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) { |
| 2679 | ret = -EBUSY; | 2565 | ret = -EBUSY; |
| 2680 | goto out; | 2566 | goto out_unlock; |
| 2681 | } | 2567 | } |
| 2682 | 2568 | ||
| 2683 | if (file->f_mode & FMODE_READ) { | 2569 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { |
| 2684 | struct seq_file *m = file->private_data; | 2570 | ret = -ENOMEM; |
| 2685 | array = m->private; | 2571 | goto out_unlock; |
| 2686 | } else | ||
| 2687 | array = file->private_data; | ||
| 2688 | |||
| 2689 | ret = get_user(ch, ubuf++); | ||
| 2690 | if (ret) | ||
| 2691 | goto out; | ||
| 2692 | read++; | ||
| 2693 | cnt--; | ||
| 2694 | |||
| 2695 | /* skip white space */ | ||
| 2696 | while (cnt && isspace(ch)) { | ||
| 2697 | ret = get_user(ch, ubuf++); | ||
| 2698 | if (ret) | ||
| 2699 | goto out; | ||
| 2700 | read++; | ||
| 2701 | cnt--; | ||
| 2702 | } | 2572 | } |
| 2703 | 2573 | ||
| 2704 | if (isspace(ch)) { | 2574 | read = trace_get_user(&parser, ubuf, cnt, ppos); |
| 2705 | *ppos += read; | ||
| 2706 | ret = read; | ||
| 2707 | goto out; | ||
| 2708 | } | ||
| 2709 | 2575 | ||
| 2710 | while (cnt && !isspace(ch)) { | 2576 | if (read >= 0 && trace_parser_loaded((&parser))) { |
| 2711 | if (index < FTRACE_BUFF_MAX) | 2577 | parser.buffer[parser.idx] = 0; |
| 2712 | buffer[index++] = ch; | 2578 | |
| 2713 | else { | 2579 | /* we allow only one expression at a time */ |
| 2714 | ret = -EINVAL; | 2580 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, |
| 2715 | goto out; | 2581 | parser.buffer); |
| 2716 | } | ||
| 2717 | ret = get_user(ch, ubuf++); | ||
| 2718 | if (ret) | 2582 | if (ret) |
| 2719 | goto out; | 2583 | goto out_free; |
| 2720 | read++; | ||
| 2721 | cnt--; | ||
| 2722 | } | 2584 | } |
| 2723 | buffer[index] = 0; | ||
| 2724 | |||
| 2725 | /* we allow only one expression at a time */ | ||
| 2726 | ret = ftrace_set_func(array, &ftrace_graph_count, buffer); | ||
| 2727 | if (ret) | ||
| 2728 | goto out; | ||
| 2729 | |||
| 2730 | file->f_pos += read; | ||
| 2731 | 2585 | ||
| 2732 | ret = read; | 2586 | ret = read; |
| 2733 | out: | 2587 | |
| 2588 | out_free: | ||
| 2589 | trace_parser_put(&parser); | ||
| 2590 | out_unlock: | ||
| 2734 | mutex_unlock(&graph_lock); | 2591 | mutex_unlock(&graph_lock); |
| 2735 | 2592 | ||
| 2736 | return ret; | 2593 | return ret; |
| @@ -3161,7 +3018,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops) | |||
| 3161 | 3018 | ||
| 3162 | int | 3019 | int |
| 3163 | ftrace_enable_sysctl(struct ctl_table *table, int write, | 3020 | ftrace_enable_sysctl(struct ctl_table *table, int write, |
| 3164 | struct file *file, void __user *buffer, size_t *lenp, | 3021 | void __user *buffer, size_t *lenp, |
| 3165 | loff_t *ppos) | 3022 | loff_t *ppos) |
| 3166 | { | 3023 | { |
| 3167 | int ret; | 3024 | int ret; |
| @@ -3171,7 +3028,7 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, | |||
| 3171 | 3028 | ||
| 3172 | mutex_lock(&ftrace_lock); | 3029 | mutex_lock(&ftrace_lock); |
| 3173 | 3030 | ||
| 3174 | ret = proc_dointvec(table, write, file, buffer, lenp, ppos); | 3031 | ret = proc_dointvec(table, write, buffer, lenp, ppos); |
| 3175 | 3032 | ||
| 3176 | if (ret || !write || (last_ftrace_enabled == !!ftrace_enabled)) | 3033 | if (ret || !write || (last_ftrace_enabled == !!ftrace_enabled)) |
| 3177 | goto out; | 3034 | goto out; |
