diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 129 |
1 files changed, 84 insertions, 45 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index fa7ece649fe1..f3dadae83883 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -800,6 +800,7 @@ static const struct file_operations ftrace_profile_fops = { | |||
800 | .open = tracing_open_generic, | 800 | .open = tracing_open_generic, |
801 | .read = ftrace_profile_read, | 801 | .read = ftrace_profile_read, |
802 | .write = ftrace_profile_write, | 802 | .write = ftrace_profile_write, |
803 | .llseek = default_llseek, | ||
803 | }; | 804 | }; |
804 | 805 | ||
805 | /* used to initialize the real stat files */ | 806 | /* used to initialize the real stat files */ |
@@ -884,10 +885,8 @@ enum { | |||
884 | FTRACE_ENABLE_CALLS = (1 << 0), | 885 | FTRACE_ENABLE_CALLS = (1 << 0), |
885 | FTRACE_DISABLE_CALLS = (1 << 1), | 886 | FTRACE_DISABLE_CALLS = (1 << 1), |
886 | FTRACE_UPDATE_TRACE_FUNC = (1 << 2), | 887 | FTRACE_UPDATE_TRACE_FUNC = (1 << 2), |
887 | FTRACE_ENABLE_MCOUNT = (1 << 3), | 888 | FTRACE_START_FUNC_RET = (1 << 3), |
888 | FTRACE_DISABLE_MCOUNT = (1 << 4), | 889 | FTRACE_STOP_FUNC_RET = (1 << 4), |
889 | FTRACE_START_FUNC_RET = (1 << 5), | ||
890 | FTRACE_STOP_FUNC_RET = (1 << 6), | ||
891 | }; | 890 | }; |
892 | 891 | ||
893 | static int ftrace_filtered; | 892 | static int ftrace_filtered; |
@@ -1226,8 +1225,6 @@ static void ftrace_shutdown(int command) | |||
1226 | 1225 | ||
1227 | static void ftrace_startup_sysctl(void) | 1226 | static void ftrace_startup_sysctl(void) |
1228 | { | 1227 | { |
1229 | int command = FTRACE_ENABLE_MCOUNT; | ||
1230 | |||
1231 | if (unlikely(ftrace_disabled)) | 1228 | if (unlikely(ftrace_disabled)) |
1232 | return; | 1229 | return; |
1233 | 1230 | ||
@@ -1235,23 +1232,17 @@ static void ftrace_startup_sysctl(void) | |||
1235 | saved_ftrace_func = NULL; | 1232 | saved_ftrace_func = NULL; |
1236 | /* ftrace_start_up is true if we want ftrace running */ | 1233 | /* ftrace_start_up is true if we want ftrace running */ |
1237 | if (ftrace_start_up) | 1234 | if (ftrace_start_up) |
1238 | command |= FTRACE_ENABLE_CALLS; | 1235 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); |
1239 | |||
1240 | ftrace_run_update_code(command); | ||
1241 | } | 1236 | } |
1242 | 1237 | ||
1243 | static void ftrace_shutdown_sysctl(void) | 1238 | static void ftrace_shutdown_sysctl(void) |
1244 | { | 1239 | { |
1245 | int command = FTRACE_DISABLE_MCOUNT; | ||
1246 | |||
1247 | if (unlikely(ftrace_disabled)) | 1240 | if (unlikely(ftrace_disabled)) |
1248 | return; | 1241 | return; |
1249 | 1242 | ||
1250 | /* ftrace_start_up is true if ftrace is running */ | 1243 | /* ftrace_start_up is true if ftrace is running */ |
1251 | if (ftrace_start_up) | 1244 | if (ftrace_start_up) |
1252 | command |= FTRACE_DISABLE_CALLS; | 1245 | ftrace_run_update_code(FTRACE_DISABLE_CALLS); |
1253 | |||
1254 | ftrace_run_update_code(command); | ||
1255 | } | 1246 | } |
1256 | 1247 | ||
1257 | static cycle_t ftrace_update_time; | 1248 | static cycle_t ftrace_update_time; |
@@ -1368,24 +1359,29 @@ enum { | |||
1368 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1359 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
1369 | 1360 | ||
1370 | struct ftrace_iterator { | 1361 | struct ftrace_iterator { |
1371 | struct ftrace_page *pg; | 1362 | loff_t pos; |
1372 | int hidx; | 1363 | loff_t func_pos; |
1373 | int idx; | 1364 | struct ftrace_page *pg; |
1374 | unsigned flags; | 1365 | struct dyn_ftrace *func; |
1375 | struct trace_parser parser; | 1366 | struct ftrace_func_probe *probe; |
1367 | struct trace_parser parser; | ||
1368 | int hidx; | ||
1369 | int idx; | ||
1370 | unsigned flags; | ||
1376 | }; | 1371 | }; |
1377 | 1372 | ||
1378 | static void * | 1373 | static void * |
1379 | t_hash_next(struct seq_file *m, void *v, loff_t *pos) | 1374 | t_hash_next(struct seq_file *m, loff_t *pos) |
1380 | { | 1375 | { |
1381 | struct ftrace_iterator *iter = m->private; | 1376 | struct ftrace_iterator *iter = m->private; |
1382 | struct hlist_node *hnd = v; | 1377 | struct hlist_node *hnd = NULL; |
1383 | struct hlist_head *hhd; | 1378 | struct hlist_head *hhd; |
1384 | 1379 | ||
1385 | WARN_ON(!(iter->flags & FTRACE_ITER_HASH)); | ||
1386 | |||
1387 | (*pos)++; | 1380 | (*pos)++; |
1381 | iter->pos = *pos; | ||
1388 | 1382 | ||
1383 | if (iter->probe) | ||
1384 | hnd = &iter->probe->node; | ||
1389 | retry: | 1385 | retry: |
1390 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) | 1386 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) |
1391 | return NULL; | 1387 | return NULL; |
@@ -1408,7 +1404,12 @@ t_hash_next(struct seq_file *m, void *v, loff_t *pos) | |||
1408 | } | 1404 | } |
1409 | } | 1405 | } |
1410 | 1406 | ||
1411 | 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; | ||
1412 | } | 1413 | } |
1413 | 1414 | ||
1414 | 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) |
@@ -1417,26 +1418,32 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) | |||
1417 | void *p = NULL; | 1418 | void *p = NULL; |
1418 | loff_t l; | 1419 | loff_t l; |
1419 | 1420 | ||
1420 | if (!(iter->flags & FTRACE_ITER_HASH)) | 1421 | if (iter->func_pos > *pos) |
1421 | *pos = 0; | 1422 | return NULL; |
1422 | |||
1423 | iter->flags |= FTRACE_ITER_HASH; | ||
1424 | 1423 | ||
1425 | iter->hidx = 0; | 1424 | iter->hidx = 0; |
1426 | for (l = 0; l <= *pos; ) { | 1425 | for (l = 0; l <= (*pos - iter->func_pos); ) { |
1427 | p = t_hash_next(m, p, &l); | 1426 | p = t_hash_next(m, &l); |
1428 | if (!p) | 1427 | if (!p) |
1429 | break; | 1428 | break; |
1430 | } | 1429 | } |
1431 | 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; | ||
1432 | } | 1437 | } |
1433 | 1438 | ||
1434 | 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) | ||
1435 | { | 1441 | { |
1436 | struct ftrace_func_probe *rec; | 1442 | struct ftrace_func_probe *rec; |
1437 | struct hlist_node *hnd = v; | ||
1438 | 1443 | ||
1439 | rec = hlist_entry(hnd, struct ftrace_func_probe, node); | 1444 | rec = iter->probe; |
1445 | if (WARN_ON_ONCE(!rec)) | ||
1446 | return -EIO; | ||
1440 | 1447 | ||
1441 | if (rec->ops->print) | 1448 | if (rec->ops->print) |
1442 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); | 1449 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); |
@@ -1457,12 +1464,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1457 | struct dyn_ftrace *rec = NULL; | 1464 | struct dyn_ftrace *rec = NULL; |
1458 | 1465 | ||
1459 | if (iter->flags & FTRACE_ITER_HASH) | 1466 | if (iter->flags & FTRACE_ITER_HASH) |
1460 | return t_hash_next(m, v, pos); | 1467 | return t_hash_next(m, pos); |
1461 | 1468 | ||
1462 | (*pos)++; | 1469 | (*pos)++; |
1470 | iter->pos = *pos; | ||
1463 | 1471 | ||
1464 | if (iter->flags & FTRACE_ITER_PRINTALL) | 1472 | if (iter->flags & FTRACE_ITER_PRINTALL) |
1465 | return NULL; | 1473 | return t_hash_start(m, pos); |
1466 | 1474 | ||
1467 | retry: | 1475 | retry: |
1468 | if (iter->idx >= iter->pg->index) { | 1476 | if (iter->idx >= iter->pg->index) { |
@@ -1491,7 +1499,20 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1491 | } | 1499 | } |
1492 | } | 1500 | } |
1493 | 1501 | ||
1494 | 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); | ||
1495 | } | 1516 | } |
1496 | 1517 | ||
1497 | static void *t_start(struct seq_file *m, loff_t *pos) | 1518 | static void *t_start(struct seq_file *m, loff_t *pos) |
@@ -1502,6 +1523,12 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1502 | 1523 | ||
1503 | mutex_lock(&ftrace_lock); | 1524 | mutex_lock(&ftrace_lock); |
1504 | /* | 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 | /* | ||
1505 | * For set_ftrace_filter reading, if we have the filter | 1532 | * For set_ftrace_filter reading, if we have the filter |
1506 | * off, we can short cut and just print out that all | 1533 | * off, we can short cut and just print out that all |
1507 | * functions are enabled. | 1534 | * functions are enabled. |
@@ -1518,6 +1545,11 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1518 | if (iter->flags & FTRACE_ITER_HASH) | 1545 | if (iter->flags & FTRACE_ITER_HASH) |
1519 | return t_hash_start(m, pos); | 1546 | return t_hash_start(m, pos); |
1520 | 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 | */ | ||
1521 | iter->pg = ftrace_pages_start; | 1553 | iter->pg = ftrace_pages_start; |
1522 | iter->idx = 0; | 1554 | iter->idx = 0; |
1523 | for (l = 0; l <= *pos; ) { | 1555 | for (l = 0; l <= *pos; ) { |
@@ -1526,10 +1558,14 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1526 | break; | 1558 | break; |
1527 | } | 1559 | } |
1528 | 1560 | ||
1529 | if (!p && iter->flags & FTRACE_ITER_FILTER) | 1561 | if (!p) { |
1530 | return t_hash_start(m, pos); | 1562 | if (iter->flags & FTRACE_ITER_FILTER) |
1563 | return t_hash_start(m, pos); | ||
1564 | |||
1565 | return NULL; | ||
1566 | } | ||
1531 | 1567 | ||
1532 | return p; | 1568 | return iter; |
1533 | } | 1569 | } |
1534 | 1570 | ||
1535 | static void t_stop(struct seq_file *m, void *p) | 1571 | static void t_stop(struct seq_file *m, void *p) |
@@ -1540,16 +1576,18 @@ static void t_stop(struct seq_file *m, void *p) | |||
1540 | static int t_show(struct seq_file *m, void *v) | 1576 | static int t_show(struct seq_file *m, void *v) |
1541 | { | 1577 | { |
1542 | struct ftrace_iterator *iter = m->private; | 1578 | struct ftrace_iterator *iter = m->private; |
1543 | struct dyn_ftrace *rec = v; | 1579 | struct dyn_ftrace *rec; |
1544 | 1580 | ||
1545 | if (iter->flags & FTRACE_ITER_HASH) | 1581 | if (iter->flags & FTRACE_ITER_HASH) |
1546 | return t_hash_show(m, v); | 1582 | return t_hash_show(m, iter); |
1547 | 1583 | ||
1548 | if (iter->flags & FTRACE_ITER_PRINTALL) { | 1584 | if (iter->flags & FTRACE_ITER_PRINTALL) { |
1549 | seq_printf(m, "#### all functions enabled ####\n"); | 1585 | seq_printf(m, "#### all functions enabled ####\n"); |
1550 | return 0; | 1586 | return 0; |
1551 | } | 1587 | } |
1552 | 1588 | ||
1589 | rec = iter->func; | ||
1590 | |||
1553 | if (!rec) | 1591 | if (!rec) |
1554 | return 0; | 1592 | return 0; |
1555 | 1593 | ||
@@ -1601,8 +1639,8 @@ ftrace_failures_open(struct inode *inode, struct file *file) | |||
1601 | 1639 | ||
1602 | ret = ftrace_avail_open(inode, file); | 1640 | ret = ftrace_avail_open(inode, file); |
1603 | if (!ret) { | 1641 | if (!ret) { |
1604 | m = (struct seq_file *)file->private_data; | 1642 | m = file->private_data; |
1605 | iter = (struct ftrace_iterator *)m->private; | 1643 | iter = m->private; |
1606 | iter->flags = FTRACE_ITER_FAILURES; | 1644 | iter->flags = FTRACE_ITER_FAILURES; |
1607 | } | 1645 | } |
1608 | 1646 | ||
@@ -2418,7 +2456,7 @@ static const struct file_operations ftrace_filter_fops = { | |||
2418 | .open = ftrace_filter_open, | 2456 | .open = ftrace_filter_open, |
2419 | .read = seq_read, | 2457 | .read = seq_read, |
2420 | .write = ftrace_filter_write, | 2458 | .write = ftrace_filter_write, |
2421 | .llseek = no_llseek, | 2459 | .llseek = ftrace_regex_lseek, |
2422 | .release = ftrace_filter_release, | 2460 | .release = ftrace_filter_release, |
2423 | }; | 2461 | }; |
2424 | 2462 | ||
@@ -2632,6 +2670,7 @@ static const struct file_operations ftrace_graph_fops = { | |||
2632 | .read = seq_read, | 2670 | .read = seq_read, |
2633 | .write = ftrace_graph_write, | 2671 | .write = ftrace_graph_write, |
2634 | .release = ftrace_graph_release, | 2672 | .release = ftrace_graph_release, |
2673 | .llseek = seq_lseek, | ||
2635 | }; | 2674 | }; |
2636 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 2675 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
2637 | 2676 | ||