diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 144 |
1 files changed, 96 insertions, 48 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0d88ce9b9fb8..f3dadae83883 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -381,12 +381,19 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
381 | { | 381 | { |
382 | struct ftrace_profile *rec = v; | 382 | struct ftrace_profile *rec = v; |
383 | char str[KSYM_SYMBOL_LEN]; | 383 | char str[KSYM_SYMBOL_LEN]; |
384 | int ret = 0; | ||
384 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 385 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
385 | static DEFINE_MUTEX(mutex); | ||
386 | static struct trace_seq s; | 386 | static struct trace_seq s; |
387 | unsigned long long avg; | 387 | unsigned long long avg; |
388 | unsigned long long stddev; | 388 | unsigned long long stddev; |
389 | #endif | 389 | #endif |
390 | mutex_lock(&ftrace_profile_lock); | ||
391 | |||
392 | /* we raced with function_profile_reset() */ | ||
393 | if (unlikely(rec->counter == 0)) { | ||
394 | ret = -EBUSY; | ||
395 | goto out; | ||
396 | } | ||
390 | 397 | ||
391 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | 398 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); |
392 | seq_printf(m, " %-30.30s %10lu", str, rec->counter); | 399 | seq_printf(m, " %-30.30s %10lu", str, rec->counter); |
@@ -408,7 +415,6 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
408 | do_div(stddev, (rec->counter - 1) * 1000); | 415 | do_div(stddev, (rec->counter - 1) * 1000); |
409 | } | 416 | } |
410 | 417 | ||
411 | mutex_lock(&mutex); | ||
412 | trace_seq_init(&s); | 418 | trace_seq_init(&s); |
413 | trace_print_graph_duration(rec->time, &s); | 419 | trace_print_graph_duration(rec->time, &s); |
414 | trace_seq_puts(&s, " "); | 420 | trace_seq_puts(&s, " "); |
@@ -416,11 +422,12 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
416 | trace_seq_puts(&s, " "); | 422 | trace_seq_puts(&s, " "); |
417 | trace_print_graph_duration(stddev, &s); | 423 | trace_print_graph_duration(stddev, &s); |
418 | trace_print_seq(m, &s); | 424 | trace_print_seq(m, &s); |
419 | mutex_unlock(&mutex); | ||
420 | #endif | 425 | #endif |
421 | seq_putc(m, '\n'); | 426 | seq_putc(m, '\n'); |
427 | out: | ||
428 | mutex_unlock(&ftrace_profile_lock); | ||
422 | 429 | ||
423 | return 0; | 430 | return ret; |
424 | } | 431 | } |
425 | 432 | ||
426 | static void ftrace_profile_reset(struct ftrace_profile_stat *stat) | 433 | static void ftrace_profile_reset(struct ftrace_profile_stat *stat) |
@@ -793,6 +800,7 @@ static const struct file_operations ftrace_profile_fops = { | |||
793 | .open = tracing_open_generic, | 800 | .open = tracing_open_generic, |
794 | .read = ftrace_profile_read, | 801 | .read = ftrace_profile_read, |
795 | .write = ftrace_profile_write, | 802 | .write = ftrace_profile_write, |
803 | .llseek = default_llseek, | ||
796 | }; | 804 | }; |
797 | 805 | ||
798 | /* used to initialize the real stat files */ | 806 | /* used to initialize the real stat files */ |
@@ -877,10 +885,8 @@ enum { | |||
877 | FTRACE_ENABLE_CALLS = (1 << 0), | 885 | FTRACE_ENABLE_CALLS = (1 << 0), |
878 | FTRACE_DISABLE_CALLS = (1 << 1), | 886 | FTRACE_DISABLE_CALLS = (1 << 1), |
879 | FTRACE_UPDATE_TRACE_FUNC = (1 << 2), | 887 | FTRACE_UPDATE_TRACE_FUNC = (1 << 2), |
880 | FTRACE_ENABLE_MCOUNT = (1 << 3), | 888 | FTRACE_START_FUNC_RET = (1 << 3), |
881 | FTRACE_DISABLE_MCOUNT = (1 << 4), | 889 | FTRACE_STOP_FUNC_RET = (1 << 4), |
882 | FTRACE_START_FUNC_RET = (1 << 5), | ||
883 | FTRACE_STOP_FUNC_RET = (1 << 6), | ||
884 | }; | 890 | }; |
885 | 891 | ||
886 | static int ftrace_filtered; | 892 | static int ftrace_filtered; |
@@ -1219,8 +1225,6 @@ static void ftrace_shutdown(int command) | |||
1219 | 1225 | ||
1220 | static void ftrace_startup_sysctl(void) | 1226 | static void ftrace_startup_sysctl(void) |
1221 | { | 1227 | { |
1222 | int command = FTRACE_ENABLE_MCOUNT; | ||
1223 | |||
1224 | if (unlikely(ftrace_disabled)) | 1228 | if (unlikely(ftrace_disabled)) |
1225 | return; | 1229 | return; |
1226 | 1230 | ||
@@ -1228,23 +1232,17 @@ static void ftrace_startup_sysctl(void) | |||
1228 | saved_ftrace_func = NULL; | 1232 | saved_ftrace_func = NULL; |
1229 | /* ftrace_start_up is true if we want ftrace running */ | 1233 | /* ftrace_start_up is true if we want ftrace running */ |
1230 | if (ftrace_start_up) | 1234 | if (ftrace_start_up) |
1231 | command |= FTRACE_ENABLE_CALLS; | 1235 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); |
1232 | |||
1233 | ftrace_run_update_code(command); | ||
1234 | } | 1236 | } |
1235 | 1237 | ||
1236 | static void ftrace_shutdown_sysctl(void) | 1238 | static void ftrace_shutdown_sysctl(void) |
1237 | { | 1239 | { |
1238 | int command = FTRACE_DISABLE_MCOUNT; | ||
1239 | |||
1240 | if (unlikely(ftrace_disabled)) | 1240 | if (unlikely(ftrace_disabled)) |
1241 | return; | 1241 | return; |
1242 | 1242 | ||
1243 | /* ftrace_start_up is true if ftrace is running */ | 1243 | /* ftrace_start_up is true if ftrace is running */ |
1244 | if (ftrace_start_up) | 1244 | if (ftrace_start_up) |
1245 | command |= FTRACE_DISABLE_CALLS; | 1245 | ftrace_run_update_code(FTRACE_DISABLE_CALLS); |
1246 | |||
1247 | ftrace_run_update_code(command); | ||
1248 | } | 1246 | } |
1249 | 1247 | ||
1250 | static cycle_t ftrace_update_time; | 1248 | static cycle_t ftrace_update_time; |
@@ -1361,24 +1359,29 @@ enum { | |||
1361 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1359 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
1362 | 1360 | ||
1363 | struct ftrace_iterator { | 1361 | struct ftrace_iterator { |
1364 | struct ftrace_page *pg; | 1362 | loff_t pos; |
1365 | int hidx; | 1363 | loff_t func_pos; |
1366 | int idx; | 1364 | struct ftrace_page *pg; |
1367 | unsigned flags; | 1365 | struct dyn_ftrace *func; |
1368 | struct trace_parser parser; | 1366 | struct ftrace_func_probe *probe; |
1367 | struct trace_parser parser; | ||
1368 | int hidx; | ||
1369 | int idx; | ||
1370 | unsigned flags; | ||
1369 | }; | 1371 | }; |
1370 | 1372 | ||
1371 | static void * | 1373 | static void * |
1372 | t_hash_next(struct seq_file *m, void *v, loff_t *pos) | 1374 | t_hash_next(struct seq_file *m, loff_t *pos) |
1373 | { | 1375 | { |
1374 | struct ftrace_iterator *iter = m->private; | 1376 | struct ftrace_iterator *iter = m->private; |
1375 | struct hlist_node *hnd = v; | 1377 | struct hlist_node *hnd = NULL; |
1376 | struct hlist_head *hhd; | 1378 | struct hlist_head *hhd; |
1377 | 1379 | ||
1378 | WARN_ON(!(iter->flags & FTRACE_ITER_HASH)); | ||
1379 | |||
1380 | (*pos)++; | 1380 | (*pos)++; |
1381 | iter->pos = *pos; | ||
1381 | 1382 | ||
1383 | if (iter->probe) | ||
1384 | hnd = &iter->probe->node; | ||
1382 | retry: | 1385 | retry: |
1383 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) | 1386 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) |
1384 | return NULL; | 1387 | return NULL; |
@@ -1401,7 +1404,12 @@ t_hash_next(struct seq_file *m, void *v, loff_t *pos) | |||
1401 | } | 1404 | } |
1402 | } | 1405 | } |
1403 | 1406 | ||
1404 | return hnd; | 1407 | if (WARN_ON_ONCE(!hnd)) |
1408 | return NULL; | ||
1409 | |||
1410 | iter->probe = hlist_entry(hnd, struct ftrace_func_probe, node); | ||
1411 | |||
1412 | return iter; | ||
1405 | } | 1413 | } |
1406 | 1414 | ||
1407 | static void *t_hash_start(struct seq_file *m, loff_t *pos) | 1415 | static void *t_hash_start(struct seq_file *m, loff_t *pos) |
@@ -1410,26 +1418,32 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) | |||
1410 | void *p = NULL; | 1418 | void *p = NULL; |
1411 | loff_t l; | 1419 | loff_t l; |
1412 | 1420 | ||
1413 | if (!(iter->flags & FTRACE_ITER_HASH)) | 1421 | if (iter->func_pos > *pos) |
1414 | *pos = 0; | 1422 | return NULL; |
1415 | |||
1416 | iter->flags |= FTRACE_ITER_HASH; | ||
1417 | 1423 | ||
1418 | iter->hidx = 0; | 1424 | iter->hidx = 0; |
1419 | for (l = 0; l <= *pos; ) { | 1425 | for (l = 0; l <= (*pos - iter->func_pos); ) { |
1420 | p = t_hash_next(m, p, &l); | 1426 | p = t_hash_next(m, &l); |
1421 | if (!p) | 1427 | if (!p) |
1422 | break; | 1428 | break; |
1423 | } | 1429 | } |
1424 | return p; | 1430 | if (!p) |
1431 | return NULL; | ||
1432 | |||
1433 | /* Only set this if we have an item */ | ||
1434 | iter->flags |= FTRACE_ITER_HASH; | ||
1435 | |||
1436 | return iter; | ||
1425 | } | 1437 | } |
1426 | 1438 | ||
1427 | static int t_hash_show(struct seq_file *m, void *v) | 1439 | static int |
1440 | t_hash_show(struct seq_file *m, struct ftrace_iterator *iter) | ||
1428 | { | 1441 | { |
1429 | struct ftrace_func_probe *rec; | 1442 | struct ftrace_func_probe *rec; |
1430 | struct hlist_node *hnd = v; | ||
1431 | 1443 | ||
1432 | rec = hlist_entry(hnd, struct ftrace_func_probe, node); | 1444 | rec = iter->probe; |
1445 | if (WARN_ON_ONCE(!rec)) | ||
1446 | return -EIO; | ||
1433 | 1447 | ||
1434 | if (rec->ops->print) | 1448 | if (rec->ops->print) |
1435 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); | 1449 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); |
@@ -1450,12 +1464,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1450 | struct dyn_ftrace *rec = NULL; | 1464 | struct dyn_ftrace *rec = NULL; |
1451 | 1465 | ||
1452 | if (iter->flags & FTRACE_ITER_HASH) | 1466 | if (iter->flags & FTRACE_ITER_HASH) |
1453 | return t_hash_next(m, v, pos); | 1467 | return t_hash_next(m, pos); |
1454 | 1468 | ||
1455 | (*pos)++; | 1469 | (*pos)++; |
1470 | iter->pos = *pos; | ||
1456 | 1471 | ||
1457 | if (iter->flags & FTRACE_ITER_PRINTALL) | 1472 | if (iter->flags & FTRACE_ITER_PRINTALL) |
1458 | return NULL; | 1473 | return t_hash_start(m, pos); |
1459 | 1474 | ||
1460 | retry: | 1475 | retry: |
1461 | if (iter->idx >= iter->pg->index) { | 1476 | if (iter->idx >= iter->pg->index) { |
@@ -1484,7 +1499,20 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1484 | } | 1499 | } |
1485 | } | 1500 | } |
1486 | 1501 | ||
1487 | return rec; | 1502 | if (!rec) |
1503 | return t_hash_start(m, pos); | ||
1504 | |||
1505 | iter->func_pos = *pos; | ||
1506 | iter->func = rec; | ||
1507 | |||
1508 | return iter; | ||
1509 | } | ||
1510 | |||
1511 | static void reset_iter_read(struct ftrace_iterator *iter) | ||
1512 | { | ||
1513 | iter->pos = 0; | ||
1514 | iter->func_pos = 0; | ||
1515 | iter->flags &= ~(FTRACE_ITER_PRINTALL & FTRACE_ITER_HASH); | ||
1488 | } | 1516 | } |
1489 | 1517 | ||
1490 | static void *t_start(struct seq_file *m, loff_t *pos) | 1518 | static void *t_start(struct seq_file *m, loff_t *pos) |
@@ -1495,6 +1523,12 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1495 | 1523 | ||
1496 | mutex_lock(&ftrace_lock); | 1524 | mutex_lock(&ftrace_lock); |
1497 | /* | 1525 | /* |
1526 | * If an lseek was done, then reset and start from beginning. | ||
1527 | */ | ||
1528 | if (*pos < iter->pos) | ||
1529 | reset_iter_read(iter); | ||
1530 | |||
1531 | /* | ||
1498 | * For set_ftrace_filter reading, if we have the filter | 1532 | * For set_ftrace_filter reading, if we have the filter |
1499 | * off, we can short cut and just print out that all | 1533 | * off, we can short cut and just print out that all |
1500 | * functions are enabled. | 1534 | * functions are enabled. |
@@ -1503,12 +1537,19 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1503 | if (*pos > 0) | 1537 | if (*pos > 0) |
1504 | return t_hash_start(m, pos); | 1538 | return t_hash_start(m, pos); |
1505 | iter->flags |= FTRACE_ITER_PRINTALL; | 1539 | iter->flags |= FTRACE_ITER_PRINTALL; |
1540 | /* reset in case of seek/pread */ | ||
1541 | iter->flags &= ~FTRACE_ITER_HASH; | ||
1506 | return iter; | 1542 | return iter; |
1507 | } | 1543 | } |
1508 | 1544 | ||
1509 | if (iter->flags & FTRACE_ITER_HASH) | 1545 | if (iter->flags & FTRACE_ITER_HASH) |
1510 | return t_hash_start(m, pos); | 1546 | return t_hash_start(m, pos); |
1511 | 1547 | ||
1548 | /* | ||
1549 | * Unfortunately, we need to restart at ftrace_pages_start | ||
1550 | * every time we let go of the ftrace_mutex. This is because | ||
1551 | * those pointers can change without the lock. | ||
1552 | */ | ||
1512 | iter->pg = ftrace_pages_start; | 1553 | iter->pg = ftrace_pages_start; |
1513 | iter->idx = 0; | 1554 | iter->idx = 0; |
1514 | for (l = 0; l <= *pos; ) { | 1555 | for (l = 0; l <= *pos; ) { |
@@ -1517,10 +1558,14 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1517 | break; | 1558 | break; |
1518 | } | 1559 | } |
1519 | 1560 | ||
1520 | if (!p && iter->flags & FTRACE_ITER_FILTER) | 1561 | if (!p) { |
1521 | return t_hash_start(m, pos); | 1562 | if (iter->flags & FTRACE_ITER_FILTER) |
1563 | return t_hash_start(m, pos); | ||
1522 | 1564 | ||
1523 | return p; | 1565 | return NULL; |
1566 | } | ||
1567 | |||
1568 | return iter; | ||
1524 | } | 1569 | } |
1525 | 1570 | ||
1526 | static void t_stop(struct seq_file *m, void *p) | 1571 | static void t_stop(struct seq_file *m, void *p) |
@@ -1531,16 +1576,18 @@ static void t_stop(struct seq_file *m, void *p) | |||
1531 | static int t_show(struct seq_file *m, void *v) | 1576 | static int t_show(struct seq_file *m, void *v) |
1532 | { | 1577 | { |
1533 | struct ftrace_iterator *iter = m->private; | 1578 | struct ftrace_iterator *iter = m->private; |
1534 | struct dyn_ftrace *rec = v; | 1579 | struct dyn_ftrace *rec; |
1535 | 1580 | ||
1536 | if (iter->flags & FTRACE_ITER_HASH) | 1581 | if (iter->flags & FTRACE_ITER_HASH) |
1537 | return t_hash_show(m, v); | 1582 | return t_hash_show(m, iter); |
1538 | 1583 | ||
1539 | if (iter->flags & FTRACE_ITER_PRINTALL) { | 1584 | if (iter->flags & FTRACE_ITER_PRINTALL) { |
1540 | seq_printf(m, "#### all functions enabled ####\n"); | 1585 | seq_printf(m, "#### all functions enabled ####\n"); |
1541 | return 0; | 1586 | return 0; |
1542 | } | 1587 | } |
1543 | 1588 | ||
1589 | rec = iter->func; | ||
1590 | |||
1544 | if (!rec) | 1591 | if (!rec) |
1545 | return 0; | 1592 | return 0; |
1546 | 1593 | ||
@@ -1592,8 +1639,8 @@ ftrace_failures_open(struct inode *inode, struct file *file) | |||
1592 | 1639 | ||
1593 | ret = ftrace_avail_open(inode, file); | 1640 | ret = ftrace_avail_open(inode, file); |
1594 | if (!ret) { | 1641 | if (!ret) { |
1595 | m = (struct seq_file *)file->private_data; | 1642 | m = file->private_data; |
1596 | iter = (struct ftrace_iterator *)m->private; | 1643 | iter = m->private; |
1597 | iter->flags = FTRACE_ITER_FAILURES; | 1644 | iter->flags = FTRACE_ITER_FAILURES; |
1598 | } | 1645 | } |
1599 | 1646 | ||
@@ -2623,6 +2670,7 @@ static const struct file_operations ftrace_graph_fops = { | |||
2623 | .read = seq_read, | 2670 | .read = seq_read, |
2624 | .write = ftrace_graph_write, | 2671 | .write = ftrace_graph_write, |
2625 | .release = ftrace_graph_release, | 2672 | .release = ftrace_graph_release, |
2673 | .llseek = seq_lseek, | ||
2626 | }; | 2674 | }; |
2627 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 2675 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
2628 | 2676 | ||