diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/ftrace.c | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index c8db0dbb984..2d51166b93f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -1368,6 +1368,7 @@ enum { | |||
1368 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1368 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
1369 | 1369 | ||
1370 | struct ftrace_iterator { | 1370 | struct ftrace_iterator { |
1371 | loff_t pos; | ||
1371 | loff_t func_pos; | 1372 | loff_t func_pos; |
1372 | struct ftrace_page *pg; | 1373 | struct ftrace_page *pg; |
1373 | struct dyn_ftrace *func; | 1374 | struct dyn_ftrace *func; |
@@ -1385,9 +1386,8 @@ t_hash_next(struct seq_file *m, loff_t *pos) | |||
1385 | struct hlist_node *hnd = NULL; | 1386 | struct hlist_node *hnd = NULL; |
1386 | struct hlist_head *hhd; | 1387 | struct hlist_head *hhd; |
1387 | 1388 | ||
1388 | WARN_ON(!(iter->flags & FTRACE_ITER_HASH)); | ||
1389 | |||
1390 | (*pos)++; | 1389 | (*pos)++; |
1390 | iter->pos = *pos; | ||
1391 | 1391 | ||
1392 | if (iter->probe) | 1392 | if (iter->probe) |
1393 | hnd = &iter->probe->node; | 1393 | hnd = &iter->probe->node; |
@@ -1427,14 +1427,9 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) | |||
1427 | void *p = NULL; | 1427 | void *p = NULL; |
1428 | loff_t l; | 1428 | loff_t l; |
1429 | 1429 | ||
1430 | if (!(iter->flags & FTRACE_ITER_HASH)) | ||
1431 | iter->func_pos = *pos; | ||
1432 | |||
1433 | if (iter->func_pos > *pos) | 1430 | if (iter->func_pos > *pos) |
1434 | return NULL; | 1431 | return NULL; |
1435 | 1432 | ||
1436 | iter->flags |= FTRACE_ITER_HASH; | ||
1437 | |||
1438 | iter->hidx = 0; | 1433 | iter->hidx = 0; |
1439 | for (l = 0; l <= (*pos - iter->func_pos); ) { | 1434 | for (l = 0; l <= (*pos - iter->func_pos); ) { |
1440 | p = t_hash_next(m, &l); | 1435 | p = t_hash_next(m, &l); |
@@ -1444,6 +1439,9 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) | |||
1444 | if (!p) | 1439 | if (!p) |
1445 | return NULL; | 1440 | return NULL; |
1446 | 1441 | ||
1442 | /* Only set this if we have an item */ | ||
1443 | iter->flags |= FTRACE_ITER_HASH; | ||
1444 | |||
1447 | return iter; | 1445 | return iter; |
1448 | } | 1446 | } |
1449 | 1447 | ||
@@ -1478,6 +1476,8 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1478 | return t_hash_next(m, pos); | 1476 | return t_hash_next(m, pos); |
1479 | 1477 | ||
1480 | (*pos)++; | 1478 | (*pos)++; |
1479 | iter->pos = *pos; | ||
1480 | iter->func_pos = *pos; | ||
1481 | 1481 | ||
1482 | if (iter->flags & FTRACE_ITER_PRINTALL) | 1482 | if (iter->flags & FTRACE_ITER_PRINTALL) |
1483 | return NULL; | 1483 | return NULL; |
@@ -1517,6 +1517,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1517 | return iter; | 1517 | return iter; |
1518 | } | 1518 | } |
1519 | 1519 | ||
1520 | static void reset_iter_read(struct ftrace_iterator *iter) | ||
1521 | { | ||
1522 | iter->pos = 0; | ||
1523 | iter->func_pos = 0; | ||
1524 | iter->flags &= ~(FTRACE_ITER_PRINTALL & FTRACE_ITER_HASH); | ||
1525 | } | ||
1526 | |||
1520 | static void *t_start(struct seq_file *m, loff_t *pos) | 1527 | static void *t_start(struct seq_file *m, loff_t *pos) |
1521 | { | 1528 | { |
1522 | struct ftrace_iterator *iter = m->private; | 1529 | struct ftrace_iterator *iter = m->private; |
@@ -1525,6 +1532,12 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1525 | 1532 | ||
1526 | mutex_lock(&ftrace_lock); | 1533 | mutex_lock(&ftrace_lock); |
1527 | /* | 1534 | /* |
1535 | * If an lseek was done, then reset and start from beginning. | ||
1536 | */ | ||
1537 | if (*pos < iter->pos) | ||
1538 | reset_iter_read(iter); | ||
1539 | |||
1540 | /* | ||
1528 | * For set_ftrace_filter reading, if we have the filter | 1541 | * For set_ftrace_filter reading, if we have the filter |
1529 | * off, we can short cut and just print out that all | 1542 | * off, we can short cut and just print out that all |
1530 | * functions are enabled. | 1543 | * functions are enabled. |
@@ -1541,6 +1554,11 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1541 | if (iter->flags & FTRACE_ITER_HASH) | 1554 | if (iter->flags & FTRACE_ITER_HASH) |
1542 | return t_hash_start(m, pos); | 1555 | return t_hash_start(m, pos); |
1543 | 1556 | ||
1557 | /* | ||
1558 | * Unfortunately, we need to restart at ftrace_pages_start | ||
1559 | * every time we let go of the ftrace_mutex. This is because | ||
1560 | * those pointers can change without the lock. | ||
1561 | */ | ||
1544 | iter->pg = ftrace_pages_start; | 1562 | iter->pg = ftrace_pages_start; |
1545 | iter->idx = 0; | 1563 | iter->idx = 0; |
1546 | for (l = 0; l <= *pos; ) { | 1564 | for (l = 0; l <= *pos; ) { |
@@ -2447,7 +2465,7 @@ static const struct file_operations ftrace_filter_fops = { | |||
2447 | .open = ftrace_filter_open, | 2465 | .open = ftrace_filter_open, |
2448 | .read = seq_read, | 2466 | .read = seq_read, |
2449 | .write = ftrace_filter_write, | 2467 | .write = ftrace_filter_write, |
2450 | .llseek = no_llseek, | 2468 | .llseek = ftrace_regex_lseek, |
2451 | .release = ftrace_filter_release, | 2469 | .release = ftrace_filter_release, |
2452 | }; | 2470 | }; |
2453 | 2471 | ||