diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-09-15 04:27:31 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-09-15 04:27:31 -0400 |
commit | 3aabae7d9dfaed60effe93662f02c19bafc18537 (patch) | |
tree | af94cdd69add07601d9f3f5988dfc1dc255e3886 /kernel/trace/ftrace.c | |
parent | 79e406d7b00ab2b261ae32a59f266fd3b7af6f29 (diff) | |
parent | 57c072c7113f54f9512624d6c665db6184448782 (diff) |
Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into perf/core
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 107 |
1 files changed, 78 insertions, 29 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 20aff3f1c719..65fb077ea79c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -1358,24 +1358,29 @@ enum { | |||
1358 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1358 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
1359 | 1359 | ||
1360 | struct ftrace_iterator { | 1360 | struct ftrace_iterator { |
1361 | struct ftrace_page *pg; | 1361 | loff_t pos; |
1362 | int hidx; | 1362 | loff_t func_pos; |
1363 | int idx; | 1363 | struct ftrace_page *pg; |
1364 | unsigned flags; | 1364 | struct dyn_ftrace *func; |
1365 | struct trace_parser parser; | 1365 | struct ftrace_func_probe *probe; |
1366 | struct trace_parser parser; | ||
1367 | int hidx; | ||
1368 | int idx; | ||
1369 | unsigned flags; | ||
1366 | }; | 1370 | }; |
1367 | 1371 | ||
1368 | static void * | 1372 | static void * |
1369 | t_hash_next(struct seq_file *m, void *v, loff_t *pos) | 1373 | t_hash_next(struct seq_file *m, loff_t *pos) |
1370 | { | 1374 | { |
1371 | struct ftrace_iterator *iter = m->private; | 1375 | struct ftrace_iterator *iter = m->private; |
1372 | struct hlist_node *hnd = v; | 1376 | struct hlist_node *hnd = NULL; |
1373 | struct hlist_head *hhd; | 1377 | struct hlist_head *hhd; |
1374 | 1378 | ||
1375 | WARN_ON(!(iter->flags & FTRACE_ITER_HASH)); | ||
1376 | |||
1377 | (*pos)++; | 1379 | (*pos)++; |
1380 | iter->pos = *pos; | ||
1378 | 1381 | ||
1382 | if (iter->probe) | ||
1383 | hnd = &iter->probe->node; | ||
1379 | retry: | 1384 | retry: |
1380 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) | 1385 | if (iter->hidx >= FTRACE_FUNC_HASHSIZE) |
1381 | return NULL; | 1386 | return NULL; |
@@ -1398,7 +1403,12 @@ t_hash_next(struct seq_file *m, void *v, loff_t *pos) | |||
1398 | } | 1403 | } |
1399 | } | 1404 | } |
1400 | 1405 | ||
1401 | return hnd; | 1406 | if (WARN_ON_ONCE(!hnd)) |
1407 | return NULL; | ||
1408 | |||
1409 | iter->probe = hlist_entry(hnd, struct ftrace_func_probe, node); | ||
1410 | |||
1411 | return iter; | ||
1402 | } | 1412 | } |
1403 | 1413 | ||
1404 | static void *t_hash_start(struct seq_file *m, loff_t *pos) | 1414 | static void *t_hash_start(struct seq_file *m, loff_t *pos) |
@@ -1407,26 +1417,32 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) | |||
1407 | void *p = NULL; | 1417 | void *p = NULL; |
1408 | loff_t l; | 1418 | loff_t l; |
1409 | 1419 | ||
1410 | if (!(iter->flags & FTRACE_ITER_HASH)) | 1420 | if (iter->func_pos > *pos) |
1411 | *pos = 0; | 1421 | return NULL; |
1412 | |||
1413 | iter->flags |= FTRACE_ITER_HASH; | ||
1414 | 1422 | ||
1415 | iter->hidx = 0; | 1423 | iter->hidx = 0; |
1416 | for (l = 0; l <= *pos; ) { | 1424 | for (l = 0; l <= (*pos - iter->func_pos); ) { |
1417 | p = t_hash_next(m, p, &l); | 1425 | p = t_hash_next(m, &l); |
1418 | if (!p) | 1426 | if (!p) |
1419 | break; | 1427 | break; |
1420 | } | 1428 | } |
1421 | return p; | 1429 | if (!p) |
1430 | return NULL; | ||
1431 | |||
1432 | /* Only set this if we have an item */ | ||
1433 | iter->flags |= FTRACE_ITER_HASH; | ||
1434 | |||
1435 | return iter; | ||
1422 | } | 1436 | } |
1423 | 1437 | ||
1424 | static int t_hash_show(struct seq_file *m, void *v) | 1438 | static int |
1439 | t_hash_show(struct seq_file *m, struct ftrace_iterator *iter) | ||
1425 | { | 1440 | { |
1426 | struct ftrace_func_probe *rec; | 1441 | struct ftrace_func_probe *rec; |
1427 | struct hlist_node *hnd = v; | ||
1428 | 1442 | ||
1429 | rec = hlist_entry(hnd, struct ftrace_func_probe, node); | 1443 | rec = iter->probe; |
1444 | if (WARN_ON_ONCE(!rec)) | ||
1445 | return -EIO; | ||
1430 | 1446 | ||
1431 | if (rec->ops->print) | 1447 | if (rec->ops->print) |
1432 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); | 1448 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); |
@@ -1447,12 +1463,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1447 | struct dyn_ftrace *rec = NULL; | 1463 | struct dyn_ftrace *rec = NULL; |
1448 | 1464 | ||
1449 | if (iter->flags & FTRACE_ITER_HASH) | 1465 | if (iter->flags & FTRACE_ITER_HASH) |
1450 | return t_hash_next(m, v, pos); | 1466 | return t_hash_next(m, pos); |
1451 | 1467 | ||
1452 | (*pos)++; | 1468 | (*pos)++; |
1469 | iter->pos = *pos; | ||
1453 | 1470 | ||
1454 | if (iter->flags & FTRACE_ITER_PRINTALL) | 1471 | if (iter->flags & FTRACE_ITER_PRINTALL) |
1455 | return NULL; | 1472 | return t_hash_start(m, pos); |
1456 | 1473 | ||
1457 | retry: | 1474 | retry: |
1458 | if (iter->idx >= iter->pg->index) { | 1475 | if (iter->idx >= iter->pg->index) { |
@@ -1481,7 +1498,20 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1481 | } | 1498 | } |
1482 | } | 1499 | } |
1483 | 1500 | ||
1484 | return rec; | 1501 | if (!rec) |
1502 | return t_hash_start(m, pos); | ||
1503 | |||
1504 | iter->func_pos = *pos; | ||
1505 | iter->func = rec; | ||
1506 | |||
1507 | return iter; | ||
1508 | } | ||
1509 | |||
1510 | static void reset_iter_read(struct ftrace_iterator *iter) | ||
1511 | { | ||
1512 | iter->pos = 0; | ||
1513 | iter->func_pos = 0; | ||
1514 | iter->flags &= ~(FTRACE_ITER_PRINTALL & FTRACE_ITER_HASH); | ||
1485 | } | 1515 | } |
1486 | 1516 | ||
1487 | static void *t_start(struct seq_file *m, loff_t *pos) | 1517 | static void *t_start(struct seq_file *m, loff_t *pos) |
@@ -1492,6 +1522,12 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1492 | 1522 | ||
1493 | mutex_lock(&ftrace_lock); | 1523 | mutex_lock(&ftrace_lock); |
1494 | /* | 1524 | /* |
1525 | * If an lseek was done, then reset and start from beginning. | ||
1526 | */ | ||
1527 | if (*pos < iter->pos) | ||
1528 | reset_iter_read(iter); | ||
1529 | |||
1530 | /* | ||
1495 | * For set_ftrace_filter reading, if we have the filter | 1531 | * For set_ftrace_filter reading, if we have the filter |
1496 | * off, we can short cut and just print out that all | 1532 | * off, we can short cut and just print out that all |
1497 | * functions are enabled. | 1533 | * functions are enabled. |
@@ -1500,12 +1536,19 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1500 | if (*pos > 0) | 1536 | if (*pos > 0) |
1501 | return t_hash_start(m, pos); | 1537 | return t_hash_start(m, pos); |
1502 | iter->flags |= FTRACE_ITER_PRINTALL; | 1538 | iter->flags |= FTRACE_ITER_PRINTALL; |
1539 | /* reset in case of seek/pread */ | ||
1540 | iter->flags &= ~FTRACE_ITER_HASH; | ||
1503 | return iter; | 1541 | return iter; |
1504 | } | 1542 | } |
1505 | 1543 | ||
1506 | if (iter->flags & FTRACE_ITER_HASH) | 1544 | if (iter->flags & FTRACE_ITER_HASH) |
1507 | return t_hash_start(m, pos); | 1545 | return t_hash_start(m, pos); |
1508 | 1546 | ||
1547 | /* | ||
1548 | * Unfortunately, we need to restart at ftrace_pages_start | ||
1549 | * every time we let go of the ftrace_mutex. This is because | ||
1550 | * those pointers can change without the lock. | ||
1551 | */ | ||
1509 | iter->pg = ftrace_pages_start; | 1552 | iter->pg = ftrace_pages_start; |
1510 | iter->idx = 0; | 1553 | iter->idx = 0; |
1511 | for (l = 0; l <= *pos; ) { | 1554 | for (l = 0; l <= *pos; ) { |
@@ -1514,10 +1557,14 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1514 | break; | 1557 | break; |
1515 | } | 1558 | } |
1516 | 1559 | ||
1517 | if (!p && iter->flags & FTRACE_ITER_FILTER) | 1560 | if (!p) { |
1518 | return t_hash_start(m, pos); | 1561 | if (iter->flags & FTRACE_ITER_FILTER) |
1562 | return t_hash_start(m, pos); | ||
1519 | 1563 | ||
1520 | return p; | 1564 | return NULL; |
1565 | } | ||
1566 | |||
1567 | return iter; | ||
1521 | } | 1568 | } |
1522 | 1569 | ||
1523 | static void t_stop(struct seq_file *m, void *p) | 1570 | static void t_stop(struct seq_file *m, void *p) |
@@ -1528,16 +1575,18 @@ static void t_stop(struct seq_file *m, void *p) | |||
1528 | static int t_show(struct seq_file *m, void *v) | 1575 | static int t_show(struct seq_file *m, void *v) |
1529 | { | 1576 | { |
1530 | struct ftrace_iterator *iter = m->private; | 1577 | struct ftrace_iterator *iter = m->private; |
1531 | struct dyn_ftrace *rec = v; | 1578 | struct dyn_ftrace *rec; |
1532 | 1579 | ||
1533 | if (iter->flags & FTRACE_ITER_HASH) | 1580 | if (iter->flags & FTRACE_ITER_HASH) |
1534 | return t_hash_show(m, v); | 1581 | return t_hash_show(m, iter); |
1535 | 1582 | ||
1536 | if (iter->flags & FTRACE_ITER_PRINTALL) { | 1583 | if (iter->flags & FTRACE_ITER_PRINTALL) { |
1537 | seq_printf(m, "#### all functions enabled ####\n"); | 1584 | seq_printf(m, "#### all functions enabled ####\n"); |
1538 | return 0; | 1585 | return 0; |
1539 | } | 1586 | } |
1540 | 1587 | ||
1588 | rec = iter->func; | ||
1589 | |||
1541 | if (!rec) | 1590 | if (!rec) |
1542 | return 0; | 1591 | return 0; |
1543 | 1592 | ||
@@ -2406,7 +2455,7 @@ static const struct file_operations ftrace_filter_fops = { | |||
2406 | .open = ftrace_filter_open, | 2455 | .open = ftrace_filter_open, |
2407 | .read = seq_read, | 2456 | .read = seq_read, |
2408 | .write = ftrace_filter_write, | 2457 | .write = ftrace_filter_write, |
2409 | .llseek = no_llseek, | 2458 | .llseek = ftrace_regex_lseek, |
2410 | .release = ftrace_filter_release, | 2459 | .release = ftrace_filter_release, |
2411 | }; | 2460 | }; |
2412 | 2461 | ||