diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/ftrace.c | 43 |
1 files changed, 28 insertions, 15 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 37f9e90d241c..92376aeac4a7 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -1507,25 +1507,38 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec) | |||
| 1507 | static void ftrace_remove_tramp(struct ftrace_ops *ops, | 1507 | static void ftrace_remove_tramp(struct ftrace_ops *ops, |
| 1508 | struct dyn_ftrace *rec) | 1508 | struct dyn_ftrace *rec) |
| 1509 | { | 1509 | { |
| 1510 | struct ftrace_func_entry *entry; | 1510 | /* If TRAMP is not set, no ops should have a trampoline for this */ |
| 1511 | 1511 | if (!(rec->flags & FTRACE_FL_TRAMP)) | |
| 1512 | entry = ftrace_lookup_ip(ops->tramp_hash, rec->ip); | ||
| 1513 | if (!entry) | ||
| 1514 | return; | 1512 | return; |
| 1515 | 1513 | ||
| 1514 | rec->flags &= ~FTRACE_FL_TRAMP; | ||
| 1515 | |||
| 1516 | if ((!ftrace_hash_empty(ops->func_hash->filter_hash) && | ||
| 1517 | !ftrace_lookup_ip(ops->func_hash->filter_hash, rec->ip)) || | ||
| 1518 | ftrace_lookup_ip(ops->func_hash->notrace_hash, rec->ip)) | ||
| 1519 | return; | ||
| 1516 | /* | 1520 | /* |
| 1517 | * The tramp_hash entry will be removed at time | 1521 | * The tramp_hash entry will be removed at time |
| 1518 | * of update. | 1522 | * of update. |
| 1519 | */ | 1523 | */ |
| 1520 | ops->nr_trampolines--; | 1524 | ops->nr_trampolines--; |
| 1521 | rec->flags &= ~FTRACE_FL_TRAMP; | ||
| 1522 | } | 1525 | } |
| 1523 | 1526 | ||
| 1524 | static void ftrace_clear_tramps(struct dyn_ftrace *rec) | 1527 | static void ftrace_clear_tramps(struct dyn_ftrace *rec, struct ftrace_ops *ops) |
| 1525 | { | 1528 | { |
| 1526 | struct ftrace_ops *op; | 1529 | struct ftrace_ops *op; |
| 1527 | 1530 | ||
| 1531 | /* If TRAMP is not set, no ops should have a trampoline for this */ | ||
| 1532 | if (!(rec->flags & FTRACE_FL_TRAMP)) | ||
| 1533 | return; | ||
| 1534 | |||
| 1528 | do_for_each_ftrace_op(op, ftrace_ops_list) { | 1535 | do_for_each_ftrace_op(op, ftrace_ops_list) { |
| 1536 | /* | ||
| 1537 | * This function is called to clear other tramps | ||
| 1538 | * not the one that is being updated. | ||
| 1539 | */ | ||
| 1540 | if (op == ops) | ||
| 1541 | continue; | ||
| 1529 | if (op->nr_trampolines) | 1542 | if (op->nr_trampolines) |
| 1530 | ftrace_remove_tramp(op, rec); | 1543 | ftrace_remove_tramp(op, rec); |
| 1531 | } while_for_each_ftrace_op(op); | 1544 | } while_for_each_ftrace_op(op); |
| @@ -1626,13 +1639,10 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, | |||
| 1626 | /* | 1639 | /* |
| 1627 | * If we are adding another function callback | 1640 | * If we are adding another function callback |
| 1628 | * to this function, and the previous had a | 1641 | * to this function, and the previous had a |
| 1629 | * trampoline used, then we need to go back to | 1642 | * custom trampoline in use, then we need to go |
| 1630 | * the default trampoline. | 1643 | * back to the default trampoline. |
| 1631 | */ | 1644 | */ |
| 1632 | rec->flags &= ~FTRACE_FL_TRAMP; | 1645 | ftrace_clear_tramps(rec, ops); |
| 1633 | |||
| 1634 | /* remove trampolines from any ops for this rec */ | ||
| 1635 | ftrace_clear_tramps(rec); | ||
| 1636 | } | 1646 | } |
| 1637 | 1647 | ||
| 1638 | /* | 1648 | /* |
| @@ -1935,8 +1945,8 @@ unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec) | |||
| 1935 | if (rec->flags & FTRACE_FL_TRAMP) { | 1945 | if (rec->flags & FTRACE_FL_TRAMP) { |
| 1936 | ops = ftrace_find_tramp_ops_new(rec); | 1946 | ops = ftrace_find_tramp_ops_new(rec); |
| 1937 | if (FTRACE_WARN_ON(!ops || !ops->trampoline)) { | 1947 | if (FTRACE_WARN_ON(!ops || !ops->trampoline)) { |
| 1938 | pr_warning("Bad trampoline accounting at: %p (%pS)\n", | 1948 | pr_warn("Bad trampoline accounting at: %p (%pS) (%lx)\n", |
| 1939 | (void *)rec->ip, (void *)rec->ip); | 1949 | (void *)rec->ip, (void *)rec->ip, rec->flags); |
| 1940 | /* Ftrace is shutting down, return anything */ | 1950 | /* Ftrace is shutting down, return anything */ |
| 1941 | return (unsigned long)FTRACE_ADDR; | 1951 | return (unsigned long)FTRACE_ADDR; |
| 1942 | } | 1952 | } |
| @@ -2266,7 +2276,10 @@ static int ftrace_save_ops_tramp_hash(struct ftrace_ops *ops) | |||
| 2266 | } while_for_each_ftrace_rec(); | 2276 | } while_for_each_ftrace_rec(); |
| 2267 | 2277 | ||
| 2268 | /* The number of recs in the hash must match nr_trampolines */ | 2278 | /* The number of recs in the hash must match nr_trampolines */ |
| 2269 | FTRACE_WARN_ON(ops->tramp_hash->count != ops->nr_trampolines); | 2279 | if (FTRACE_WARN_ON(ops->tramp_hash->count != ops->nr_trampolines)) |
| 2280 | pr_warn("count=%ld trampolines=%d\n", | ||
| 2281 | ops->tramp_hash->count, | ||
| 2282 | ops->nr_trampolines); | ||
| 2270 | 2283 | ||
| 2271 | return 0; | 2284 | return 0; |
| 2272 | } | 2285 | } |
