diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 183 |
1 files changed, 49 insertions, 134 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8c804e24f96f..23df7771c937 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -1323,11 +1323,10 @@ static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) | |||
1323 | 1323 | ||
1324 | enum { | 1324 | enum { |
1325 | FTRACE_ITER_FILTER = (1 << 0), | 1325 | FTRACE_ITER_FILTER = (1 << 0), |
1326 | FTRACE_ITER_CONT = (1 << 1), | 1326 | FTRACE_ITER_NOTRACE = (1 << 1), |
1327 | FTRACE_ITER_NOTRACE = (1 << 2), | 1327 | FTRACE_ITER_FAILURES = (1 << 2), |
1328 | FTRACE_ITER_FAILURES = (1 << 3), | 1328 | FTRACE_ITER_PRINTALL = (1 << 3), |
1329 | FTRACE_ITER_PRINTALL = (1 << 4), | 1329 | FTRACE_ITER_HASH = (1 << 4), |
1330 | FTRACE_ITER_HASH = (1 << 5), | ||
1331 | }; | 1330 | }; |
1332 | 1331 | ||
1333 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1332 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
@@ -1337,8 +1336,7 @@ struct ftrace_iterator { | |||
1337 | int hidx; | 1336 | int hidx; |
1338 | int idx; | 1337 | int idx; |
1339 | unsigned flags; | 1338 | unsigned flags; |
1340 | unsigned char buffer[FTRACE_BUFF_MAX+1]; | 1339 | struct trace_parser parser; |
1341 | unsigned buffer_idx; | ||
1342 | }; | 1340 | }; |
1343 | 1341 | ||
1344 | static void * | 1342 | static void * |
@@ -1407,7 +1405,7 @@ static int t_hash_show(struct seq_file *m, void *v) | |||
1407 | if (rec->ops->print) | 1405 | if (rec->ops->print) |
1408 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); | 1406 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); |
1409 | 1407 | ||
1410 | seq_printf(m, "%pf:%pf", (void *)rec->ip, (void *)rec->ops->func); | 1408 | seq_printf(m, "%ps:%ps", (void *)rec->ip, (void *)rec->ops->func); |
1411 | 1409 | ||
1412 | if (rec->data) | 1410 | if (rec->data) |
1413 | seq_printf(m, ":%p", rec->data); | 1411 | seq_printf(m, ":%p", rec->data); |
@@ -1517,12 +1515,12 @@ static int t_show(struct seq_file *m, void *v) | |||
1517 | if (!rec) | 1515 | if (!rec) |
1518 | return 0; | 1516 | return 0; |
1519 | 1517 | ||
1520 | seq_printf(m, "%pf\n", (void *)rec->ip); | 1518 | seq_printf(m, "%ps\n", (void *)rec->ip); |
1521 | 1519 | ||
1522 | return 0; | 1520 | return 0; |
1523 | } | 1521 | } |
1524 | 1522 | ||
1525 | static struct seq_operations show_ftrace_seq_ops = { | 1523 | static const struct seq_operations show_ftrace_seq_ops = { |
1526 | .start = t_start, | 1524 | .start = t_start, |
1527 | .next = t_next, | 1525 | .next = t_next, |
1528 | .stop = t_stop, | 1526 | .stop = t_stop, |
@@ -1604,6 +1602,11 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable) | |||
1604 | if (!iter) | 1602 | if (!iter) |
1605 | return -ENOMEM; | 1603 | return -ENOMEM; |
1606 | 1604 | ||
1605 | if (trace_parser_get_init(&iter->parser, FTRACE_BUFF_MAX)) { | ||
1606 | kfree(iter); | ||
1607 | return -ENOMEM; | ||
1608 | } | ||
1609 | |||
1607 | mutex_lock(&ftrace_regex_lock); | 1610 | mutex_lock(&ftrace_regex_lock); |
1608 | if ((file->f_mode & FMODE_WRITE) && | 1611 | if ((file->f_mode & FMODE_WRITE) && |
1609 | (file->f_flags & O_TRUNC)) | 1612 | (file->f_flags & O_TRUNC)) |
@@ -2059,9 +2062,9 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
2059 | int i, len = 0; | 2062 | int i, len = 0; |
2060 | char *search; | 2063 | char *search; |
2061 | 2064 | ||
2062 | if (glob && (strcmp(glob, "*") || !strlen(glob))) | 2065 | if (glob && (strcmp(glob, "*") == 0 || !strlen(glob))) |
2063 | glob = NULL; | 2066 | glob = NULL; |
2064 | else { | 2067 | else if (glob) { |
2065 | int not; | 2068 | int not; |
2066 | 2069 | ||
2067 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 2070 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); |
@@ -2196,9 +2199,8 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
2196 | size_t cnt, loff_t *ppos, int enable) | 2199 | size_t cnt, loff_t *ppos, int enable) |
2197 | { | 2200 | { |
2198 | struct ftrace_iterator *iter; | 2201 | struct ftrace_iterator *iter; |
2199 | char ch; | 2202 | struct trace_parser *parser; |
2200 | size_t read = 0; | 2203 | ssize_t ret, read; |
2201 | ssize_t ret; | ||
2202 | 2204 | ||
2203 | if (!cnt || cnt < 0) | 2205 | if (!cnt || cnt < 0) |
2204 | return 0; | 2206 | return 0; |
@@ -2211,72 +2213,23 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
2211 | } else | 2213 | } else |
2212 | iter = file->private_data; | 2214 | iter = file->private_data; |
2213 | 2215 | ||
2214 | if (!*ppos) { | 2216 | parser = &iter->parser; |
2215 | iter->flags &= ~FTRACE_ITER_CONT; | 2217 | read = trace_get_user(parser, ubuf, cnt, ppos); |
2216 | iter->buffer_idx = 0; | ||
2217 | } | ||
2218 | 2218 | ||
2219 | ret = get_user(ch, ubuf++); | 2219 | if (trace_parser_loaded(parser) && |
2220 | if (ret) | 2220 | !trace_parser_cont(parser)) { |
2221 | goto out; | 2221 | ret = ftrace_process_regex(parser->buffer, |
2222 | read++; | 2222 | parser->idx, enable); |
2223 | cnt--; | ||
2224 | |||
2225 | /* | ||
2226 | * If the parser haven't finished with the last write, | ||
2227 | * continue reading the user input without skipping spaces. | ||
2228 | */ | ||
2229 | if (!(iter->flags & FTRACE_ITER_CONT)) { | ||
2230 | /* skip white space */ | ||
2231 | while (cnt && isspace(ch)) { | ||
2232 | ret = get_user(ch, ubuf++); | ||
2233 | if (ret) | ||
2234 | goto out; | ||
2235 | read++; | ||
2236 | cnt--; | ||
2237 | } | ||
2238 | |||
2239 | /* only spaces were written */ | ||
2240 | if (isspace(ch)) { | ||
2241 | *ppos += read; | ||
2242 | ret = read; | ||
2243 | goto out; | ||
2244 | } | ||
2245 | |||
2246 | iter->buffer_idx = 0; | ||
2247 | } | ||
2248 | |||
2249 | while (cnt && !isspace(ch)) { | ||
2250 | if (iter->buffer_idx < FTRACE_BUFF_MAX) | ||
2251 | iter->buffer[iter->buffer_idx++] = ch; | ||
2252 | else { | ||
2253 | ret = -EINVAL; | ||
2254 | goto out; | ||
2255 | } | ||
2256 | ret = get_user(ch, ubuf++); | ||
2257 | if (ret) | 2223 | if (ret) |
2258 | goto out; | 2224 | goto out; |
2259 | read++; | ||
2260 | cnt--; | ||
2261 | } | ||
2262 | 2225 | ||
2263 | if (isspace(ch)) { | 2226 | trace_parser_clear(parser); |
2264 | iter->buffer[iter->buffer_idx] = 0; | ||
2265 | ret = ftrace_process_regex(iter->buffer, | ||
2266 | iter->buffer_idx, enable); | ||
2267 | if (ret) | ||
2268 | goto out; | ||
2269 | iter->buffer_idx = 0; | ||
2270 | } else { | ||
2271 | iter->flags |= FTRACE_ITER_CONT; | ||
2272 | iter->buffer[iter->buffer_idx++] = ch; | ||
2273 | } | 2227 | } |
2274 | 2228 | ||
2275 | *ppos += read; | ||
2276 | ret = read; | 2229 | ret = read; |
2277 | out: | ||
2278 | mutex_unlock(&ftrace_regex_lock); | ||
2279 | 2230 | ||
2231 | mutex_unlock(&ftrace_regex_lock); | ||
2232 | out: | ||
2280 | return ret; | 2233 | return ret; |
2281 | } | 2234 | } |
2282 | 2235 | ||
@@ -2381,6 +2334,7 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
2381 | { | 2334 | { |
2382 | struct seq_file *m = (struct seq_file *)file->private_data; | 2335 | struct seq_file *m = (struct seq_file *)file->private_data; |
2383 | struct ftrace_iterator *iter; | 2336 | struct ftrace_iterator *iter; |
2337 | struct trace_parser *parser; | ||
2384 | 2338 | ||
2385 | mutex_lock(&ftrace_regex_lock); | 2339 | mutex_lock(&ftrace_regex_lock); |
2386 | if (file->f_mode & FMODE_READ) { | 2340 | if (file->f_mode & FMODE_READ) { |
@@ -2390,9 +2344,10 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
2390 | } else | 2344 | } else |
2391 | iter = file->private_data; | 2345 | iter = file->private_data; |
2392 | 2346 | ||
2393 | if (iter->buffer_idx) { | 2347 | parser = &iter->parser; |
2394 | iter->buffer[iter->buffer_idx] = 0; | 2348 | if (trace_parser_loaded(parser)) { |
2395 | ftrace_match_records(iter->buffer, iter->buffer_idx, enable); | 2349 | parser->buffer[parser->idx] = 0; |
2350 | ftrace_match_records(parser->buffer, parser->idx, enable); | ||
2396 | } | 2351 | } |
2397 | 2352 | ||
2398 | mutex_lock(&ftrace_lock); | 2353 | mutex_lock(&ftrace_lock); |
@@ -2400,7 +2355,9 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
2400 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); | 2355 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); |
2401 | mutex_unlock(&ftrace_lock); | 2356 | mutex_unlock(&ftrace_lock); |
2402 | 2357 | ||
2358 | trace_parser_put(parser); | ||
2403 | kfree(iter); | 2359 | kfree(iter); |
2360 | |||
2404 | mutex_unlock(&ftrace_regex_lock); | 2361 | mutex_unlock(&ftrace_regex_lock); |
2405 | return 0; | 2362 | return 0; |
2406 | } | 2363 | } |
@@ -2457,11 +2414,9 @@ unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | |||
2457 | static void * | 2414 | static void * |
2458 | __g_next(struct seq_file *m, loff_t *pos) | 2415 | __g_next(struct seq_file *m, loff_t *pos) |
2459 | { | 2416 | { |
2460 | unsigned long *array = m->private; | ||
2461 | |||
2462 | if (*pos >= ftrace_graph_count) | 2417 | if (*pos >= ftrace_graph_count) |
2463 | return NULL; | 2418 | return NULL; |
2464 | return &array[*pos]; | 2419 | return &ftrace_graph_funcs[*pos]; |
2465 | } | 2420 | } |
2466 | 2421 | ||
2467 | static void * | 2422 | static void * |
@@ -2499,12 +2454,12 @@ static int g_show(struct seq_file *m, void *v) | |||
2499 | return 0; | 2454 | return 0; |
2500 | } | 2455 | } |
2501 | 2456 | ||
2502 | seq_printf(m, "%pf\n", v); | 2457 | seq_printf(m, "%ps\n", (void *)*ptr); |
2503 | 2458 | ||
2504 | return 0; | 2459 | return 0; |
2505 | } | 2460 | } |
2506 | 2461 | ||
2507 | static struct seq_operations ftrace_graph_seq_ops = { | 2462 | static const struct seq_operations ftrace_graph_seq_ops = { |
2508 | .start = g_start, | 2463 | .start = g_start, |
2509 | .next = g_next, | 2464 | .next = g_next, |
2510 | .stop = g_stop, | 2465 | .stop = g_stop, |
@@ -2525,16 +2480,10 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
2525 | ftrace_graph_count = 0; | 2480 | ftrace_graph_count = 0; |
2526 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | 2481 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); |
2527 | } | 2482 | } |
2483 | mutex_unlock(&graph_lock); | ||
2528 | 2484 | ||
2529 | if (file->f_mode & FMODE_READ) { | 2485 | if (file->f_mode & FMODE_READ) |
2530 | ret = seq_open(file, &ftrace_graph_seq_ops); | 2486 | ret = seq_open(file, &ftrace_graph_seq_ops); |
2531 | if (!ret) { | ||
2532 | struct seq_file *m = file->private_data; | ||
2533 | m->private = ftrace_graph_funcs; | ||
2534 | } | ||
2535 | } else | ||
2536 | file->private_data = ftrace_graph_funcs; | ||
2537 | mutex_unlock(&graph_lock); | ||
2538 | 2487 | ||
2539 | return ret; | 2488 | return ret; |
2540 | } | 2489 | } |
@@ -2602,12 +2551,9 @@ static ssize_t | |||
2602 | ftrace_graph_write(struct file *file, const char __user *ubuf, | 2551 | ftrace_graph_write(struct file *file, const char __user *ubuf, |
2603 | size_t cnt, loff_t *ppos) | 2552 | size_t cnt, loff_t *ppos) |
2604 | { | 2553 | { |
2605 | unsigned char buffer[FTRACE_BUFF_MAX+1]; | 2554 | struct trace_parser parser; |
2606 | unsigned long *array; | ||
2607 | size_t read = 0; | 2555 | size_t read = 0; |
2608 | ssize_t ret; | 2556 | ssize_t ret; |
2609 | int index = 0; | ||
2610 | char ch; | ||
2611 | 2557 | ||
2612 | if (!cnt || cnt < 0) | 2558 | if (!cnt || cnt < 0) |
2613 | return 0; | 2559 | return 0; |
@@ -2619,57 +2565,26 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
2619 | goto out; | 2565 | goto out; |
2620 | } | 2566 | } |
2621 | 2567 | ||
2622 | if (file->f_mode & FMODE_READ) { | 2568 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { |
2623 | struct seq_file *m = file->private_data; | 2569 | ret = -ENOMEM; |
2624 | array = m->private; | ||
2625 | } else | ||
2626 | array = file->private_data; | ||
2627 | |||
2628 | ret = get_user(ch, ubuf++); | ||
2629 | if (ret) | ||
2630 | goto out; | 2570 | goto out; |
2631 | read++; | ||
2632 | cnt--; | ||
2633 | |||
2634 | /* skip white space */ | ||
2635 | while (cnt && isspace(ch)) { | ||
2636 | ret = get_user(ch, ubuf++); | ||
2637 | if (ret) | ||
2638 | goto out; | ||
2639 | read++; | ||
2640 | cnt--; | ||
2641 | } | 2571 | } |
2642 | 2572 | ||
2643 | if (isspace(ch)) { | 2573 | read = trace_get_user(&parser, ubuf, cnt, ppos); |
2644 | *ppos += read; | ||
2645 | ret = read; | ||
2646 | goto out; | ||
2647 | } | ||
2648 | 2574 | ||
2649 | while (cnt && !isspace(ch)) { | 2575 | if (trace_parser_loaded((&parser))) { |
2650 | if (index < FTRACE_BUFF_MAX) | 2576 | parser.buffer[parser.idx] = 0; |
2651 | buffer[index++] = ch; | 2577 | |
2652 | else { | 2578 | /* we allow only one expression at a time */ |
2653 | ret = -EINVAL; | 2579 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, |
2654 | goto out; | 2580 | parser.buffer); |
2655 | } | ||
2656 | ret = get_user(ch, ubuf++); | ||
2657 | if (ret) | 2581 | if (ret) |
2658 | goto out; | 2582 | goto out; |
2659 | read++; | ||
2660 | cnt--; | ||
2661 | } | 2583 | } |
2662 | buffer[index] = 0; | ||
2663 | |||
2664 | /* we allow only one expression at a time */ | ||
2665 | ret = ftrace_set_func(array, &ftrace_graph_count, buffer); | ||
2666 | if (ret) | ||
2667 | goto out; | ||
2668 | |||
2669 | file->f_pos += read; | ||
2670 | 2584 | ||
2671 | ret = read; | 2585 | ret = read; |
2672 | out: | 2586 | out: |
2587 | trace_parser_put(&parser); | ||
2673 | mutex_unlock(&graph_lock); | 2588 | mutex_unlock(&graph_lock); |
2674 | 2589 | ||
2675 | return ret; | 2590 | return ret; |