diff options
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/Kconfig | 30 | ||||
| -rw-r--r-- | kernel/trace/Makefile | 3 | ||||
| -rw-r--r-- | kernel/trace/ftrace.c | 267 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 441 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 46 | ||||
| -rw-r--r-- | kernel/trace/trace_benchmark.c | 198 | ||||
| -rw-r--r-- | kernel/trace/trace_benchmark.h | 41 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 13 | ||||
| -rw-r--r-- | kernel/trace/trace_functions.c | 56 | ||||
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 19 | ||||
| -rw-r--r-- | kernel/trace/trace_irqsoff.c | 71 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_nop.c | 1 | ||||
| -rw-r--r-- | kernel/trace/trace_output.c | 41 | ||||
| -rw-r--r-- | kernel/trace/trace_sched_wakeup.c | 70 | ||||
| -rw-r--r-- | kernel/trace/trace_selftest.c | 69 | ||||
| -rw-r--r-- | kernel/trace/trace_stack.c | 42 |
17 files changed, 951 insertions, 460 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 8639819f6cef..d4409356f40d 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
| @@ -535,6 +535,36 @@ config MMIOTRACE_TEST | |||
| 535 | 535 | ||
| 536 | Say N, unless you absolutely know what you are doing. | 536 | Say N, unless you absolutely know what you are doing. |
| 537 | 537 | ||
| 538 | config TRACEPOINT_BENCHMARK | ||
| 539 | bool "Add tracepoint that benchmarks tracepoints" | ||
| 540 | help | ||
| 541 | This option creates the tracepoint "benchmark:benchmark_event". | ||
| 542 | When the tracepoint is enabled, it kicks off a kernel thread that | ||
| 543 | goes into an infinite loop (calling cond_sched() to let other tasks | ||
| 544 | run), and calls the tracepoint. Each iteration will record the time | ||
| 545 | it took to write to the tracepoint and the next iteration that | ||
| 546 | data will be passed to the tracepoint itself. That is, the tracepoint | ||
| 547 | will report the time it took to do the previous tracepoint. | ||
| 548 | The string written to the tracepoint is a static string of 128 bytes | ||
| 549 | to keep the time the same. The initial string is simply a write of | ||
| 550 | "START". The second string records the cold cache time of the first | ||
| 551 | write which is not added to the rest of the calculations. | ||
| 552 | |||
| 553 | As it is a tight loop, it benchmarks as hot cache. That's fine because | ||
| 554 | we care most about hot paths that are probably in cache already. | ||
| 555 | |||
| 556 | An example of the output: | ||
| 557 | |||
| 558 | START | ||
| 559 | first=3672 [COLD CACHED] | ||
| 560 | last=632 first=3672 max=632 min=632 avg=316 std=446 std^2=199712 | ||
| 561 | last=278 first=3672 max=632 min=278 avg=303 std=316 std^2=100337 | ||
| 562 | last=277 first=3672 max=632 min=277 avg=296 std=258 std^2=67064 | ||
| 563 | last=273 first=3672 max=632 min=273 avg=292 std=224 std^2=50411 | ||
| 564 | last=273 first=3672 max=632 min=273 avg=288 std=200 std^2=40389 | ||
| 565 | last=281 first=3672 max=632 min=273 avg=287 std=183 std^2=33666 | ||
| 566 | |||
| 567 | |||
| 538 | config RING_BUFFER_BENCHMARK | 568 | config RING_BUFFER_BENCHMARK |
| 539 | tristate "Ring buffer benchmark stress tester" | 569 | tristate "Ring buffer benchmark stress tester" |
| 540 | depends on RING_BUFFER | 570 | depends on RING_BUFFER |
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index 1378e84fbe39..2611613f14f1 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile | |||
| @@ -17,6 +17,7 @@ ifdef CONFIG_TRACING_BRANCHES | |||
| 17 | KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING | 17 | KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING |
| 18 | endif | 18 | endif |
| 19 | 19 | ||
| 20 | CFLAGS_trace_benchmark.o := -I$(src) | ||
| 20 | CFLAGS_trace_events_filter.o := -I$(src) | 21 | CFLAGS_trace_events_filter.o := -I$(src) |
| 21 | 22 | ||
| 22 | obj-$(CONFIG_TRACE_CLOCK) += trace_clock.o | 23 | obj-$(CONFIG_TRACE_CLOCK) += trace_clock.o |
| @@ -62,4 +63,6 @@ endif | |||
| 62 | obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o | 63 | obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o |
| 63 | obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o | 64 | obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o |
| 64 | 65 | ||
| 66 | obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o | ||
| 67 | |||
| 65 | libftrace-y := ftrace.o | 68 | libftrace-y := ftrace.o |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 4a54a25afa2f..5b372e3ed675 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -62,7 +62,7 @@ | |||
| 62 | #define FTRACE_HASH_DEFAULT_BITS 10 | 62 | #define FTRACE_HASH_DEFAULT_BITS 10 |
| 63 | #define FTRACE_HASH_MAX_BITS 12 | 63 | #define FTRACE_HASH_MAX_BITS 12 |
| 64 | 64 | ||
| 65 | #define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_CONTROL) | 65 | #define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_CONTROL) |
| 66 | 66 | ||
| 67 | #ifdef CONFIG_DYNAMIC_FTRACE | 67 | #ifdef CONFIG_DYNAMIC_FTRACE |
| 68 | #define INIT_REGEX_LOCK(opsname) \ | 68 | #define INIT_REGEX_LOCK(opsname) \ |
| @@ -103,7 +103,6 @@ static int ftrace_disabled __read_mostly; | |||
| 103 | 103 | ||
| 104 | static DEFINE_MUTEX(ftrace_lock); | 104 | static DEFINE_MUTEX(ftrace_lock); |
| 105 | 105 | ||
| 106 | static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end; | ||
| 107 | static struct ftrace_ops *ftrace_control_list __read_mostly = &ftrace_list_end; | 106 | static struct ftrace_ops *ftrace_control_list __read_mostly = &ftrace_list_end; |
| 108 | static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end; | 107 | static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end; |
| 109 | ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | 108 | ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; |
| @@ -171,23 +170,6 @@ int ftrace_nr_registered_ops(void) | |||
| 171 | return cnt; | 170 | return cnt; |
| 172 | } | 171 | } |
| 173 | 172 | ||
| 174 | static void | ||
| 175 | ftrace_global_list_func(unsigned long ip, unsigned long parent_ip, | ||
| 176 | struct ftrace_ops *op, struct pt_regs *regs) | ||
| 177 | { | ||
| 178 | int bit; | ||
| 179 | |||
| 180 | bit = trace_test_and_set_recursion(TRACE_GLOBAL_START, TRACE_GLOBAL_MAX); | ||
| 181 | if (bit < 0) | ||
| 182 | return; | ||
| 183 | |||
| 184 | do_for_each_ftrace_op(op, ftrace_global_list) { | ||
| 185 | op->func(ip, parent_ip, op, regs); | ||
| 186 | } while_for_each_ftrace_op(op); | ||
| 187 | |||
| 188 | trace_clear_recursion(bit); | ||
| 189 | } | ||
| 190 | |||
| 191 | static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, | 173 | static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, |
| 192 | struct ftrace_ops *op, struct pt_regs *regs) | 174 | struct ftrace_ops *op, struct pt_regs *regs) |
| 193 | { | 175 | { |
| @@ -237,43 +219,6 @@ static int control_ops_alloc(struct ftrace_ops *ops) | |||
| 237 | return 0; | 219 | return 0; |
| 238 | } | 220 | } |
| 239 | 221 | ||
| 240 | static void update_global_ops(void) | ||
| 241 | { | ||
| 242 | ftrace_func_t func = ftrace_global_list_func; | ||
| 243 | void *private = NULL; | ||
| 244 | |||
| 245 | /* The list has its own recursion protection. */ | ||
| 246 | global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE; | ||
| 247 | |||
| 248 | /* | ||
| 249 | * If there's only one function registered, then call that | ||
| 250 | * function directly. Otherwise, we need to iterate over the | ||
| 251 | * registered callers. | ||
| 252 | */ | ||
| 253 | if (ftrace_global_list == &ftrace_list_end || | ||
| 254 | ftrace_global_list->next == &ftrace_list_end) { | ||
| 255 | func = ftrace_global_list->func; | ||
| 256 | private = ftrace_global_list->private; | ||
| 257 | /* | ||
| 258 | * As we are calling the function directly. | ||
| 259 | * If it does not have recursion protection, | ||
| 260 | * the function_trace_op needs to be updated | ||
| 261 | * accordingly. | ||
| 262 | */ | ||
| 263 | if (!(ftrace_global_list->flags & FTRACE_OPS_FL_RECURSION_SAFE)) | ||
| 264 | global_ops.flags &= ~FTRACE_OPS_FL_RECURSION_SAFE; | ||
| 265 | } | ||
| 266 | |||
| 267 | /* If we filter on pids, update to use the pid function */ | ||
| 268 | if (!list_empty(&ftrace_pids)) { | ||
| 269 | set_ftrace_pid_function(func); | ||
| 270 | func = ftrace_pid_func; | ||
| 271 | } | ||
| 272 | |||
| 273 | global_ops.func = func; | ||
| 274 | global_ops.private = private; | ||
| 275 | } | ||
| 276 | |||
| 277 | static void ftrace_sync(struct work_struct *work) | 222 | static void ftrace_sync(struct work_struct *work) |
| 278 | { | 223 | { |
| 279 | /* | 224 | /* |
| @@ -301,8 +246,6 @@ static void update_ftrace_function(void) | |||
| 301 | { | 246 | { |
| 302 | ftrace_func_t func; | 247 | ftrace_func_t func; |
| 303 | 248 | ||
| 304 | update_global_ops(); | ||
| 305 | |||
| 306 | /* | 249 | /* |
| 307 | * If we are at the end of the list and this ops is | 250 | * If we are at the end of the list and this ops is |
| 308 | * recursion safe and not dynamic and the arch supports passing ops, | 251 | * recursion safe and not dynamic and the arch supports passing ops, |
| @@ -314,10 +257,7 @@ static void update_ftrace_function(void) | |||
| 314 | (ftrace_ops_list->flags & FTRACE_OPS_FL_RECURSION_SAFE) && | 257 | (ftrace_ops_list->flags & FTRACE_OPS_FL_RECURSION_SAFE) && |
| 315 | !FTRACE_FORCE_LIST_FUNC)) { | 258 | !FTRACE_FORCE_LIST_FUNC)) { |
| 316 | /* Set the ftrace_ops that the arch callback uses */ | 259 | /* Set the ftrace_ops that the arch callback uses */ |
| 317 | if (ftrace_ops_list == &global_ops) | 260 | set_function_trace_op = ftrace_ops_list; |
| 318 | set_function_trace_op = ftrace_global_list; | ||
| 319 | else | ||
| 320 | set_function_trace_op = ftrace_ops_list; | ||
| 321 | func = ftrace_ops_list->func; | 261 | func = ftrace_ops_list->func; |
| 322 | } else { | 262 | } else { |
| 323 | /* Just use the default ftrace_ops */ | 263 | /* Just use the default ftrace_ops */ |
| @@ -373,6 +313,11 @@ static void update_ftrace_function(void) | |||
| 373 | ftrace_trace_function = func; | 313 | ftrace_trace_function = func; |
| 374 | } | 314 | } |
| 375 | 315 | ||
| 316 | int using_ftrace_ops_list_func(void) | ||
| 317 | { | ||
| 318 | return ftrace_trace_function == ftrace_ops_list_func; | ||
| 319 | } | ||
| 320 | |||
| 376 | static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops) | 321 | static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops) |
| 377 | { | 322 | { |
| 378 | ops->next = *list; | 323 | ops->next = *list; |
| @@ -434,16 +379,9 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
| 434 | if (ops->flags & FTRACE_OPS_FL_DELETED) | 379 | if (ops->flags & FTRACE_OPS_FL_DELETED) |
| 435 | return -EINVAL; | 380 | return -EINVAL; |
| 436 | 381 | ||
| 437 | if (FTRACE_WARN_ON(ops == &global_ops)) | ||
| 438 | return -EINVAL; | ||
| 439 | |||
| 440 | if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED)) | 382 | if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED)) |
| 441 | return -EBUSY; | 383 | return -EBUSY; |
| 442 | 384 | ||
| 443 | /* We don't support both control and global flags set. */ | ||
| 444 | if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK) | ||
| 445 | return -EINVAL; | ||
| 446 | |||
| 447 | #ifndef CONFIG_DYNAMIC_FTRACE_WITH_REGS | 385 | #ifndef CONFIG_DYNAMIC_FTRACE_WITH_REGS |
| 448 | /* | 386 | /* |
| 449 | * If the ftrace_ops specifies SAVE_REGS, then it only can be used | 387 | * If the ftrace_ops specifies SAVE_REGS, then it only can be used |
| @@ -461,10 +399,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
| 461 | if (!core_kernel_data((unsigned long)ops)) | 399 | if (!core_kernel_data((unsigned long)ops)) |
| 462 | ops->flags |= FTRACE_OPS_FL_DYNAMIC; | 400 | ops->flags |= FTRACE_OPS_FL_DYNAMIC; |
| 463 | 401 | ||
| 464 | if (ops->flags & FTRACE_OPS_FL_GLOBAL) { | 402 | if (ops->flags & FTRACE_OPS_FL_CONTROL) { |
| 465 | add_ftrace_list_ops(&ftrace_global_list, &global_ops, ops); | ||
| 466 | ops->flags |= FTRACE_OPS_FL_ENABLED; | ||
| 467 | } else if (ops->flags & FTRACE_OPS_FL_CONTROL) { | ||
| 468 | if (control_ops_alloc(ops)) | 403 | if (control_ops_alloc(ops)) |
| 469 | return -ENOMEM; | 404 | return -ENOMEM; |
| 470 | add_ftrace_list_ops(&ftrace_control_list, &control_ops, ops); | 405 | add_ftrace_list_ops(&ftrace_control_list, &control_ops, ops); |
| @@ -484,15 +419,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
| 484 | if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED))) | 419 | if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED))) |
| 485 | return -EBUSY; | 420 | return -EBUSY; |
| 486 | 421 | ||
| 487 | if (FTRACE_WARN_ON(ops == &global_ops)) | 422 | if (ops->flags & FTRACE_OPS_FL_CONTROL) { |
| 488 | return -EINVAL; | ||
| 489 | |||
| 490 | if (ops->flags & FTRACE_OPS_FL_GLOBAL) { | ||
| 491 | ret = remove_ftrace_list_ops(&ftrace_global_list, | ||
| 492 | &global_ops, ops); | ||
| 493 | if (!ret) | ||
| 494 | ops->flags &= ~FTRACE_OPS_FL_ENABLED; | ||
| 495 | } else if (ops->flags & FTRACE_OPS_FL_CONTROL) { | ||
| 496 | ret = remove_ftrace_list_ops(&ftrace_control_list, | 423 | ret = remove_ftrace_list_ops(&ftrace_control_list, |
| 497 | &control_ops, ops); | 424 | &control_ops, ops); |
| 498 | } else | 425 | } else |
| @@ -895,7 +822,7 @@ function_profile_call(unsigned long ip, unsigned long parent_ip, | |||
| 895 | 822 | ||
| 896 | local_irq_save(flags); | 823 | local_irq_save(flags); |
| 897 | 824 | ||
| 898 | stat = &__get_cpu_var(ftrace_profile_stats); | 825 | stat = this_cpu_ptr(&ftrace_profile_stats); |
| 899 | if (!stat->hash || !ftrace_profile_enabled) | 826 | if (!stat->hash || !ftrace_profile_enabled) |
| 900 | goto out; | 827 | goto out; |
| 901 | 828 | ||
| @@ -926,7 +853,7 @@ static void profile_graph_return(struct ftrace_graph_ret *trace) | |||
| 926 | unsigned long flags; | 853 | unsigned long flags; |
| 927 | 854 | ||
| 928 | local_irq_save(flags); | 855 | local_irq_save(flags); |
| 929 | stat = &__get_cpu_var(ftrace_profile_stats); | 856 | stat = this_cpu_ptr(&ftrace_profile_stats); |
| 930 | if (!stat->hash || !ftrace_profile_enabled) | 857 | if (!stat->hash || !ftrace_profile_enabled) |
| 931 | goto out; | 858 | goto out; |
| 932 | 859 | ||
| @@ -1178,7 +1105,7 @@ struct ftrace_page { | |||
| 1178 | static struct ftrace_page *ftrace_pages_start; | 1105 | static struct ftrace_page *ftrace_pages_start; |
| 1179 | static struct ftrace_page *ftrace_pages; | 1106 | static struct ftrace_page *ftrace_pages; |
| 1180 | 1107 | ||
| 1181 | static bool ftrace_hash_empty(struct ftrace_hash *hash) | 1108 | static bool __always_inline ftrace_hash_empty(struct ftrace_hash *hash) |
| 1182 | { | 1109 | { |
| 1183 | return !hash || !hash->count; | 1110 | return !hash || !hash->count; |
| 1184 | } | 1111 | } |
| @@ -1625,7 +1552,14 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, | |||
| 1625 | in_other_hash = !!ftrace_lookup_ip(other_hash, rec->ip); | 1552 | in_other_hash = !!ftrace_lookup_ip(other_hash, rec->ip); |
| 1626 | 1553 | ||
| 1627 | /* | 1554 | /* |
| 1555 | * If filter_hash is set, we want to match all functions | ||
| 1556 | * that are in the hash but not in the other hash. | ||
| 1628 | * | 1557 | * |
| 1558 | * If filter_hash is not set, then we are decrementing. | ||
| 1559 | * That means we match anything that is in the hash | ||
| 1560 | * and also in the other_hash. That is, we need to turn | ||
| 1561 | * off functions in the other hash because they are disabled | ||
| 1562 | * by this hash. | ||
| 1629 | */ | 1563 | */ |
| 1630 | if (filter_hash && in_hash && !in_other_hash) | 1564 | if (filter_hash && in_hash && !in_other_hash) |
| 1631 | match = 1; | 1565 | match = 1; |
| @@ -1767,19 +1701,15 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update) | |||
| 1767 | /* | 1701 | /* |
| 1768 | * If this record is being updated from a nop, then | 1702 | * If this record is being updated from a nop, then |
| 1769 | * return UPDATE_MAKE_CALL. | 1703 | * return UPDATE_MAKE_CALL. |
| 1770 | * Otherwise, if the EN flag is set, then return | ||
| 1771 | * UPDATE_MODIFY_CALL_REGS to tell the caller to convert | ||
| 1772 | * from the non-save regs, to a save regs function. | ||
| 1773 | * Otherwise, | 1704 | * Otherwise, |
| 1774 | * return UPDATE_MODIFY_CALL to tell the caller to convert | 1705 | * return UPDATE_MODIFY_CALL to tell the caller to convert |
| 1775 | * from the save regs, to a non-save regs function. | 1706 | * from the save regs, to a non-save regs function or |
| 1707 | * vice versa. | ||
| 1776 | */ | 1708 | */ |
| 1777 | if (flag & FTRACE_FL_ENABLED) | 1709 | if (flag & FTRACE_FL_ENABLED) |
| 1778 | return FTRACE_UPDATE_MAKE_CALL; | 1710 | return FTRACE_UPDATE_MAKE_CALL; |
| 1779 | else if (rec->flags & FTRACE_FL_REGS_EN) | 1711 | |
| 1780 | return FTRACE_UPDATE_MODIFY_CALL_REGS; | 1712 | return FTRACE_UPDATE_MODIFY_CALL; |
| 1781 | else | ||
| 1782 | return FTRACE_UPDATE_MODIFY_CALL; | ||
| 1783 | } | 1713 | } |
| 1784 | 1714 | ||
| 1785 | if (update) { | 1715 | if (update) { |
| @@ -1821,6 +1751,42 @@ int ftrace_test_record(struct dyn_ftrace *rec, int enable) | |||
| 1821 | return ftrace_check_record(rec, enable, 0); | 1751 | return ftrace_check_record(rec, enable, 0); |
| 1822 | } | 1752 | } |
| 1823 | 1753 | ||
| 1754 | /** | ||
| 1755 | * ftrace_get_addr_new - Get the call address to set to | ||
| 1756 | * @rec: The ftrace record descriptor | ||
| 1757 | * | ||
| 1758 | * If the record has the FTRACE_FL_REGS set, that means that it | ||
| 1759 | * wants to convert to a callback that saves all regs. If FTRACE_FL_REGS | ||
| 1760 | * is not not set, then it wants to convert to the normal callback. | ||
| 1761 | * | ||
| 1762 | * Returns the address of the trampoline to set to | ||
| 1763 | */ | ||
| 1764 | unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec) | ||
| 1765 | { | ||
| 1766 | if (rec->flags & FTRACE_FL_REGS) | ||
| 1767 | return (unsigned long)FTRACE_REGS_ADDR; | ||
| 1768 | else | ||
| 1769 | return (unsigned long)FTRACE_ADDR; | ||
| 1770 | } | ||
| 1771 | |||
| 1772 | /** | ||
| 1773 | * ftrace_get_addr_curr - Get the call address that is already there | ||
| 1774 | * @rec: The ftrace record descriptor | ||
| 1775 | * | ||
| 1776 | * The FTRACE_FL_REGS_EN is set when the record already points to | ||
| 1777 | * a function that saves all the regs. Basically the '_EN' version | ||
| 1778 | * represents the current state of the function. | ||
| 1779 | * | ||
| 1780 | * Returns the address of the trampoline that is currently being called | ||
| 1781 | */ | ||
| 1782 | unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec) | ||
| 1783 | { | ||
| 1784 | if (rec->flags & FTRACE_FL_REGS_EN) | ||
| 1785 | return (unsigned long)FTRACE_REGS_ADDR; | ||
| 1786 | else | ||
| 1787 | return (unsigned long)FTRACE_ADDR; | ||
| 1788 | } | ||
| 1789 | |||
| 1824 | static int | 1790 | static int |
| 1825 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | 1791 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) |
| 1826 | { | 1792 | { |
| @@ -1828,12 +1794,12 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | |||
| 1828 | unsigned long ftrace_addr; | 1794 | unsigned long ftrace_addr; |
| 1829 | int ret; | 1795 | int ret; |
| 1830 | 1796 | ||
| 1831 | ret = ftrace_update_record(rec, enable); | 1797 | ftrace_addr = ftrace_get_addr_new(rec); |
| 1832 | 1798 | ||
| 1833 | if (rec->flags & FTRACE_FL_REGS) | 1799 | /* This needs to be done before we call ftrace_update_record */ |
| 1834 | ftrace_addr = (unsigned long)FTRACE_REGS_ADDR; | 1800 | ftrace_old_addr = ftrace_get_addr_curr(rec); |
| 1835 | else | 1801 | |
| 1836 | ftrace_addr = (unsigned long)FTRACE_ADDR; | 1802 | ret = ftrace_update_record(rec, enable); |
| 1837 | 1803 | ||
| 1838 | switch (ret) { | 1804 | switch (ret) { |
| 1839 | case FTRACE_UPDATE_IGNORE: | 1805 | case FTRACE_UPDATE_IGNORE: |
| @@ -1845,13 +1811,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | |||
| 1845 | case FTRACE_UPDATE_MAKE_NOP: | 1811 | case FTRACE_UPDATE_MAKE_NOP: |
| 1846 | return ftrace_make_nop(NULL, rec, ftrace_addr); | 1812 | return ftrace_make_nop(NULL, rec, ftrace_addr); |
| 1847 | 1813 | ||
| 1848 | case FTRACE_UPDATE_MODIFY_CALL_REGS: | ||
| 1849 | case FTRACE_UPDATE_MODIFY_CALL: | 1814 | case FTRACE_UPDATE_MODIFY_CALL: |
| 1850 | if (rec->flags & FTRACE_FL_REGS) | ||
| 1851 | ftrace_old_addr = (unsigned long)FTRACE_ADDR; | ||
| 1852 | else | ||
| 1853 | ftrace_old_addr = (unsigned long)FTRACE_REGS_ADDR; | ||
| 1854 | |||
| 1855 | return ftrace_modify_call(rec, ftrace_old_addr, ftrace_addr); | 1815 | return ftrace_modify_call(rec, ftrace_old_addr, ftrace_addr); |
| 1856 | } | 1816 | } |
| 1857 | 1817 | ||
| @@ -2115,7 +2075,6 @@ static void ftrace_startup_enable(int command) | |||
| 2115 | 2075 | ||
| 2116 | static int ftrace_startup(struct ftrace_ops *ops, int command) | 2076 | static int ftrace_startup(struct ftrace_ops *ops, int command) |
| 2117 | { | 2077 | { |
| 2118 | bool hash_enable = true; | ||
| 2119 | int ret; | 2078 | int ret; |
| 2120 | 2079 | ||
| 2121 | if (unlikely(ftrace_disabled)) | 2080 | if (unlikely(ftrace_disabled)) |
| @@ -2128,18 +2087,9 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) | |||
| 2128 | ftrace_start_up++; | 2087 | ftrace_start_up++; |
| 2129 | command |= FTRACE_UPDATE_CALLS; | 2088 | command |= FTRACE_UPDATE_CALLS; |
| 2130 | 2089 | ||
| 2131 | /* ops marked global share the filter hashes */ | ||
| 2132 | if (ops->flags & FTRACE_OPS_FL_GLOBAL) { | ||
| 2133 | ops = &global_ops; | ||
| 2134 | /* Don't update hash if global is already set */ | ||
| 2135 | if (global_start_up) | ||
| 2136 | hash_enable = false; | ||
| 2137 | global_start_up++; | ||
| 2138 | } | ||
| 2139 | |||
| 2140 | ops->flags |= FTRACE_OPS_FL_ENABLED; | 2090 | ops->flags |= FTRACE_OPS_FL_ENABLED; |
| 2141 | if (hash_enable) | 2091 | |
| 2142 | ftrace_hash_rec_enable(ops, 1); | 2092 | ftrace_hash_rec_enable(ops, 1); |
| 2143 | 2093 | ||
| 2144 | ftrace_startup_enable(command); | 2094 | ftrace_startup_enable(command); |
| 2145 | 2095 | ||
| @@ -2148,7 +2098,6 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) | |||
| 2148 | 2098 | ||
| 2149 | static int ftrace_shutdown(struct ftrace_ops *ops, int command) | 2099 | static int ftrace_shutdown(struct ftrace_ops *ops, int command) |
| 2150 | { | 2100 | { |
| 2151 | bool hash_disable = true; | ||
| 2152 | int ret; | 2101 | int ret; |
| 2153 | 2102 | ||
| 2154 | if (unlikely(ftrace_disabled)) | 2103 | if (unlikely(ftrace_disabled)) |
| @@ -2166,21 +2115,9 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command) | |||
| 2166 | */ | 2115 | */ |
| 2167 | WARN_ON_ONCE(ftrace_start_up < 0); | 2116 | WARN_ON_ONCE(ftrace_start_up < 0); |
| 2168 | 2117 | ||
| 2169 | if (ops->flags & FTRACE_OPS_FL_GLOBAL) { | 2118 | ftrace_hash_rec_disable(ops, 1); |
| 2170 | ops = &global_ops; | ||
| 2171 | global_start_up--; | ||
| 2172 | WARN_ON_ONCE(global_start_up < 0); | ||
| 2173 | /* Don't update hash if global still has users */ | ||
| 2174 | if (global_start_up) { | ||
| 2175 | WARN_ON_ONCE(!ftrace_start_up); | ||
| 2176 | hash_disable = false; | ||
| 2177 | } | ||
| 2178 | } | ||
| 2179 | |||
| 2180 | if (hash_disable) | ||
| 2181 | ftrace_hash_rec_disable(ops, 1); | ||
| 2182 | 2119 | ||
| 2183 | if (ops != &global_ops || !global_start_up) | 2120 | if (!global_start_up) |
| 2184 | ops->flags &= ~FTRACE_OPS_FL_ENABLED; | 2121 | ops->flags &= ~FTRACE_OPS_FL_ENABLED; |
| 2185 | 2122 | ||
| 2186 | command |= FTRACE_UPDATE_CALLS; | 2123 | command |= FTRACE_UPDATE_CALLS; |
| @@ -3524,10 +3461,6 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
| 3524 | struct ftrace_hash *hash; | 3461 | struct ftrace_hash *hash; |
| 3525 | int ret; | 3462 | int ret; |
| 3526 | 3463 | ||
| 3527 | /* All global ops uses the global ops filters */ | ||
| 3528 | if (ops->flags & FTRACE_OPS_FL_GLOBAL) | ||
| 3529 | ops = &global_ops; | ||
| 3530 | |||
| 3531 | if (unlikely(ftrace_disabled)) | 3464 | if (unlikely(ftrace_disabled)) |
| 3532 | return -ENODEV; | 3465 | return -ENODEV; |
| 3533 | 3466 | ||
| @@ -3639,8 +3572,7 @@ int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, | |||
| 3639 | } | 3572 | } |
| 3640 | EXPORT_SYMBOL_GPL(ftrace_set_notrace); | 3573 | EXPORT_SYMBOL_GPL(ftrace_set_notrace); |
| 3641 | /** | 3574 | /** |
| 3642 | * ftrace_set_filter - set a function to filter on in ftrace | 3575 | * ftrace_set_global_filter - set a function to filter on with global tracers |
| 3643 | * @ops - the ops to set the filter with | ||
| 3644 | * @buf - the string that holds the function filter text. | 3576 | * @buf - the string that holds the function filter text. |
| 3645 | * @len - the length of the string. | 3577 | * @len - the length of the string. |
| 3646 | * @reset - non zero to reset all filters before applying this filter. | 3578 | * @reset - non zero to reset all filters before applying this filter. |
| @@ -3655,8 +3587,7 @@ void ftrace_set_global_filter(unsigned char *buf, int len, int reset) | |||
| 3655 | EXPORT_SYMBOL_GPL(ftrace_set_global_filter); | 3587 | EXPORT_SYMBOL_GPL(ftrace_set_global_filter); |
| 3656 | 3588 | ||
| 3657 | /** | 3589 | /** |
| 3658 | * ftrace_set_notrace - set a function to not trace in ftrace | 3590 | * ftrace_set_global_notrace - set a function to not trace with global tracers |
| 3659 | * @ops - the ops to set the notrace filter with | ||
| 3660 | * @buf - the string that holds the function notrace text. | 3591 | * @buf - the string that holds the function notrace text. |
| 3661 | * @len - the length of the string. | 3592 | * @len - the length of the string. |
| 3662 | * @reset - non zero to reset all filters before applying this filter. | 3593 | * @reset - non zero to reset all filters before applying this filter. |
| @@ -4443,6 +4374,34 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs) | |||
| 4443 | 4374 | ||
| 4444 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 4375 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
| 4445 | 4376 | ||
| 4377 | __init void ftrace_init_global_array_ops(struct trace_array *tr) | ||
| 4378 | { | ||
| 4379 | tr->ops = &global_ops; | ||
| 4380 | tr->ops->private = tr; | ||
| 4381 | } | ||
| 4382 | |||
| 4383 | void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func) | ||
| 4384 | { | ||
| 4385 | /* If we filter on pids, update to use the pid function */ | ||
| 4386 | if (tr->flags & TRACE_ARRAY_FL_GLOBAL) { | ||
| 4387 | if (WARN_ON(tr->ops->func != ftrace_stub)) | ||
| 4388 | printk("ftrace ops had %pS for function\n", | ||
| 4389 | tr->ops->func); | ||
| 4390 | /* Only the top level instance does pid tracing */ | ||
| 4391 | if (!list_empty(&ftrace_pids)) { | ||
| 4392 | set_ftrace_pid_function(func); | ||
| 4393 | func = ftrace_pid_func; | ||
| 4394 | } | ||
| 4395 | } | ||
| 4396 | tr->ops->func = func; | ||
| 4397 | tr->ops->private = tr; | ||
| 4398 | } | ||
| 4399 | |||
| 4400 | void ftrace_reset_array_ops(struct trace_array *tr) | ||
| 4401 | { | ||
| 4402 | tr->ops->func = ftrace_stub; | ||
| 4403 | } | ||
| 4404 | |||
| 4446 | static void | 4405 | static void |
| 4447 | ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip, | 4406 | ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip, |
| 4448 | struct ftrace_ops *op, struct pt_regs *regs) | 4407 | struct ftrace_ops *op, struct pt_regs *regs) |
| @@ -4501,9 +4460,16 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, | |||
| 4501 | */ | 4460 | */ |
| 4502 | preempt_disable_notrace(); | 4461 | preempt_disable_notrace(); |
| 4503 | do_for_each_ftrace_op(op, ftrace_ops_list) { | 4462 | do_for_each_ftrace_op(op, ftrace_ops_list) { |
| 4504 | if (ftrace_ops_test(op, ip, regs)) | 4463 | if (ftrace_ops_test(op, ip, regs)) { |
| 4464 | if (WARN_ON(!op->func)) { | ||
| 4465 | function_trace_stop = 1; | ||
| 4466 | printk("op=%p %pS\n", op, op); | ||
| 4467 | goto out; | ||
| 4468 | } | ||
| 4505 | op->func(ip, parent_ip, op, regs); | 4469 | op->func(ip, parent_ip, op, regs); |
| 4470 | } | ||
| 4506 | } while_for_each_ftrace_op(op); | 4471 | } while_for_each_ftrace_op(op); |
| 4472 | out: | ||
| 4507 | preempt_enable_notrace(); | 4473 | preempt_enable_notrace(); |
| 4508 | trace_clear_recursion(bit); | 4474 | trace_clear_recursion(bit); |
| 4509 | } | 4475 | } |
| @@ -4908,7 +4874,6 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, | |||
| 4908 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 4874 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| 4909 | 4875 | ||
| 4910 | static int ftrace_graph_active; | 4876 | static int ftrace_graph_active; |
| 4911 | static struct notifier_block ftrace_suspend_notifier; | ||
| 4912 | 4877 | ||
| 4913 | int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace) | 4878 | int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace) |
| 4914 | { | 4879 | { |
| @@ -5054,13 +5019,6 @@ ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state, | |||
| 5054 | return NOTIFY_DONE; | 5019 | return NOTIFY_DONE; |
| 5055 | } | 5020 | } |
| 5056 | 5021 | ||
| 5057 | /* Just a place holder for function graph */ | ||
| 5058 | static struct ftrace_ops fgraph_ops __read_mostly = { | ||
| 5059 | .func = ftrace_stub, | ||
| 5060 | .flags = FTRACE_OPS_FL_STUB | FTRACE_OPS_FL_GLOBAL | | ||
| 5061 | FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 5062 | }; | ||
| 5063 | |||
| 5064 | static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace) | 5022 | static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace) |
| 5065 | { | 5023 | { |
| 5066 | if (!ftrace_ops_test(&global_ops, trace->func, NULL)) | 5024 | if (!ftrace_ops_test(&global_ops, trace->func, NULL)) |
| @@ -5085,6 +5043,10 @@ static void update_function_graph_func(void) | |||
| 5085 | ftrace_graph_entry = ftrace_graph_entry_test; | 5043 | ftrace_graph_entry = ftrace_graph_entry_test; |
| 5086 | } | 5044 | } |
| 5087 | 5045 | ||
| 5046 | static struct notifier_block ftrace_suspend_notifier = { | ||
| 5047 | .notifier_call = ftrace_suspend_notifier_call, | ||
| 5048 | }; | ||
| 5049 | |||
| 5088 | int register_ftrace_graph(trace_func_graph_ret_t retfunc, | 5050 | int register_ftrace_graph(trace_func_graph_ret_t retfunc, |
| 5089 | trace_func_graph_ent_t entryfunc) | 5051 | trace_func_graph_ent_t entryfunc) |
| 5090 | { | 5052 | { |
| @@ -5098,7 +5060,6 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, | |||
| 5098 | goto out; | 5060 | goto out; |
| 5099 | } | 5061 | } |
| 5100 | 5062 | ||
| 5101 | ftrace_suspend_notifier.notifier_call = ftrace_suspend_notifier_call; | ||
| 5102 | register_pm_notifier(&ftrace_suspend_notifier); | 5063 | register_pm_notifier(&ftrace_suspend_notifier); |
| 5103 | 5064 | ||
| 5104 | ftrace_graph_active++; | 5065 | ftrace_graph_active++; |
| @@ -5120,7 +5081,10 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, | |||
| 5120 | ftrace_graph_entry = ftrace_graph_entry_test; | 5081 | ftrace_graph_entry = ftrace_graph_entry_test; |
| 5121 | update_function_graph_func(); | 5082 | update_function_graph_func(); |
| 5122 | 5083 | ||
| 5123 | ret = ftrace_startup(&fgraph_ops, FTRACE_START_FUNC_RET); | 5084 | /* Function graph doesn't use the .func field of global_ops */ |
| 5085 | global_ops.flags |= FTRACE_OPS_FL_STUB; | ||
| 5086 | |||
| 5087 | ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET); | ||
| 5124 | 5088 | ||
| 5125 | out: | 5089 | out: |
| 5126 | mutex_unlock(&ftrace_lock); | 5090 | mutex_unlock(&ftrace_lock); |
| @@ -5138,7 +5102,8 @@ void unregister_ftrace_graph(void) | |||
| 5138 | ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; | 5102 | ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; |
| 5139 | ftrace_graph_entry = ftrace_graph_entry_stub; | 5103 | ftrace_graph_entry = ftrace_graph_entry_stub; |
| 5140 | __ftrace_graph_entry = ftrace_graph_entry_stub; | 5104 | __ftrace_graph_entry = ftrace_graph_entry_stub; |
| 5141 | ftrace_shutdown(&fgraph_ops, FTRACE_STOP_FUNC_RET); | 5105 | ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET); |
| 5106 | global_ops.flags &= ~FTRACE_OPS_FL_STUB; | ||
| 5142 | unregister_pm_notifier(&ftrace_suspend_notifier); | 5107 | unregister_pm_notifier(&ftrace_suspend_notifier); |
| 5143 | unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); | 5108 | unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); |
| 5144 | 5109 | ||
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 737b0efa1a62..16f7038d1f4d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -275,7 +275,7 @@ int call_filter_check_discard(struct ftrace_event_call *call, void *rec, | |||
| 275 | } | 275 | } |
| 276 | EXPORT_SYMBOL_GPL(call_filter_check_discard); | 276 | EXPORT_SYMBOL_GPL(call_filter_check_discard); |
| 277 | 277 | ||
| 278 | cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu) | 278 | static cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu) |
| 279 | { | 279 | { |
| 280 | u64 ts; | 280 | u64 ts; |
| 281 | 281 | ||
| @@ -599,7 +599,7 @@ static int alloc_snapshot(struct trace_array *tr) | |||
| 599 | return 0; | 599 | return 0; |
| 600 | } | 600 | } |
| 601 | 601 | ||
| 602 | void free_snapshot(struct trace_array *tr) | 602 | static void free_snapshot(struct trace_array *tr) |
| 603 | { | 603 | { |
| 604 | /* | 604 | /* |
| 605 | * We don't free the ring buffer. instead, resize it because | 605 | * We don't free the ring buffer. instead, resize it because |
| @@ -963,27 +963,9 @@ static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt) | |||
| 963 | return cnt; | 963 | return cnt; |
| 964 | } | 964 | } |
| 965 | 965 | ||
| 966 | /* | ||
| 967 | * ftrace_max_lock is used to protect the swapping of buffers | ||
| 968 | * when taking a max snapshot. The buffers themselves are | ||
| 969 | * protected by per_cpu spinlocks. But the action of the swap | ||
| 970 | * needs its own lock. | ||
| 971 | * | ||
| 972 | * This is defined as a arch_spinlock_t in order to help | ||
| 973 | * with performance when lockdep debugging is enabled. | ||
| 974 | * | ||
| 975 | * It is also used in other places outside the update_max_tr | ||
| 976 | * so it needs to be defined outside of the | ||
| 977 | * CONFIG_TRACER_MAX_TRACE. | ||
| 978 | */ | ||
| 979 | static arch_spinlock_t ftrace_max_lock = | ||
| 980 | (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; | ||
| 981 | |||
| 982 | unsigned long __read_mostly tracing_thresh; | 966 | unsigned long __read_mostly tracing_thresh; |
| 983 | 967 | ||
| 984 | #ifdef CONFIG_TRACER_MAX_TRACE | 968 | #ifdef CONFIG_TRACER_MAX_TRACE |
| 985 | unsigned long __read_mostly tracing_max_latency; | ||
| 986 | |||
| 987 | /* | 969 | /* |
| 988 | * Copy the new maximum trace into the separate maximum-trace | 970 | * Copy the new maximum trace into the separate maximum-trace |
| 989 | * structure. (this way the maximum trace is permanently saved, | 971 | * structure. (this way the maximum trace is permanently saved, |
| @@ -1000,7 +982,7 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) | |||
| 1000 | max_buf->cpu = cpu; | 982 | max_buf->cpu = cpu; |
| 1001 | max_buf->time_start = data->preempt_timestamp; | 983 | max_buf->time_start = data->preempt_timestamp; |
| 1002 | 984 | ||
| 1003 | max_data->saved_latency = tracing_max_latency; | 985 | max_data->saved_latency = tr->max_latency; |
| 1004 | max_data->critical_start = data->critical_start; | 986 | max_data->critical_start = data->critical_start; |
| 1005 | max_data->critical_end = data->critical_end; | 987 | max_data->critical_end = data->critical_end; |
| 1006 | 988 | ||
| @@ -1048,14 +1030,14 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) | |||
| 1048 | return; | 1030 | return; |
| 1049 | } | 1031 | } |
| 1050 | 1032 | ||
| 1051 | arch_spin_lock(&ftrace_max_lock); | 1033 | arch_spin_lock(&tr->max_lock); |
| 1052 | 1034 | ||
| 1053 | buf = tr->trace_buffer.buffer; | 1035 | buf = tr->trace_buffer.buffer; |
| 1054 | tr->trace_buffer.buffer = tr->max_buffer.buffer; | 1036 | tr->trace_buffer.buffer = tr->max_buffer.buffer; |
| 1055 | tr->max_buffer.buffer = buf; | 1037 | tr->max_buffer.buffer = buf; |
| 1056 | 1038 | ||
| 1057 | __update_max_tr(tr, tsk, cpu); | 1039 | __update_max_tr(tr, tsk, cpu); |
| 1058 | arch_spin_unlock(&ftrace_max_lock); | 1040 | arch_spin_unlock(&tr->max_lock); |
| 1059 | } | 1041 | } |
| 1060 | 1042 | ||
| 1061 | /** | 1043 | /** |
| @@ -1081,7 +1063,7 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) | |||
| 1081 | return; | 1063 | return; |
| 1082 | } | 1064 | } |
| 1083 | 1065 | ||
| 1084 | arch_spin_lock(&ftrace_max_lock); | 1066 | arch_spin_lock(&tr->max_lock); |
| 1085 | 1067 | ||
| 1086 | ret = ring_buffer_swap_cpu(tr->max_buffer.buffer, tr->trace_buffer.buffer, cpu); | 1068 | ret = ring_buffer_swap_cpu(tr->max_buffer.buffer, tr->trace_buffer.buffer, cpu); |
| 1087 | 1069 | ||
| @@ -1099,11 +1081,11 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) | |||
| 1099 | WARN_ON_ONCE(ret && ret != -EAGAIN && ret != -EBUSY); | 1081 | WARN_ON_ONCE(ret && ret != -EAGAIN && ret != -EBUSY); |
| 1100 | 1082 | ||
| 1101 | __update_max_tr(tr, tsk, cpu); | 1083 | __update_max_tr(tr, tsk, cpu); |
| 1102 | arch_spin_unlock(&ftrace_max_lock); | 1084 | arch_spin_unlock(&tr->max_lock); |
| 1103 | } | 1085 | } |
| 1104 | #endif /* CONFIG_TRACER_MAX_TRACE */ | 1086 | #endif /* CONFIG_TRACER_MAX_TRACE */ |
| 1105 | 1087 | ||
| 1106 | static void default_wait_pipe(struct trace_iterator *iter) | 1088 | static void wait_on_pipe(struct trace_iterator *iter) |
| 1107 | { | 1089 | { |
| 1108 | /* Iterators are static, they should be filled or empty */ | 1090 | /* Iterators are static, they should be filled or empty */ |
| 1109 | if (trace_buffer_iter(iter, iter->cpu_file)) | 1091 | if (trace_buffer_iter(iter, iter->cpu_file)) |
| @@ -1220,8 +1202,6 @@ int register_tracer(struct tracer *type) | |||
| 1220 | else | 1202 | else |
| 1221 | if (!type->flags->opts) | 1203 | if (!type->flags->opts) |
| 1222 | type->flags->opts = dummy_tracer_opt; | 1204 | type->flags->opts = dummy_tracer_opt; |
| 1223 | if (!type->wait_pipe) | ||
| 1224 | type->wait_pipe = default_wait_pipe; | ||
| 1225 | 1205 | ||
| 1226 | ret = run_tracer_selftest(type); | 1206 | ret = run_tracer_selftest(type); |
| 1227 | if (ret < 0) | 1207 | if (ret < 0) |
| @@ -1305,22 +1285,71 @@ void tracing_reset_all_online_cpus(void) | |||
| 1305 | } | 1285 | } |
| 1306 | } | 1286 | } |
| 1307 | 1287 | ||
| 1308 | #define SAVED_CMDLINES 128 | 1288 | #define SAVED_CMDLINES_DEFAULT 128 |
| 1309 | #define NO_CMDLINE_MAP UINT_MAX | 1289 | #define NO_CMDLINE_MAP UINT_MAX |
| 1310 | static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; | ||
| 1311 | static unsigned map_cmdline_to_pid[SAVED_CMDLINES]; | ||
| 1312 | static char saved_cmdlines[SAVED_CMDLINES][TASK_COMM_LEN]; | ||
| 1313 | static int cmdline_idx; | ||
| 1314 | static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED; | 1290 | static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED; |
| 1291 | struct saved_cmdlines_buffer { | ||
| 1292 | unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; | ||
| 1293 | unsigned *map_cmdline_to_pid; | ||
| 1294 | unsigned cmdline_num; | ||
| 1295 | int cmdline_idx; | ||
| 1296 | char *saved_cmdlines; | ||
| 1297 | }; | ||
| 1298 | static struct saved_cmdlines_buffer *savedcmd; | ||
| 1315 | 1299 | ||
| 1316 | /* temporary disable recording */ | 1300 | /* temporary disable recording */ |
| 1317 | static atomic_t trace_record_cmdline_disabled __read_mostly; | 1301 | static atomic_t trace_record_cmdline_disabled __read_mostly; |
| 1318 | 1302 | ||
| 1319 | static void trace_init_cmdlines(void) | 1303 | static inline char *get_saved_cmdlines(int idx) |
| 1320 | { | 1304 | { |
| 1321 | memset(&map_pid_to_cmdline, NO_CMDLINE_MAP, sizeof(map_pid_to_cmdline)); | 1305 | return &savedcmd->saved_cmdlines[idx * TASK_COMM_LEN]; |
| 1322 | memset(&map_cmdline_to_pid, NO_CMDLINE_MAP, sizeof(map_cmdline_to_pid)); | 1306 | } |
| 1323 | cmdline_idx = 0; | 1307 | |
| 1308 | static inline void set_cmdline(int idx, const char *cmdline) | ||
| 1309 | { | ||
| 1310 | memcpy(get_saved_cmdlines(idx), cmdline, TASK_COMM_LEN); | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | static int allocate_cmdlines_buffer(unsigned int val, | ||
| 1314 | struct saved_cmdlines_buffer *s) | ||
| 1315 | { | ||
| 1316 | s->map_cmdline_to_pid = kmalloc(val * sizeof(*s->map_cmdline_to_pid), | ||
| 1317 | GFP_KERNEL); | ||
| 1318 | if (!s->map_cmdline_to_pid) | ||
| 1319 | return -ENOMEM; | ||
| 1320 | |||
| 1321 | s->saved_cmdlines = kmalloc(val * TASK_COMM_LEN, GFP_KERNEL); | ||
| 1322 | if (!s->saved_cmdlines) { | ||
| 1323 | kfree(s->map_cmdline_to_pid); | ||
| 1324 | return -ENOMEM; | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | s->cmdline_idx = 0; | ||
| 1328 | s->cmdline_num = val; | ||
| 1329 | memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP, | ||
| 1330 | sizeof(s->map_pid_to_cmdline)); | ||
| 1331 | memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP, | ||
| 1332 | val * sizeof(*s->map_cmdline_to_pid)); | ||
| 1333 | |||
| 1334 | return 0; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | static int trace_create_savedcmd(void) | ||
| 1338 | { | ||
| 1339 | int ret; | ||
| 1340 | |||
| 1341 | savedcmd = kmalloc(sizeof(struct saved_cmdlines_buffer), GFP_KERNEL); | ||
| 1342 | if (!savedcmd) | ||
| 1343 | return -ENOMEM; | ||
| 1344 | |||
| 1345 | ret = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT, savedcmd); | ||
| 1346 | if (ret < 0) { | ||
| 1347 | kfree(savedcmd); | ||
| 1348 | savedcmd = NULL; | ||
| 1349 | return -ENOMEM; | ||
| 1350 | } | ||
| 1351 | |||
| 1352 | return 0; | ||
| 1324 | } | 1353 | } |
| 1325 | 1354 | ||
| 1326 | int is_tracing_stopped(void) | 1355 | int is_tracing_stopped(void) |
| @@ -1353,7 +1382,7 @@ void tracing_start(void) | |||
| 1353 | } | 1382 | } |
| 1354 | 1383 | ||
| 1355 | /* Prevent the buffers from switching */ | 1384 | /* Prevent the buffers from switching */ |
| 1356 | arch_spin_lock(&ftrace_max_lock); | 1385 | arch_spin_lock(&global_trace.max_lock); |
| 1357 | 1386 | ||
| 1358 | buffer = global_trace.trace_buffer.buffer; | 1387 | buffer = global_trace.trace_buffer.buffer; |
| 1359 | if (buffer) | 1388 | if (buffer) |
| @@ -1365,7 +1394,7 @@ void tracing_start(void) | |||
| 1365 | ring_buffer_record_enable(buffer); | 1394 | ring_buffer_record_enable(buffer); |
| 1366 | #endif | 1395 | #endif |
| 1367 | 1396 | ||
| 1368 | arch_spin_unlock(&ftrace_max_lock); | 1397 | arch_spin_unlock(&global_trace.max_lock); |
| 1369 | 1398 | ||
| 1370 | ftrace_start(); | 1399 | ftrace_start(); |
| 1371 | out: | 1400 | out: |
| @@ -1420,7 +1449,7 @@ void tracing_stop(void) | |||
| 1420 | goto out; | 1449 | goto out; |
| 1421 | 1450 | ||
| 1422 | /* Prevent the buffers from switching */ | 1451 | /* Prevent the buffers from switching */ |
| 1423 | arch_spin_lock(&ftrace_max_lock); | 1452 | arch_spin_lock(&global_trace.max_lock); |
| 1424 | 1453 | ||
| 1425 | buffer = global_trace.trace_buffer.buffer; | 1454 | buffer = global_trace.trace_buffer.buffer; |
| 1426 | if (buffer) | 1455 | if (buffer) |
| @@ -1432,7 +1461,7 @@ void tracing_stop(void) | |||
| 1432 | ring_buffer_record_disable(buffer); | 1461 | ring_buffer_record_disable(buffer); |
| 1433 | #endif | 1462 | #endif |
| 1434 | 1463 | ||
| 1435 | arch_spin_unlock(&ftrace_max_lock); | 1464 | arch_spin_unlock(&global_trace.max_lock); |
| 1436 | 1465 | ||
| 1437 | out: | 1466 | out: |
| 1438 | raw_spin_unlock_irqrestore(&global_trace.start_lock, flags); | 1467 | raw_spin_unlock_irqrestore(&global_trace.start_lock, flags); |
| @@ -1461,12 +1490,12 @@ static void tracing_stop_tr(struct trace_array *tr) | |||
| 1461 | 1490 | ||
| 1462 | void trace_stop_cmdline_recording(void); | 1491 | void trace_stop_cmdline_recording(void); |
| 1463 | 1492 | ||
| 1464 | static void trace_save_cmdline(struct task_struct *tsk) | 1493 | static int trace_save_cmdline(struct task_struct *tsk) |
| 1465 | { | 1494 | { |
| 1466 | unsigned pid, idx; | 1495 | unsigned pid, idx; |
| 1467 | 1496 | ||
| 1468 | if (!tsk->pid || unlikely(tsk->pid > PID_MAX_DEFAULT)) | 1497 | if (!tsk->pid || unlikely(tsk->pid > PID_MAX_DEFAULT)) |
| 1469 | return; | 1498 | return 0; |
| 1470 | 1499 | ||
| 1471 | /* | 1500 | /* |
| 1472 | * It's not the end of the world if we don't get | 1501 | * It's not the end of the world if we don't get |
| @@ -1475,11 +1504,11 @@ static void trace_save_cmdline(struct task_struct *tsk) | |||
| 1475 | * so if we miss here, then better luck next time. | 1504 | * so if we miss here, then better luck next time. |
| 1476 | */ | 1505 | */ |
| 1477 | if (!arch_spin_trylock(&trace_cmdline_lock)) | 1506 | if (!arch_spin_trylock(&trace_cmdline_lock)) |
| 1478 | return; | 1507 | return 0; |
| 1479 | 1508 | ||
| 1480 | idx = map_pid_to_cmdline[tsk->pid]; | 1509 | idx = savedcmd->map_pid_to_cmdline[tsk->pid]; |
| 1481 | if (idx == NO_CMDLINE_MAP) { | 1510 | if (idx == NO_CMDLINE_MAP) { |
| 1482 | idx = (cmdline_idx + 1) % SAVED_CMDLINES; | 1511 | idx = (savedcmd->cmdline_idx + 1) % savedcmd->cmdline_num; |
| 1483 | 1512 | ||
| 1484 | /* | 1513 | /* |
| 1485 | * Check whether the cmdline buffer at idx has a pid | 1514 | * Check whether the cmdline buffer at idx has a pid |
| @@ -1487,22 +1516,24 @@ static void trace_save_cmdline(struct task_struct *tsk) | |||
| 1487 | * need to clear the map_pid_to_cmdline. Otherwise we | 1516 | * need to clear the map_pid_to_cmdline. Otherwise we |
| 1488 | * would read the new comm for the old pid. | 1517 | * would read the new comm for the old pid. |
| 1489 | */ | 1518 | */ |
| 1490 | pid = map_cmdline_to_pid[idx]; | 1519 | pid = savedcmd->map_cmdline_to_pid[idx]; |
| 1491 | if (pid != NO_CMDLINE_MAP) | 1520 | if (pid != NO_CMDLINE_MAP) |
| 1492 | map_pid_to_cmdline[pid] = NO_CMDLINE_MAP; | 1521 | savedcmd->map_pid_to_cmdline[pid] = NO_CMDLINE_MAP; |
| 1493 | 1522 | ||
| 1494 | map_cmdline_to_pid[idx] = tsk->pid; | 1523 | savedcmd->map_cmdline_to_pid[idx] = tsk->pid; |
| 1495 | map_pid_to_cmdline[tsk->pid] = idx; | 1524 | savedcmd->map_pid_to_cmdline[tsk->pid] = idx; |
| 1496 | 1525 | ||
| 1497 | cmdline_idx = idx; | 1526 | savedcmd->cmdline_idx = idx; |
| 1498 | } | 1527 | } |
| 1499 | 1528 | ||
| 1500 | memcpy(&saved_cmdlines[idx], tsk->comm, TASK_COMM_LEN); | 1529 | set_cmdline(idx, tsk->comm); |
| 1501 | 1530 | ||
| 1502 | arch_spin_unlock(&trace_cmdline_lock); | 1531 | arch_spin_unlock(&trace_cmdline_lock); |
| 1532 | |||
| 1533 | return 1; | ||
| 1503 | } | 1534 | } |
| 1504 | 1535 | ||
| 1505 | void trace_find_cmdline(int pid, char comm[]) | 1536 | static void __trace_find_cmdline(int pid, char comm[]) |
| 1506 | { | 1537 | { |
| 1507 | unsigned map; | 1538 | unsigned map; |
| 1508 | 1539 | ||
| @@ -1521,13 +1552,19 @@ void trace_find_cmdline(int pid, char comm[]) | |||
| 1521 | return; | 1552 | return; |
| 1522 | } | 1553 | } |
| 1523 | 1554 | ||
| 1524 | preempt_disable(); | 1555 | map = savedcmd->map_pid_to_cmdline[pid]; |
| 1525 | arch_spin_lock(&trace_cmdline_lock); | ||
| 1526 | map = map_pid_to_cmdline[pid]; | ||
| 1527 | if (map != NO_CMDLINE_MAP) | 1556 | if (map != NO_CMDLINE_MAP) |
| 1528 | strcpy(comm, saved_cmdlines[map]); | 1557 | strcpy(comm, get_saved_cmdlines(map)); |
| 1529 | else | 1558 | else |
| 1530 | strcpy(comm, "<...>"); | 1559 | strcpy(comm, "<...>"); |
| 1560 | } | ||
| 1561 | |||
| 1562 | void trace_find_cmdline(int pid, char comm[]) | ||
| 1563 | { | ||
| 1564 | preempt_disable(); | ||
| 1565 | arch_spin_lock(&trace_cmdline_lock); | ||
| 1566 | |||
| 1567 | __trace_find_cmdline(pid, comm); | ||
| 1531 | 1568 | ||
| 1532 | arch_spin_unlock(&trace_cmdline_lock); | 1569 | arch_spin_unlock(&trace_cmdline_lock); |
| 1533 | preempt_enable(); | 1570 | preempt_enable(); |
| @@ -1541,9 +1578,8 @@ void tracing_record_cmdline(struct task_struct *tsk) | |||
| 1541 | if (!__this_cpu_read(trace_cmdline_save)) | 1578 | if (!__this_cpu_read(trace_cmdline_save)) |
| 1542 | return; | 1579 | return; |
| 1543 | 1580 | ||
| 1544 | __this_cpu_write(trace_cmdline_save, false); | 1581 | if (trace_save_cmdline(tsk)) |
| 1545 | 1582 | __this_cpu_write(trace_cmdline_save, false); | |
| 1546 | trace_save_cmdline(tsk); | ||
| 1547 | } | 1583 | } |
| 1548 | 1584 | ||
| 1549 | void | 1585 | void |
| @@ -1746,7 +1782,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer, | |||
| 1746 | */ | 1782 | */ |
| 1747 | barrier(); | 1783 | barrier(); |
| 1748 | if (use_stack == 1) { | 1784 | if (use_stack == 1) { |
| 1749 | trace.entries = &__get_cpu_var(ftrace_stack).calls[0]; | 1785 | trace.entries = this_cpu_ptr(ftrace_stack.calls); |
| 1750 | trace.max_entries = FTRACE_STACK_MAX_ENTRIES; | 1786 | trace.max_entries = FTRACE_STACK_MAX_ENTRIES; |
| 1751 | 1787 | ||
| 1752 | if (regs) | 1788 | if (regs) |
| @@ -1995,7 +2031,21 @@ void trace_printk_init_buffers(void) | |||
| 1995 | if (alloc_percpu_trace_buffer()) | 2031 | if (alloc_percpu_trace_buffer()) |
| 1996 | return; | 2032 | return; |
| 1997 | 2033 | ||
| 1998 | pr_info("ftrace: Allocated trace_printk buffers\n"); | 2034 | /* trace_printk() is for debug use only. Don't use it in production. */ |
| 2035 | |||
| 2036 | pr_warning("\n**********************************************************\n"); | ||
| 2037 | pr_warning("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); | ||
| 2038 | pr_warning("** **\n"); | ||
| 2039 | pr_warning("** trace_printk() being used. Allocating extra memory. **\n"); | ||
| 2040 | pr_warning("** **\n"); | ||
| 2041 | pr_warning("** This means that this is a DEBUG kernel and it is **\n"); | ||
| 2042 | pr_warning("** unsafe for produciton use. **\n"); | ||
| 2043 | pr_warning("** **\n"); | ||
| 2044 | pr_warning("** If you see this message and you are not debugging **\n"); | ||
| 2045 | pr_warning("** the kernel, report this immediately to your vendor! **\n"); | ||
| 2046 | pr_warning("** **\n"); | ||
| 2047 | pr_warning("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); | ||
| 2048 | pr_warning("**********************************************************\n"); | ||
| 1999 | 2049 | ||
| 2000 | /* Expand the buffers to set size */ | 2050 | /* Expand the buffers to set size */ |
| 2001 | tracing_update_buffers(); | 2051 | tracing_update_buffers(); |
| @@ -3333,7 +3383,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, | |||
| 3333 | mutex_lock(&tracing_cpumask_update_lock); | 3383 | mutex_lock(&tracing_cpumask_update_lock); |
| 3334 | 3384 | ||
| 3335 | local_irq_disable(); | 3385 | local_irq_disable(); |
| 3336 | arch_spin_lock(&ftrace_max_lock); | 3386 | arch_spin_lock(&tr->max_lock); |
| 3337 | for_each_tracing_cpu(cpu) { | 3387 | for_each_tracing_cpu(cpu) { |
| 3338 | /* | 3388 | /* |
| 3339 | * Increase/decrease the disabled counter if we are | 3389 | * Increase/decrease the disabled counter if we are |
| @@ -3350,7 +3400,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, | |||
| 3350 | ring_buffer_record_enable_cpu(tr->trace_buffer.buffer, cpu); | 3400 | ring_buffer_record_enable_cpu(tr->trace_buffer.buffer, cpu); |
| 3351 | } | 3401 | } |
| 3352 | } | 3402 | } |
| 3353 | arch_spin_unlock(&ftrace_max_lock); | 3403 | arch_spin_unlock(&tr->max_lock); |
| 3354 | local_irq_enable(); | 3404 | local_irq_enable(); |
| 3355 | 3405 | ||
| 3356 | cpumask_copy(tr->tracing_cpumask, tracing_cpumask_new); | 3406 | cpumask_copy(tr->tracing_cpumask, tracing_cpumask_new); |
| @@ -3592,6 +3642,7 @@ static const char readme_msg[] = | |||
| 3592 | " trace_options\t\t- Set format or modify how tracing happens\n" | 3642 | " trace_options\t\t- Set format or modify how tracing happens\n" |
| 3593 | "\t\t\t Disable an option by adding a suffix 'no' to the\n" | 3643 | "\t\t\t Disable an option by adding a suffix 'no' to the\n" |
| 3594 | "\t\t\t option name\n" | 3644 | "\t\t\t option name\n" |
| 3645 | " saved_cmdlines_size\t- echo command number in here to store comm-pid list\n" | ||
| 3595 | #ifdef CONFIG_DYNAMIC_FTRACE | 3646 | #ifdef CONFIG_DYNAMIC_FTRACE |
| 3596 | "\n available_filter_functions - list of functions that can be filtered on\n" | 3647 | "\n available_filter_functions - list of functions that can be filtered on\n" |
| 3597 | " set_ftrace_filter\t- echo function name in here to only trace these\n" | 3648 | " set_ftrace_filter\t- echo function name in here to only trace these\n" |
| @@ -3705,55 +3756,153 @@ static const struct file_operations tracing_readme_fops = { | |||
| 3705 | .llseek = generic_file_llseek, | 3756 | .llseek = generic_file_llseek, |
| 3706 | }; | 3757 | }; |
| 3707 | 3758 | ||
| 3759 | static void *saved_cmdlines_next(struct seq_file *m, void *v, loff_t *pos) | ||
| 3760 | { | ||
| 3761 | unsigned int *ptr = v; | ||
| 3762 | |||
| 3763 | if (*pos || m->count) | ||
| 3764 | ptr++; | ||
| 3765 | |||
| 3766 | (*pos)++; | ||
| 3767 | |||
| 3768 | for (; ptr < &savedcmd->map_cmdline_to_pid[savedcmd->cmdline_num]; | ||
| 3769 | ptr++) { | ||
| 3770 | if (*ptr == -1 || *ptr == NO_CMDLINE_MAP) | ||
| 3771 | continue; | ||
| 3772 | |||
| 3773 | return ptr; | ||
| 3774 | } | ||
| 3775 | |||
| 3776 | return NULL; | ||
| 3777 | } | ||
| 3778 | |||
| 3779 | static void *saved_cmdlines_start(struct seq_file *m, loff_t *pos) | ||
| 3780 | { | ||
| 3781 | void *v; | ||
| 3782 | loff_t l = 0; | ||
| 3783 | |||
| 3784 | preempt_disable(); | ||
| 3785 | arch_spin_lock(&trace_cmdline_lock); | ||
| 3786 | |||
| 3787 | v = &savedcmd->map_cmdline_to_pid[0]; | ||
| 3788 | while (l <= *pos) { | ||
| 3789 | v = saved_cmdlines_next(m, v, &l); | ||
| 3790 | if (!v) | ||
| 3791 | return NULL; | ||
| 3792 | } | ||
| 3793 | |||
| 3794 | return v; | ||
| 3795 | } | ||
| 3796 | |||
| 3797 | static void saved_cmdlines_stop(struct seq_file *m, void *v) | ||
| 3798 | { | ||
| 3799 | arch_spin_unlock(&trace_cmdline_lock); | ||
| 3800 | preempt_enable(); | ||
| 3801 | } | ||
| 3802 | |||
| 3803 | static int saved_cmdlines_show(struct seq_file *m, void *v) | ||
| 3804 | { | ||
| 3805 | char buf[TASK_COMM_LEN]; | ||
| 3806 | unsigned int *pid = v; | ||
| 3807 | |||
| 3808 | __trace_find_cmdline(*pid, buf); | ||
| 3809 | seq_printf(m, "%d %s\n", *pid, buf); | ||
| 3810 | return 0; | ||
| 3811 | } | ||
| 3812 | |||
| 3813 | static const struct seq_operations tracing_saved_cmdlines_seq_ops = { | ||
| 3814 | .start = saved_cmdlines_start, | ||
| 3815 | .next = saved_cmdlines_next, | ||
| 3816 | .stop = saved_cmdlines_stop, | ||
| 3817 | .show = saved_cmdlines_show, | ||
| 3818 | }; | ||
| 3819 | |||
| 3820 | static int tracing_saved_cmdlines_open(struct inode *inode, struct file *filp) | ||
| 3821 | { | ||
| 3822 | if (tracing_disabled) | ||
| 3823 | return -ENODEV; | ||
| 3824 | |||
| 3825 | return seq_open(filp, &tracing_saved_cmdlines_seq_ops); | ||
| 3826 | } | ||
| 3827 | |||
| 3828 | static const struct file_operations tracing_saved_cmdlines_fops = { | ||
| 3829 | .open = tracing_saved_cmdlines_open, | ||
| 3830 | .read = seq_read, | ||
| 3831 | .llseek = seq_lseek, | ||
| 3832 | .release = seq_release, | ||
| 3833 | }; | ||
| 3834 | |||
| 3708 | static ssize_t | 3835 | static ssize_t |
| 3709 | tracing_saved_cmdlines_read(struct file *file, char __user *ubuf, | 3836 | tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf, |
| 3710 | size_t cnt, loff_t *ppos) | 3837 | size_t cnt, loff_t *ppos) |
| 3711 | { | 3838 | { |
| 3712 | char *buf_comm; | 3839 | char buf[64]; |
| 3713 | char *file_buf; | 3840 | int r; |
| 3714 | char *buf; | 3841 | |
| 3715 | int len = 0; | 3842 | arch_spin_lock(&trace_cmdline_lock); |
| 3716 | int pid; | 3843 | r = sprintf(buf, "%u\n", savedcmd->cmdline_num); |
| 3717 | int i; | 3844 | arch_spin_unlock(&trace_cmdline_lock); |
| 3845 | |||
| 3846 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
| 3847 | } | ||
| 3848 | |||
| 3849 | static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) | ||
| 3850 | { | ||
| 3851 | kfree(s->saved_cmdlines); | ||
| 3852 | kfree(s->map_cmdline_to_pid); | ||
| 3853 | kfree(s); | ||
| 3854 | } | ||
| 3855 | |||
| 3856 | static int tracing_resize_saved_cmdlines(unsigned int val) | ||
| 3857 | { | ||
| 3858 | struct saved_cmdlines_buffer *s, *savedcmd_temp; | ||
| 3718 | 3859 | ||
| 3719 | file_buf = kmalloc(SAVED_CMDLINES*(16+TASK_COMM_LEN), GFP_KERNEL); | 3860 | s = kmalloc(sizeof(struct saved_cmdlines_buffer), GFP_KERNEL); |
| 3720 | if (!file_buf) | 3861 | if (!s) |
| 3721 | return -ENOMEM; | 3862 | return -ENOMEM; |
| 3722 | 3863 | ||
| 3723 | buf_comm = kmalloc(TASK_COMM_LEN, GFP_KERNEL); | 3864 | if (allocate_cmdlines_buffer(val, s) < 0) { |
| 3724 | if (!buf_comm) { | 3865 | kfree(s); |
| 3725 | kfree(file_buf); | ||
| 3726 | return -ENOMEM; | 3866 | return -ENOMEM; |
| 3727 | } | 3867 | } |
| 3728 | 3868 | ||
| 3729 | buf = file_buf; | 3869 | arch_spin_lock(&trace_cmdline_lock); |
| 3870 | savedcmd_temp = savedcmd; | ||
| 3871 | savedcmd = s; | ||
| 3872 | arch_spin_unlock(&trace_cmdline_lock); | ||
| 3873 | free_saved_cmdlines_buffer(savedcmd_temp); | ||
| 3730 | 3874 | ||
| 3731 | for (i = 0; i < SAVED_CMDLINES; i++) { | 3875 | return 0; |
| 3732 | int r; | 3876 | } |
| 3733 | 3877 | ||
| 3734 | pid = map_cmdline_to_pid[i]; | 3878 | static ssize_t |
| 3735 | if (pid == -1 || pid == NO_CMDLINE_MAP) | 3879 | tracing_saved_cmdlines_size_write(struct file *filp, const char __user *ubuf, |
| 3736 | continue; | 3880 | size_t cnt, loff_t *ppos) |
| 3881 | { | ||
| 3882 | unsigned long val; | ||
| 3883 | int ret; | ||
| 3737 | 3884 | ||
| 3738 | trace_find_cmdline(pid, buf_comm); | 3885 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
| 3739 | r = sprintf(buf, "%d %s\n", pid, buf_comm); | 3886 | if (ret) |
| 3740 | buf += r; | 3887 | return ret; |
| 3741 | len += r; | ||
| 3742 | } | ||
| 3743 | 3888 | ||
| 3744 | len = simple_read_from_buffer(ubuf, cnt, ppos, | 3889 | /* must have at least 1 entry or less than PID_MAX_DEFAULT */ |
| 3745 | file_buf, len); | 3890 | if (!val || val > PID_MAX_DEFAULT) |
| 3891 | return -EINVAL; | ||
| 3746 | 3892 | ||
| 3747 | kfree(file_buf); | 3893 | ret = tracing_resize_saved_cmdlines((unsigned int)val); |
| 3748 | kfree(buf_comm); | 3894 | if (ret < 0) |
| 3895 | return ret; | ||
| 3749 | 3896 | ||
| 3750 | return len; | 3897 | *ppos += cnt; |
| 3898 | |||
| 3899 | return cnt; | ||
| 3751 | } | 3900 | } |
| 3752 | 3901 | ||
| 3753 | static const struct file_operations tracing_saved_cmdlines_fops = { | 3902 | static const struct file_operations tracing_saved_cmdlines_size_fops = { |
| 3754 | .open = tracing_open_generic, | 3903 | .open = tracing_open_generic, |
| 3755 | .read = tracing_saved_cmdlines_read, | 3904 | .read = tracing_saved_cmdlines_size_read, |
| 3756 | .llseek = generic_file_llseek, | 3905 | .write = tracing_saved_cmdlines_size_write, |
| 3757 | }; | 3906 | }; |
| 3758 | 3907 | ||
| 3759 | static ssize_t | 3908 | static ssize_t |
| @@ -4225,25 +4374,6 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table) | |||
| 4225 | return trace_poll(iter, filp, poll_table); | 4374 | return trace_poll(iter, filp, poll_table); |
| 4226 | } | 4375 | } |
| 4227 | 4376 | ||
| 4228 | /* | ||
| 4229 | * This is a make-shift waitqueue. | ||
| 4230 | * A tracer might use this callback on some rare cases: | ||
| 4231 | * | ||
| 4232 | * 1) the current tracer might hold the runqueue lock when it wakes up | ||
| 4233 | * a reader, hence a deadlock (sched, function, and function graph tracers) | ||
| 4234 | * 2) the function tracers, trace all functions, we don't want | ||
| 4235 | * the overhead of calling wake_up and friends | ||
| 4236 | * (and tracing them too) | ||
| 4237 | * | ||
| 4238 | * Anyway, this is really very primitive wakeup. | ||
| 4239 | */ | ||
| 4240 | void poll_wait_pipe(struct trace_iterator *iter) | ||
| 4241 | { | ||
| 4242 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 4243 | /* sleep for 100 msecs, and try again. */ | ||
| 4244 | schedule_timeout(HZ / 10); | ||
| 4245 | } | ||
| 4246 | |||
| 4247 | /* Must be called with trace_types_lock mutex held. */ | 4377 | /* Must be called with trace_types_lock mutex held. */ |
| 4248 | static int tracing_wait_pipe(struct file *filp) | 4378 | static int tracing_wait_pipe(struct file *filp) |
| 4249 | { | 4379 | { |
| @@ -4255,15 +4385,6 @@ static int tracing_wait_pipe(struct file *filp) | |||
| 4255 | return -EAGAIN; | 4385 | return -EAGAIN; |
| 4256 | } | 4386 | } |
| 4257 | 4387 | ||
| 4258 | mutex_unlock(&iter->mutex); | ||
| 4259 | |||
| 4260 | iter->trace->wait_pipe(iter); | ||
| 4261 | |||
| 4262 | mutex_lock(&iter->mutex); | ||
| 4263 | |||
| 4264 | if (signal_pending(current)) | ||
| 4265 | return -EINTR; | ||
| 4266 | |||
| 4267 | /* | 4388 | /* |
| 4268 | * We block until we read something and tracing is disabled. | 4389 | * We block until we read something and tracing is disabled. |
| 4269 | * We still block if tracing is disabled, but we have never | 4390 | * We still block if tracing is disabled, but we have never |
| @@ -4275,6 +4396,15 @@ static int tracing_wait_pipe(struct file *filp) | |||
| 4275 | */ | 4396 | */ |
| 4276 | if (!tracing_is_on() && iter->pos) | 4397 | if (!tracing_is_on() && iter->pos) |
| 4277 | break; | 4398 | break; |
| 4399 | |||
| 4400 | mutex_unlock(&iter->mutex); | ||
| 4401 | |||
| 4402 | wait_on_pipe(iter); | ||
| 4403 | |||
| 4404 | mutex_lock(&iter->mutex); | ||
| 4405 | |||
| 4406 | if (signal_pending(current)) | ||
| 4407 | return -EINTR; | ||
| 4278 | } | 4408 | } |
| 4279 | 4409 | ||
| 4280 | return 1; | 4410 | return 1; |
| @@ -5197,7 +5327,7 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, | |||
| 5197 | goto out_unlock; | 5327 | goto out_unlock; |
| 5198 | } | 5328 | } |
| 5199 | mutex_unlock(&trace_types_lock); | 5329 | mutex_unlock(&trace_types_lock); |
| 5200 | iter->trace->wait_pipe(iter); | 5330 | wait_on_pipe(iter); |
| 5201 | mutex_lock(&trace_types_lock); | 5331 | mutex_lock(&trace_types_lock); |
| 5202 | if (signal_pending(current)) { | 5332 | if (signal_pending(current)) { |
| 5203 | size = -EINTR; | 5333 | size = -EINTR; |
| @@ -5408,7 +5538,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | |||
| 5408 | goto out; | 5538 | goto out; |
| 5409 | } | 5539 | } |
| 5410 | mutex_unlock(&trace_types_lock); | 5540 | mutex_unlock(&trace_types_lock); |
| 5411 | iter->trace->wait_pipe(iter); | 5541 | wait_on_pipe(iter); |
| 5412 | mutex_lock(&trace_types_lock); | 5542 | mutex_lock(&trace_types_lock); |
| 5413 | if (signal_pending(current)) { | 5543 | if (signal_pending(current)) { |
| 5414 | ret = -EINTR; | 5544 | ret = -EINTR; |
| @@ -6102,6 +6232,25 @@ static int allocate_trace_buffers(struct trace_array *tr, int size) | |||
| 6102 | return 0; | 6232 | return 0; |
| 6103 | } | 6233 | } |
| 6104 | 6234 | ||
| 6235 | static void free_trace_buffers(struct trace_array *tr) | ||
| 6236 | { | ||
| 6237 | if (!tr) | ||
| 6238 | return; | ||
| 6239 | |||
| 6240 | if (tr->trace_buffer.buffer) { | ||
| 6241 | ring_buffer_free(tr->trace_buffer.buffer); | ||
| 6242 | tr->trace_buffer.buffer = NULL; | ||
| 6243 | free_percpu(tr->trace_buffer.data); | ||
| 6244 | } | ||
| 6245 | |||
| 6246 | #ifdef CONFIG_TRACER_MAX_TRACE | ||
| 6247 | if (tr->max_buffer.buffer) { | ||
| 6248 | ring_buffer_free(tr->max_buffer.buffer); | ||
| 6249 | tr->max_buffer.buffer = NULL; | ||
| 6250 | } | ||
| 6251 | #endif | ||
| 6252 | } | ||
| 6253 | |||
| 6105 | static int new_instance_create(const char *name) | 6254 | static int new_instance_create(const char *name) |
| 6106 | { | 6255 | { |
| 6107 | struct trace_array *tr; | 6256 | struct trace_array *tr; |
| @@ -6131,6 +6280,8 @@ static int new_instance_create(const char *name) | |||
| 6131 | 6280 | ||
| 6132 | raw_spin_lock_init(&tr->start_lock); | 6281 | raw_spin_lock_init(&tr->start_lock); |
| 6133 | 6282 | ||
| 6283 | tr->max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; | ||
| 6284 | |||
| 6134 | tr->current_trace = &nop_trace; | 6285 | tr->current_trace = &nop_trace; |
| 6135 | 6286 | ||
| 6136 | INIT_LIST_HEAD(&tr->systems); | 6287 | INIT_LIST_HEAD(&tr->systems); |
| @@ -6158,8 +6309,7 @@ static int new_instance_create(const char *name) | |||
| 6158 | return 0; | 6309 | return 0; |
| 6159 | 6310 | ||
| 6160 | out_free_tr: | 6311 | out_free_tr: |
| 6161 | if (tr->trace_buffer.buffer) | 6312 | free_trace_buffers(tr); |
| 6162 | ring_buffer_free(tr->trace_buffer.buffer); | ||
| 6163 | free_cpumask_var(tr->tracing_cpumask); | 6313 | free_cpumask_var(tr->tracing_cpumask); |
| 6164 | kfree(tr->name); | 6314 | kfree(tr->name); |
| 6165 | kfree(tr); | 6315 | kfree(tr); |
| @@ -6199,8 +6349,7 @@ static int instance_delete(const char *name) | |||
| 6199 | event_trace_del_tracer(tr); | 6349 | event_trace_del_tracer(tr); |
| 6200 | ftrace_destroy_function_files(tr); | 6350 | ftrace_destroy_function_files(tr); |
| 6201 | debugfs_remove_recursive(tr->dir); | 6351 | debugfs_remove_recursive(tr->dir); |
| 6202 | free_percpu(tr->trace_buffer.data); | 6352 | free_trace_buffers(tr); |
| 6203 | ring_buffer_free(tr->trace_buffer.buffer); | ||
| 6204 | 6353 | ||
| 6205 | kfree(tr->name); | 6354 | kfree(tr->name); |
| 6206 | kfree(tr); | 6355 | kfree(tr); |
| @@ -6328,6 +6477,11 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) | |||
| 6328 | trace_create_file("tracing_on", 0644, d_tracer, | 6477 | trace_create_file("tracing_on", 0644, d_tracer, |
| 6329 | tr, &rb_simple_fops); | 6478 | tr, &rb_simple_fops); |
| 6330 | 6479 | ||
| 6480 | #ifdef CONFIG_TRACER_MAX_TRACE | ||
| 6481 | trace_create_file("tracing_max_latency", 0644, d_tracer, | ||
| 6482 | &tr->max_latency, &tracing_max_lat_fops); | ||
| 6483 | #endif | ||
| 6484 | |||
| 6331 | if (ftrace_create_function_files(tr, d_tracer)) | 6485 | if (ftrace_create_function_files(tr, d_tracer)) |
| 6332 | WARN(1, "Could not allocate function filter files"); | 6486 | WARN(1, "Could not allocate function filter files"); |
| 6333 | 6487 | ||
| @@ -6353,11 +6507,6 @@ static __init int tracer_init_debugfs(void) | |||
| 6353 | 6507 | ||
| 6354 | init_tracer_debugfs(&global_trace, d_tracer); | 6508 | init_tracer_debugfs(&global_trace, d_tracer); |
| 6355 | 6509 | ||
| 6356 | #ifdef CONFIG_TRACER_MAX_TRACE | ||
| 6357 | trace_create_file("tracing_max_latency", 0644, d_tracer, | ||
| 6358 | &tracing_max_latency, &tracing_max_lat_fops); | ||
| 6359 | #endif | ||
| 6360 | |||
| 6361 | trace_create_file("tracing_thresh", 0644, d_tracer, | 6510 | trace_create_file("tracing_thresh", 0644, d_tracer, |
| 6362 | &tracing_thresh, &tracing_max_lat_fops); | 6511 | &tracing_thresh, &tracing_max_lat_fops); |
| 6363 | 6512 | ||
| @@ -6367,6 +6516,9 @@ static __init int tracer_init_debugfs(void) | |||
| 6367 | trace_create_file("saved_cmdlines", 0444, d_tracer, | 6516 | trace_create_file("saved_cmdlines", 0444, d_tracer, |
| 6368 | NULL, &tracing_saved_cmdlines_fops); | 6517 | NULL, &tracing_saved_cmdlines_fops); |
| 6369 | 6518 | ||
| 6519 | trace_create_file("saved_cmdlines_size", 0644, d_tracer, | ||
| 6520 | NULL, &tracing_saved_cmdlines_size_fops); | ||
| 6521 | |||
| 6370 | #ifdef CONFIG_DYNAMIC_FTRACE | 6522 | #ifdef CONFIG_DYNAMIC_FTRACE |
| 6371 | trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, | 6523 | trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, |
| 6372 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); | 6524 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); |
| @@ -6603,18 +6755,19 @@ __init static int tracer_alloc_buffers(void) | |||
| 6603 | if (!temp_buffer) | 6755 | if (!temp_buffer) |
| 6604 | goto out_free_cpumask; | 6756 | goto out_free_cpumask; |
| 6605 | 6757 | ||
| 6758 | if (trace_create_savedcmd() < 0) | ||
| 6759 | goto out_free_temp_buffer; | ||
| 6760 | |||
| 6606 | /* TODO: make the number of buffers hot pluggable with CPUS */ | 6761 | /* TODO: make the number of buffers hot pluggable with CPUS */ |
| 6607 | if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) { | 6762 | if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) { |
| 6608 | printk(KERN_ERR "tracer: failed to allocate ring buffer!\n"); | 6763 | printk(KERN_ERR "tracer: failed to allocate ring buffer!\n"); |
| 6609 | WARN_ON(1); | 6764 | WARN_ON(1); |
| 6610 | goto out_free_temp_buffer; | 6765 | goto out_free_savedcmd; |
| 6611 | } | 6766 | } |
| 6612 | 6767 | ||
| 6613 | if (global_trace.buffer_disabled) | 6768 | if (global_trace.buffer_disabled) |
| 6614 | tracing_off(); | 6769 | tracing_off(); |
| 6615 | 6770 | ||
| 6616 | trace_init_cmdlines(); | ||
| 6617 | |||
| 6618 | if (trace_boot_clock) { | 6771 | if (trace_boot_clock) { |
| 6619 | ret = tracing_set_clock(&global_trace, trace_boot_clock); | 6772 | ret = tracing_set_clock(&global_trace, trace_boot_clock); |
| 6620 | if (ret < 0) | 6773 | if (ret < 0) |
| @@ -6629,6 +6782,10 @@ __init static int tracer_alloc_buffers(void) | |||
| 6629 | */ | 6782 | */ |
| 6630 | global_trace.current_trace = &nop_trace; | 6783 | global_trace.current_trace = &nop_trace; |
| 6631 | 6784 | ||
| 6785 | global_trace.max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; | ||
| 6786 | |||
| 6787 | ftrace_init_global_array_ops(&global_trace); | ||
| 6788 | |||
| 6632 | register_tracer(&nop_trace); | 6789 | register_tracer(&nop_trace); |
| 6633 | 6790 | ||
| 6634 | /* All seems OK, enable tracing */ | 6791 | /* All seems OK, enable tracing */ |
| @@ -6656,13 +6813,11 @@ __init static int tracer_alloc_buffers(void) | |||
| 6656 | 6813 | ||
| 6657 | return 0; | 6814 | return 0; |
| 6658 | 6815 | ||
| 6816 | out_free_savedcmd: | ||
| 6817 | free_saved_cmdlines_buffer(savedcmd); | ||
| 6659 | out_free_temp_buffer: | 6818 | out_free_temp_buffer: |
| 6660 | ring_buffer_free(temp_buffer); | 6819 | ring_buffer_free(temp_buffer); |
| 6661 | out_free_cpumask: | 6820 | out_free_cpumask: |
| 6662 | free_percpu(global_trace.trace_buffer.data); | ||
| 6663 | #ifdef CONFIG_TRACER_MAX_TRACE | ||
| 6664 | free_percpu(global_trace.max_buffer.data); | ||
| 6665 | #endif | ||
| 6666 | free_cpumask_var(global_trace.tracing_cpumask); | 6821 | free_cpumask_var(global_trace.tracing_cpumask); |
| 6667 | out_free_buffer_mask: | 6822 | out_free_buffer_mask: |
| 6668 | free_cpumask_var(tracing_buffer_mask); | 6823 | free_cpumask_var(tracing_buffer_mask); |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 2e29d7ba5a52..9e82551dd566 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -190,7 +190,22 @@ struct trace_array { | |||
| 190 | */ | 190 | */ |
| 191 | struct trace_buffer max_buffer; | 191 | struct trace_buffer max_buffer; |
| 192 | bool allocated_snapshot; | 192 | bool allocated_snapshot; |
| 193 | unsigned long max_latency; | ||
| 193 | #endif | 194 | #endif |
| 195 | /* | ||
| 196 | * max_lock is used to protect the swapping of buffers | ||
| 197 | * when taking a max snapshot. The buffers themselves are | ||
| 198 | * protected by per_cpu spinlocks. But the action of the swap | ||
| 199 | * needs its own lock. | ||
| 200 | * | ||
| 201 | * This is defined as a arch_spinlock_t in order to help | ||
| 202 | * with performance when lockdep debugging is enabled. | ||
| 203 | * | ||
| 204 | * It is also used in other places outside the update_max_tr | ||
| 205 | * so it needs to be defined outside of the | ||
| 206 | * CONFIG_TRACER_MAX_TRACE. | ||
| 207 | */ | ||
| 208 | arch_spinlock_t max_lock; | ||
| 194 | int buffer_disabled; | 209 | int buffer_disabled; |
| 195 | #ifdef CONFIG_FTRACE_SYSCALLS | 210 | #ifdef CONFIG_FTRACE_SYSCALLS |
| 196 | int sys_refcount_enter; | 211 | int sys_refcount_enter; |
| @@ -237,6 +252,9 @@ static inline struct trace_array *top_trace_array(void) | |||
| 237 | { | 252 | { |
| 238 | struct trace_array *tr; | 253 | struct trace_array *tr; |
| 239 | 254 | ||
| 255 | if (list_empty(ftrace_trace_arrays.prev)) | ||
| 256 | return NULL; | ||
| 257 | |||
| 240 | tr = list_entry(ftrace_trace_arrays.prev, | 258 | tr = list_entry(ftrace_trace_arrays.prev, |
| 241 | typeof(*tr), list); | 259 | typeof(*tr), list); |
| 242 | WARN_ON(!(tr->flags & TRACE_ARRAY_FL_GLOBAL)); | 260 | WARN_ON(!(tr->flags & TRACE_ARRAY_FL_GLOBAL)); |
| @@ -323,7 +341,6 @@ struct tracer_flags { | |||
| 323 | * @stop: called when tracing is paused (echo 0 > tracing_enabled) | 341 | * @stop: called when tracing is paused (echo 0 > tracing_enabled) |
| 324 | * @open: called when the trace file is opened | 342 | * @open: called when the trace file is opened |
| 325 | * @pipe_open: called when the trace_pipe file is opened | 343 | * @pipe_open: called when the trace_pipe file is opened |
| 326 | * @wait_pipe: override how the user waits for traces on trace_pipe | ||
| 327 | * @close: called when the trace file is released | 344 | * @close: called when the trace file is released |
| 328 | * @pipe_close: called when the trace_pipe file is released | 345 | * @pipe_close: called when the trace_pipe file is released |
| 329 | * @read: override the default read callback on trace_pipe | 346 | * @read: override the default read callback on trace_pipe |
| @@ -342,7 +359,6 @@ struct tracer { | |||
| 342 | void (*stop)(struct trace_array *tr); | 359 | void (*stop)(struct trace_array *tr); |
| 343 | void (*open)(struct trace_iterator *iter); | 360 | void (*open)(struct trace_iterator *iter); |
| 344 | void (*pipe_open)(struct trace_iterator *iter); | 361 | void (*pipe_open)(struct trace_iterator *iter); |
| 345 | void (*wait_pipe)(struct trace_iterator *iter); | ||
| 346 | void (*close)(struct trace_iterator *iter); | 362 | void (*close)(struct trace_iterator *iter); |
| 347 | void (*pipe_close)(struct trace_iterator *iter); | 363 | void (*pipe_close)(struct trace_iterator *iter); |
| 348 | ssize_t (*read)(struct trace_iterator *iter, | 364 | ssize_t (*read)(struct trace_iterator *iter, |
| @@ -416,13 +432,7 @@ enum { | |||
| 416 | TRACE_FTRACE_IRQ_BIT, | 432 | TRACE_FTRACE_IRQ_BIT, |
| 417 | TRACE_FTRACE_SIRQ_BIT, | 433 | TRACE_FTRACE_SIRQ_BIT, |
| 418 | 434 | ||
| 419 | /* GLOBAL_BITs must be greater than FTRACE_BITs */ | 435 | /* INTERNAL_BITs must be greater than FTRACE_BITs */ |
| 420 | TRACE_GLOBAL_BIT, | ||
| 421 | TRACE_GLOBAL_NMI_BIT, | ||
| 422 | TRACE_GLOBAL_IRQ_BIT, | ||
| 423 | TRACE_GLOBAL_SIRQ_BIT, | ||
| 424 | |||
| 425 | /* INTERNAL_BITs must be greater than GLOBAL_BITs */ | ||
| 426 | TRACE_INTERNAL_BIT, | 436 | TRACE_INTERNAL_BIT, |
| 427 | TRACE_INTERNAL_NMI_BIT, | 437 | TRACE_INTERNAL_NMI_BIT, |
| 428 | TRACE_INTERNAL_IRQ_BIT, | 438 | TRACE_INTERNAL_IRQ_BIT, |
| @@ -449,9 +459,6 @@ enum { | |||
| 449 | #define TRACE_FTRACE_START TRACE_FTRACE_BIT | 459 | #define TRACE_FTRACE_START TRACE_FTRACE_BIT |
| 450 | #define TRACE_FTRACE_MAX ((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1) | 460 | #define TRACE_FTRACE_MAX ((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1) |
| 451 | 461 | ||
| 452 | #define TRACE_GLOBAL_START TRACE_GLOBAL_BIT | ||
| 453 | #define TRACE_GLOBAL_MAX ((1 << (TRACE_GLOBAL_START + TRACE_CONTEXT_BITS)) - 1) | ||
| 454 | |||
| 455 | #define TRACE_LIST_START TRACE_INTERNAL_BIT | 462 | #define TRACE_LIST_START TRACE_INTERNAL_BIT |
| 456 | #define TRACE_LIST_MAX ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1) | 463 | #define TRACE_LIST_MAX ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1) |
| 457 | 464 | ||
| @@ -560,8 +567,6 @@ void trace_init_global_iter(struct trace_iterator *iter); | |||
| 560 | 567 | ||
| 561 | void tracing_iter_reset(struct trace_iterator *iter, int cpu); | 568 | void tracing_iter_reset(struct trace_iterator *iter, int cpu); |
| 562 | 569 | ||
| 563 | void poll_wait_pipe(struct trace_iterator *iter); | ||
| 564 | |||
| 565 | void tracing_sched_switch_trace(struct trace_array *tr, | 570 | void tracing_sched_switch_trace(struct trace_array *tr, |
| 566 | struct task_struct *prev, | 571 | struct task_struct *prev, |
| 567 | struct task_struct *next, | 572 | struct task_struct *next, |
| @@ -608,8 +613,6 @@ extern unsigned long nsecs_to_usecs(unsigned long nsecs); | |||
| 608 | extern unsigned long tracing_thresh; | 613 | extern unsigned long tracing_thresh; |
| 609 | 614 | ||
| 610 | #ifdef CONFIG_TRACER_MAX_TRACE | 615 | #ifdef CONFIG_TRACER_MAX_TRACE |
| 611 | extern unsigned long tracing_max_latency; | ||
| 612 | |||
| 613 | void update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu); | 616 | void update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu); |
| 614 | void update_max_tr_single(struct trace_array *tr, | 617 | void update_max_tr_single(struct trace_array *tr, |
| 615 | struct task_struct *tsk, int cpu); | 618 | struct task_struct *tsk, int cpu); |
| @@ -724,6 +727,8 @@ extern unsigned long trace_flags; | |||
| 724 | #define TRACE_GRAPH_PRINT_PROC 0x8 | 727 | #define TRACE_GRAPH_PRINT_PROC 0x8 |
| 725 | #define TRACE_GRAPH_PRINT_DURATION 0x10 | 728 | #define TRACE_GRAPH_PRINT_DURATION 0x10 |
| 726 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 | 729 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 |
| 730 | #define TRACE_GRAPH_PRINT_IRQS 0x40 | ||
| 731 | #define TRACE_GRAPH_PRINT_TAIL 0x80 | ||
| 727 | #define TRACE_GRAPH_PRINT_FILL_SHIFT 28 | 732 | #define TRACE_GRAPH_PRINT_FILL_SHIFT 28 |
| 728 | #define TRACE_GRAPH_PRINT_FILL_MASK (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT) | 733 | #define TRACE_GRAPH_PRINT_FILL_MASK (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT) |
| 729 | 734 | ||
| @@ -823,6 +828,10 @@ extern int ftrace_is_dead(void); | |||
| 823 | int ftrace_create_function_files(struct trace_array *tr, | 828 | int ftrace_create_function_files(struct trace_array *tr, |
| 824 | struct dentry *parent); | 829 | struct dentry *parent); |
| 825 | void ftrace_destroy_function_files(struct trace_array *tr); | 830 | void ftrace_destroy_function_files(struct trace_array *tr); |
| 831 | void ftrace_init_global_array_ops(struct trace_array *tr); | ||
| 832 | void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func); | ||
| 833 | void ftrace_reset_array_ops(struct trace_array *tr); | ||
| 834 | int using_ftrace_ops_list_func(void); | ||
| 826 | #else | 835 | #else |
| 827 | static inline int ftrace_trace_task(struct task_struct *task) | 836 | static inline int ftrace_trace_task(struct task_struct *task) |
| 828 | { | 837 | { |
| @@ -836,6 +845,11 @@ ftrace_create_function_files(struct trace_array *tr, | |||
| 836 | return 0; | 845 | return 0; |
| 837 | } | 846 | } |
| 838 | static inline void ftrace_destroy_function_files(struct trace_array *tr) { } | 847 | static inline void ftrace_destroy_function_files(struct trace_array *tr) { } |
| 848 | static inline __init void | ||
| 849 | ftrace_init_global_array_ops(struct trace_array *tr) { } | ||
| 850 | static inline void ftrace_reset_array_ops(struct trace_array *tr) { } | ||
| 851 | /* ftace_func_t type is not defined, use macro instead of static inline */ | ||
| 852 | #define ftrace_init_array_ops(tr, func) do { } while (0) | ||
| 839 | #endif /* CONFIG_FUNCTION_TRACER */ | 853 | #endif /* CONFIG_FUNCTION_TRACER */ |
| 840 | 854 | ||
| 841 | #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE) | 855 | #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE) |
diff --git a/kernel/trace/trace_benchmark.c b/kernel/trace/trace_benchmark.c new file mode 100644 index 000000000000..40a14cbcf8e0 --- /dev/null +++ b/kernel/trace/trace_benchmark.c | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | #include <linux/delay.h> | ||
| 2 | #include <linux/module.h> | ||
| 3 | #include <linux/kthread.h> | ||
| 4 | #include <linux/trace_clock.h> | ||
| 5 | |||
| 6 | #define CREATE_TRACE_POINTS | ||
| 7 | #include "trace_benchmark.h" | ||
| 8 | |||
| 9 | static struct task_struct *bm_event_thread; | ||
| 10 | |||
| 11 | static char bm_str[BENCHMARK_EVENT_STRLEN] = "START"; | ||
| 12 | |||
| 13 | static u64 bm_total; | ||
| 14 | static u64 bm_totalsq; | ||
| 15 | static u64 bm_last; | ||
| 16 | static u64 bm_max; | ||
| 17 | static u64 bm_min; | ||
| 18 | static u64 bm_first; | ||
| 19 | static u64 bm_cnt; | ||
| 20 | static u64 bm_stddev; | ||
| 21 | static unsigned int bm_avg; | ||
| 22 | static unsigned int bm_std; | ||
| 23 | |||
| 24 | /* | ||
| 25 | * This gets called in a loop recording the time it took to write | ||
| 26 | * the tracepoint. What it writes is the time statistics of the last | ||
| 27 | * tracepoint write. As there is nothing to write the first time | ||
| 28 | * it simply writes "START". As the first write is cold cache and | ||
| 29 | * the rest is hot, we save off that time in bm_first and it is | ||
| 30 | * reported as "first", which is shown in the second write to the | ||
| 31 | * tracepoint. The "first" field is writen within the statics from | ||
| 32 | * then on but never changes. | ||
| 33 | */ | ||
| 34 | static void trace_do_benchmark(void) | ||
| 35 | { | ||
| 36 | u64 start; | ||
| 37 | u64 stop; | ||
| 38 | u64 delta; | ||
| 39 | u64 stddev; | ||
| 40 | u64 seed; | ||
| 41 | u64 last_seed; | ||
| 42 | unsigned int avg; | ||
| 43 | unsigned int std = 0; | ||
| 44 | |||
| 45 | /* Only run if the tracepoint is actually active */ | ||
| 46 | if (!trace_benchmark_event_enabled()) | ||
| 47 | return; | ||
| 48 | |||
| 49 | local_irq_disable(); | ||
| 50 | start = trace_clock_local(); | ||
| 51 | trace_benchmark_event(bm_str); | ||
| 52 | stop = trace_clock_local(); | ||
| 53 | local_irq_enable(); | ||
| 54 | |||
| 55 | bm_cnt++; | ||
| 56 | |||
| 57 | delta = stop - start; | ||
| 58 | |||
| 59 | /* | ||
| 60 | * The first read is cold cached, keep it separate from the | ||
| 61 | * other calculations. | ||
| 62 | */ | ||
| 63 | if (bm_cnt == 1) { | ||
| 64 | bm_first = delta; | ||
| 65 | scnprintf(bm_str, BENCHMARK_EVENT_STRLEN, | ||
| 66 | "first=%llu [COLD CACHED]", bm_first); | ||
| 67 | return; | ||
| 68 | } | ||
| 69 | |||
| 70 | bm_last = delta; | ||
| 71 | |||
| 72 | if (delta > bm_max) | ||
| 73 | bm_max = delta; | ||
| 74 | if (!bm_min || delta < bm_min) | ||
| 75 | bm_min = delta; | ||
| 76 | |||
| 77 | /* | ||
| 78 | * When bm_cnt is greater than UINT_MAX, it breaks the statistics | ||
| 79 | * accounting. Freeze the statistics when that happens. | ||
| 80 | * We should have enough data for the avg and stddev anyway. | ||
| 81 | */ | ||
| 82 | if (bm_cnt > UINT_MAX) { | ||
| 83 | scnprintf(bm_str, BENCHMARK_EVENT_STRLEN, | ||
| 84 | "last=%llu first=%llu max=%llu min=%llu ** avg=%u std=%d std^2=%lld", | ||
| 85 | bm_last, bm_first, bm_max, bm_min, bm_avg, bm_std, bm_stddev); | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 89 | bm_total += delta; | ||
| 90 | bm_totalsq += delta * delta; | ||
| 91 | |||
| 92 | |||
| 93 | if (bm_cnt > 1) { | ||
| 94 | /* | ||
| 95 | * Apply Welford's method to calculate standard deviation: | ||
| 96 | * s^2 = 1 / (n * (n-1)) * (n * \Sum (x_i)^2 - (\Sum x_i)^2) | ||
| 97 | */ | ||
| 98 | stddev = (u64)bm_cnt * bm_totalsq - bm_total * bm_total; | ||
| 99 | do_div(stddev, (u32)bm_cnt); | ||
| 100 | do_div(stddev, (u32)bm_cnt - 1); | ||
| 101 | } else | ||
| 102 | stddev = 0; | ||
| 103 | |||
| 104 | delta = bm_total; | ||
| 105 | do_div(delta, bm_cnt); | ||
| 106 | avg = delta; | ||
| 107 | |||
| 108 | if (stddev > 0) { | ||
| 109 | int i = 0; | ||
| 110 | /* | ||
| 111 | * stddev is the square of standard deviation but | ||
| 112 | * we want the actualy number. Use the average | ||
| 113 | * as our seed to find the std. | ||
| 114 | * | ||
| 115 | * The next try is: | ||
| 116 | * x = (x + N/x) / 2 | ||
| 117 | * | ||
| 118 | * Where N is the squared number to find the square | ||
| 119 | * root of. | ||
| 120 | */ | ||
| 121 | seed = avg; | ||
| 122 | do { | ||
| 123 | last_seed = seed; | ||
| 124 | seed = stddev; | ||
| 125 | if (!last_seed) | ||
| 126 | break; | ||
| 127 | do_div(seed, last_seed); | ||
| 128 | seed += last_seed; | ||
| 129 | do_div(seed, 2); | ||
| 130 | } while (i++ < 10 && last_seed != seed); | ||
| 131 | |||
| 132 | std = seed; | ||
| 133 | } | ||
| 134 | |||
| 135 | scnprintf(bm_str, BENCHMARK_EVENT_STRLEN, | ||
| 136 | "last=%llu first=%llu max=%llu min=%llu avg=%u std=%d std^2=%lld", | ||
| 137 | bm_last, bm_first, bm_max, bm_min, avg, std, stddev); | ||
| 138 | |||
| 139 | bm_std = std; | ||
| 140 | bm_avg = avg; | ||
| 141 | bm_stddev = stddev; | ||
| 142 | } | ||
| 143 | |||
| 144 | static int benchmark_event_kthread(void *arg) | ||
| 145 | { | ||
| 146 | /* sleep a bit to make sure the tracepoint gets activated */ | ||
| 147 | msleep(100); | ||
| 148 | |||
| 149 | while (!kthread_should_stop()) { | ||
| 150 | |||
| 151 | trace_do_benchmark(); | ||
| 152 | |||
| 153 | /* | ||
| 154 | * We don't go to sleep, but let others | ||
| 155 | * run as well. | ||
| 156 | */ | ||
| 157 | cond_resched(); | ||
| 158 | } | ||
| 159 | |||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* | ||
| 164 | * When the benchmark tracepoint is enabled, it calls this | ||
| 165 | * function and the thread that calls the tracepoint is created. | ||
| 166 | */ | ||
| 167 | void trace_benchmark_reg(void) | ||
| 168 | { | ||
| 169 | bm_event_thread = kthread_run(benchmark_event_kthread, | ||
| 170 | NULL, "event_benchmark"); | ||
| 171 | WARN_ON(!bm_event_thread); | ||
| 172 | } | ||
| 173 | |||
| 174 | /* | ||
| 175 | * When the benchmark tracepoint is disabled, it calls this | ||
| 176 | * function and the thread that calls the tracepoint is deleted | ||
| 177 | * and all the numbers are reset. | ||
| 178 | */ | ||
| 179 | void trace_benchmark_unreg(void) | ||
| 180 | { | ||
| 181 | if (!bm_event_thread) | ||
| 182 | return; | ||
| 183 | |||
| 184 | kthread_stop(bm_event_thread); | ||
| 185 | |||
| 186 | strcpy(bm_str, "START"); | ||
| 187 | bm_total = 0; | ||
| 188 | bm_totalsq = 0; | ||
| 189 | bm_last = 0; | ||
| 190 | bm_max = 0; | ||
| 191 | bm_min = 0; | ||
| 192 | bm_cnt = 0; | ||
| 193 | /* These don't need to be reset but reset them anyway */ | ||
| 194 | bm_first = 0; | ||
| 195 | bm_std = 0; | ||
| 196 | bm_avg = 0; | ||
| 197 | bm_stddev = 0; | ||
| 198 | } | ||
diff --git a/kernel/trace/trace_benchmark.h b/kernel/trace/trace_benchmark.h new file mode 100644 index 000000000000..3c1df1df4e29 --- /dev/null +++ b/kernel/trace/trace_benchmark.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM benchmark | ||
| 3 | |||
| 4 | #if !defined(_TRACE_BENCHMARK_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define _TRACE_BENCHMARK_H | ||
| 6 | |||
| 7 | #include <linux/tracepoint.h> | ||
| 8 | |||
| 9 | extern void trace_benchmark_reg(void); | ||
| 10 | extern void trace_benchmark_unreg(void); | ||
| 11 | |||
| 12 | #define BENCHMARK_EVENT_STRLEN 128 | ||
| 13 | |||
| 14 | TRACE_EVENT_FN(benchmark_event, | ||
| 15 | |||
| 16 | TP_PROTO(const char *str), | ||
| 17 | |||
| 18 | TP_ARGS(str), | ||
| 19 | |||
| 20 | TP_STRUCT__entry( | ||
| 21 | __array( char, str, BENCHMARK_EVENT_STRLEN ) | ||
| 22 | ), | ||
| 23 | |||
| 24 | TP_fast_assign( | ||
| 25 | memcpy(__entry->str, str, BENCHMARK_EVENT_STRLEN); | ||
| 26 | ), | ||
| 27 | |||
| 28 | TP_printk("%s", __entry->str), | ||
| 29 | |||
| 30 | trace_benchmark_reg, trace_benchmark_unreg | ||
| 31 | ); | ||
| 32 | |||
| 33 | #endif /* _TRACE_BENCHMARK_H */ | ||
| 34 | |||
| 35 | #undef TRACE_INCLUDE_FILE | ||
| 36 | #undef TRACE_INCLUDE_PATH | ||
| 37 | #define TRACE_INCLUDE_PATH . | ||
| 38 | #define TRACE_INCLUDE_FILE trace_benchmark | ||
| 39 | |||
| 40 | /* This part must be outside protection */ | ||
| 41 | #include <trace/define_trace.h> | ||
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 3ddfd8f62c05..f99e0b3bca8c 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -574,6 +574,9 @@ int trace_set_clr_event(const char *system, const char *event, int set) | |||
| 574 | { | 574 | { |
| 575 | struct trace_array *tr = top_trace_array(); | 575 | struct trace_array *tr = top_trace_array(); |
| 576 | 576 | ||
| 577 | if (!tr) | ||
| 578 | return -ENODEV; | ||
| 579 | |||
| 577 | return __ftrace_set_clr_event(tr, NULL, system, event, set); | 580 | return __ftrace_set_clr_event(tr, NULL, system, event, set); |
| 578 | } | 581 | } |
| 579 | EXPORT_SYMBOL_GPL(trace_set_clr_event); | 582 | EXPORT_SYMBOL_GPL(trace_set_clr_event); |
| @@ -2065,6 +2068,9 @@ event_enable_func(struct ftrace_hash *hash, | |||
| 2065 | bool enable; | 2068 | bool enable; |
| 2066 | int ret; | 2069 | int ret; |
| 2067 | 2070 | ||
| 2071 | if (!tr) | ||
| 2072 | return -ENODEV; | ||
| 2073 | |||
| 2068 | /* hash funcs only work with set_ftrace_filter */ | 2074 | /* hash funcs only work with set_ftrace_filter */ |
| 2069 | if (!enabled || !param) | 2075 | if (!enabled || !param) |
| 2070 | return -EINVAL; | 2076 | return -EINVAL; |
| @@ -2396,6 +2402,9 @@ static __init int event_trace_enable(void) | |||
| 2396 | char *token; | 2402 | char *token; |
| 2397 | int ret; | 2403 | int ret; |
| 2398 | 2404 | ||
| 2405 | if (!tr) | ||
| 2406 | return -ENODEV; | ||
| 2407 | |||
| 2399 | for_each_event(iter, __start_ftrace_events, __stop_ftrace_events) { | 2408 | for_each_event(iter, __start_ftrace_events, __stop_ftrace_events) { |
| 2400 | 2409 | ||
| 2401 | call = *iter; | 2410 | call = *iter; |
| @@ -2442,6 +2451,8 @@ static __init int event_trace_init(void) | |||
| 2442 | int ret; | 2451 | int ret; |
| 2443 | 2452 | ||
| 2444 | tr = top_trace_array(); | 2453 | tr = top_trace_array(); |
| 2454 | if (!tr) | ||
| 2455 | return -ENODEV; | ||
| 2445 | 2456 | ||
| 2446 | d_tracer = tracing_init_dentry(); | 2457 | d_tracer = tracing_init_dentry(); |
| 2447 | if (!d_tracer) | 2458 | if (!d_tracer) |
| @@ -2535,6 +2546,8 @@ static __init void event_trace_self_tests(void) | |||
| 2535 | int ret; | 2546 | int ret; |
| 2536 | 2547 | ||
| 2537 | tr = top_trace_array(); | 2548 | tr = top_trace_array(); |
| 2549 | if (!tr) | ||
| 2550 | return; | ||
| 2538 | 2551 | ||
| 2539 | pr_info("Running tests on trace events:\n"); | 2552 | pr_info("Running tests on trace events:\n"); |
| 2540 | 2553 | ||
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index ffd56351b521..57f0ec962d2c 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c | |||
| @@ -26,8 +26,6 @@ function_trace_call(unsigned long ip, unsigned long parent_ip, | |||
| 26 | static void | 26 | static void |
| 27 | function_stack_trace_call(unsigned long ip, unsigned long parent_ip, | 27 | function_stack_trace_call(unsigned long ip, unsigned long parent_ip, |
| 28 | struct ftrace_ops *op, struct pt_regs *pt_regs); | 28 | struct ftrace_ops *op, struct pt_regs *pt_regs); |
| 29 | static struct ftrace_ops trace_ops; | ||
| 30 | static struct ftrace_ops trace_stack_ops; | ||
| 31 | static struct tracer_flags func_flags; | 29 | static struct tracer_flags func_flags; |
| 32 | 30 | ||
| 33 | /* Our option */ | 31 | /* Our option */ |
| @@ -83,28 +81,24 @@ void ftrace_destroy_function_files(struct trace_array *tr) | |||
| 83 | 81 | ||
| 84 | static int function_trace_init(struct trace_array *tr) | 82 | static int function_trace_init(struct trace_array *tr) |
| 85 | { | 83 | { |
| 86 | struct ftrace_ops *ops; | 84 | ftrace_func_t func; |
| 87 | |||
| 88 | if (tr->flags & TRACE_ARRAY_FL_GLOBAL) { | ||
| 89 | /* There's only one global tr */ | ||
| 90 | if (!trace_ops.private) { | ||
| 91 | trace_ops.private = tr; | ||
| 92 | trace_stack_ops.private = tr; | ||
| 93 | } | ||
| 94 | 85 | ||
| 95 | if (func_flags.val & TRACE_FUNC_OPT_STACK) | 86 | /* |
| 96 | ops = &trace_stack_ops; | 87 | * Instance trace_arrays get their ops allocated |
| 97 | else | 88 | * at instance creation. Unless it failed |
| 98 | ops = &trace_ops; | 89 | * the allocation. |
| 99 | tr->ops = ops; | 90 | */ |
| 100 | } else if (!tr->ops) { | 91 | if (!tr->ops) |
| 101 | /* | ||
| 102 | * Instance trace_arrays get their ops allocated | ||
| 103 | * at instance creation. Unless it failed | ||
| 104 | * the allocation. | ||
| 105 | */ | ||
| 106 | return -ENOMEM; | 92 | return -ENOMEM; |
| 107 | } | 93 | |
| 94 | /* Currently only the global instance can do stack tracing */ | ||
| 95 | if (tr->flags & TRACE_ARRAY_FL_GLOBAL && | ||
| 96 | func_flags.val & TRACE_FUNC_OPT_STACK) | ||
| 97 | func = function_stack_trace_call; | ||
| 98 | else | ||
| 99 | func = function_trace_call; | ||
| 100 | |||
| 101 | ftrace_init_array_ops(tr, func); | ||
| 108 | 102 | ||
| 109 | tr->trace_buffer.cpu = get_cpu(); | 103 | tr->trace_buffer.cpu = get_cpu(); |
| 110 | put_cpu(); | 104 | put_cpu(); |
| @@ -118,6 +112,7 @@ static void function_trace_reset(struct trace_array *tr) | |||
| 118 | { | 112 | { |
| 119 | tracing_stop_function_trace(tr); | 113 | tracing_stop_function_trace(tr); |
| 120 | tracing_stop_cmdline_record(); | 114 | tracing_stop_cmdline_record(); |
| 115 | ftrace_reset_array_ops(tr); | ||
| 121 | } | 116 | } |
| 122 | 117 | ||
| 123 | static void function_trace_start(struct trace_array *tr) | 118 | static void function_trace_start(struct trace_array *tr) |
| @@ -199,18 +194,6 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip, | |||
| 199 | local_irq_restore(flags); | 194 | local_irq_restore(flags); |
| 200 | } | 195 | } |
| 201 | 196 | ||
| 202 | static struct ftrace_ops trace_ops __read_mostly = | ||
| 203 | { | ||
| 204 | .func = function_trace_call, | ||
| 205 | .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 206 | }; | ||
| 207 | |||
| 208 | static struct ftrace_ops trace_stack_ops __read_mostly = | ||
| 209 | { | ||
| 210 | .func = function_stack_trace_call, | ||
| 211 | .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 212 | }; | ||
| 213 | |||
| 214 | static struct tracer_opt func_opts[] = { | 197 | static struct tracer_opt func_opts[] = { |
| 215 | #ifdef CONFIG_STACKTRACE | 198 | #ifdef CONFIG_STACKTRACE |
| 216 | { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) }, | 199 | { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) }, |
| @@ -248,10 +231,10 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) | |||
| 248 | unregister_ftrace_function(tr->ops); | 231 | unregister_ftrace_function(tr->ops); |
| 249 | 232 | ||
| 250 | if (set) { | 233 | if (set) { |
| 251 | tr->ops = &trace_stack_ops; | 234 | tr->ops->func = function_stack_trace_call; |
| 252 | register_ftrace_function(tr->ops); | 235 | register_ftrace_function(tr->ops); |
| 253 | } else { | 236 | } else { |
| 254 | tr->ops = &trace_ops; | 237 | tr->ops->func = function_trace_call; |
| 255 | register_ftrace_function(tr->ops); | 238 | register_ftrace_function(tr->ops); |
| 256 | } | 239 | } |
| 257 | 240 | ||
| @@ -269,7 +252,6 @@ static struct tracer function_trace __tracer_data = | |||
| 269 | .init = function_trace_init, | 252 | .init = function_trace_init, |
| 270 | .reset = function_trace_reset, | 253 | .reset = function_trace_reset, |
| 271 | .start = function_trace_start, | 254 | .start = function_trace_start, |
| 272 | .wait_pipe = poll_wait_pipe, | ||
| 273 | .flags = &func_flags, | 255 | .flags = &func_flags, |
| 274 | .set_flag = func_set_flag, | 256 | .set_flag = func_set_flag, |
| 275 | .allow_instances = true, | 257 | .allow_instances = true, |
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index deff11200261..4de3e57f723c 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
| @@ -38,15 +38,6 @@ struct fgraph_data { | |||
| 38 | 38 | ||
| 39 | #define TRACE_GRAPH_INDENT 2 | 39 | #define TRACE_GRAPH_INDENT 2 |
| 40 | 40 | ||
| 41 | /* Flag options */ | ||
| 42 | #define TRACE_GRAPH_PRINT_OVERRUN 0x1 | ||
| 43 | #define TRACE_GRAPH_PRINT_CPU 0x2 | ||
| 44 | #define TRACE_GRAPH_PRINT_OVERHEAD 0x4 | ||
| 45 | #define TRACE_GRAPH_PRINT_PROC 0x8 | ||
| 46 | #define TRACE_GRAPH_PRINT_DURATION 0x10 | ||
| 47 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 | ||
| 48 | #define TRACE_GRAPH_PRINT_IRQS 0x40 | ||
| 49 | |||
| 50 | static unsigned int max_depth; | 41 | static unsigned int max_depth; |
| 51 | 42 | ||
| 52 | static struct tracer_opt trace_opts[] = { | 43 | static struct tracer_opt trace_opts[] = { |
| @@ -64,11 +55,13 @@ static struct tracer_opt trace_opts[] = { | |||
| 64 | { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) }, | 55 | { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) }, |
| 65 | /* Display interrupts */ | 56 | /* Display interrupts */ |
| 66 | { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) }, | 57 | { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) }, |
| 58 | /* Display function name after trailing } */ | ||
| 59 | { TRACER_OPT(funcgraph-tail, TRACE_GRAPH_PRINT_TAIL) }, | ||
| 67 | { } /* Empty entry */ | 60 | { } /* Empty entry */ |
| 68 | }; | 61 | }; |
| 69 | 62 | ||
| 70 | static struct tracer_flags tracer_flags = { | 63 | static struct tracer_flags tracer_flags = { |
| 71 | /* Don't display overruns and proc by default */ | 64 | /* Don't display overruns, proc, or tail by default */ |
| 72 | .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD | | 65 | .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD | |
| 73 | TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS, | 66 | TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS, |
| 74 | .opts = trace_opts | 67 | .opts = trace_opts |
| @@ -1176,9 +1169,10 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
| 1176 | * If the return function does not have a matching entry, | 1169 | * If the return function does not have a matching entry, |
| 1177 | * then the entry was lost. Instead of just printing | 1170 | * then the entry was lost. Instead of just printing |
| 1178 | * the '}' and letting the user guess what function this | 1171 | * the '}' and letting the user guess what function this |
| 1179 | * belongs to, write out the function name. | 1172 | * belongs to, write out the function name. Always do |
| 1173 | * that if the funcgraph-tail option is enabled. | ||
| 1180 | */ | 1174 | */ |
| 1181 | if (func_match) { | 1175 | if (func_match && !(flags & TRACE_GRAPH_PRINT_TAIL)) { |
| 1182 | ret = trace_seq_puts(s, "}\n"); | 1176 | ret = trace_seq_puts(s, "}\n"); |
| 1183 | if (!ret) | 1177 | if (!ret) |
| 1184 | return TRACE_TYPE_PARTIAL_LINE; | 1178 | return TRACE_TYPE_PARTIAL_LINE; |
| @@ -1505,7 +1499,6 @@ static struct tracer graph_trace __tracer_data = { | |||
| 1505 | .pipe_open = graph_trace_open, | 1499 | .pipe_open = graph_trace_open, |
| 1506 | .close = graph_trace_close, | 1500 | .close = graph_trace_close, |
| 1507 | .pipe_close = graph_trace_close, | 1501 | .pipe_close = graph_trace_close, |
| 1508 | .wait_pipe = poll_wait_pipe, | ||
| 1509 | .init = graph_trace_init, | 1502 | .init = graph_trace_init, |
| 1510 | .reset = graph_trace_reset, | 1503 | .reset = graph_trace_reset, |
| 1511 | .print_line = print_graph_function, | 1504 | .print_line = print_graph_function, |
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 8ff02cbb892f..9bb104f748d0 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c | |||
| @@ -151,12 +151,6 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip, | |||
| 151 | 151 | ||
| 152 | atomic_dec(&data->disabled); | 152 | atomic_dec(&data->disabled); |
| 153 | } | 153 | } |
| 154 | |||
| 155 | static struct ftrace_ops trace_ops __read_mostly = | ||
| 156 | { | ||
| 157 | .func = irqsoff_tracer_call, | ||
| 158 | .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 159 | }; | ||
| 160 | #endif /* CONFIG_FUNCTION_TRACER */ | 154 | #endif /* CONFIG_FUNCTION_TRACER */ |
| 161 | 155 | ||
| 162 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 156 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| @@ -176,7 +170,7 @@ irqsoff_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) | |||
| 176 | for_each_possible_cpu(cpu) | 170 | for_each_possible_cpu(cpu) |
| 177 | per_cpu(tracing_cpu, cpu) = 0; | 171 | per_cpu(tracing_cpu, cpu) = 0; |
| 178 | 172 | ||
| 179 | tracing_max_latency = 0; | 173 | tr->max_latency = 0; |
| 180 | tracing_reset_online_cpus(&irqsoff_trace->trace_buffer); | 174 | tracing_reset_online_cpus(&irqsoff_trace->trace_buffer); |
| 181 | 175 | ||
| 182 | return start_irqsoff_tracer(irqsoff_trace, set); | 176 | return start_irqsoff_tracer(irqsoff_trace, set); |
| @@ -303,13 +297,13 @@ static void irqsoff_print_header(struct seq_file *s) | |||
| 303 | /* | 297 | /* |
| 304 | * Should this new latency be reported/recorded? | 298 | * Should this new latency be reported/recorded? |
| 305 | */ | 299 | */ |
| 306 | static int report_latency(cycle_t delta) | 300 | static int report_latency(struct trace_array *tr, cycle_t delta) |
| 307 | { | 301 | { |
| 308 | if (tracing_thresh) { | 302 | if (tracing_thresh) { |
| 309 | if (delta < tracing_thresh) | 303 | if (delta < tracing_thresh) |
| 310 | return 0; | 304 | return 0; |
| 311 | } else { | 305 | } else { |
| 312 | if (delta <= tracing_max_latency) | 306 | if (delta <= tr->max_latency) |
| 313 | return 0; | 307 | return 0; |
| 314 | } | 308 | } |
| 315 | return 1; | 309 | return 1; |
| @@ -333,13 +327,13 @@ check_critical_timing(struct trace_array *tr, | |||
| 333 | 327 | ||
| 334 | pc = preempt_count(); | 328 | pc = preempt_count(); |
| 335 | 329 | ||
| 336 | if (!report_latency(delta)) | 330 | if (!report_latency(tr, delta)) |
| 337 | goto out; | 331 | goto out; |
| 338 | 332 | ||
| 339 | raw_spin_lock_irqsave(&max_trace_lock, flags); | 333 | raw_spin_lock_irqsave(&max_trace_lock, flags); |
| 340 | 334 | ||
| 341 | /* check if we are still the max latency */ | 335 | /* check if we are still the max latency */ |
| 342 | if (!report_latency(delta)) | 336 | if (!report_latency(tr, delta)) |
| 343 | goto out_unlock; | 337 | goto out_unlock; |
| 344 | 338 | ||
| 345 | __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc); | 339 | __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc); |
| @@ -352,7 +346,7 @@ check_critical_timing(struct trace_array *tr, | |||
| 352 | data->critical_end = parent_ip; | 346 | data->critical_end = parent_ip; |
| 353 | 347 | ||
| 354 | if (likely(!is_tracing_stopped())) { | 348 | if (likely(!is_tracing_stopped())) { |
| 355 | tracing_max_latency = delta; | 349 | tr->max_latency = delta; |
| 356 | update_max_tr_single(tr, current, cpu); | 350 | update_max_tr_single(tr, current, cpu); |
| 357 | } | 351 | } |
| 358 | 352 | ||
| @@ -531,7 +525,7 @@ void trace_preempt_off(unsigned long a0, unsigned long a1) | |||
| 531 | } | 525 | } |
| 532 | #endif /* CONFIG_PREEMPT_TRACER */ | 526 | #endif /* CONFIG_PREEMPT_TRACER */ |
| 533 | 527 | ||
| 534 | static int register_irqsoff_function(int graph, int set) | 528 | static int register_irqsoff_function(struct trace_array *tr, int graph, int set) |
| 535 | { | 529 | { |
| 536 | int ret; | 530 | int ret; |
| 537 | 531 | ||
| @@ -543,7 +537,7 @@ static int register_irqsoff_function(int graph, int set) | |||
| 543 | ret = register_ftrace_graph(&irqsoff_graph_return, | 537 | ret = register_ftrace_graph(&irqsoff_graph_return, |
| 544 | &irqsoff_graph_entry); | 538 | &irqsoff_graph_entry); |
| 545 | else | 539 | else |
| 546 | ret = register_ftrace_function(&trace_ops); | 540 | ret = register_ftrace_function(tr->ops); |
| 547 | 541 | ||
| 548 | if (!ret) | 542 | if (!ret) |
| 549 | function_enabled = true; | 543 | function_enabled = true; |
| @@ -551,7 +545,7 @@ static int register_irqsoff_function(int graph, int set) | |||
| 551 | return ret; | 545 | return ret; |
| 552 | } | 546 | } |
| 553 | 547 | ||
| 554 | static void unregister_irqsoff_function(int graph) | 548 | static void unregister_irqsoff_function(struct trace_array *tr, int graph) |
| 555 | { | 549 | { |
| 556 | if (!function_enabled) | 550 | if (!function_enabled) |
| 557 | return; | 551 | return; |
| @@ -559,17 +553,17 @@ static void unregister_irqsoff_function(int graph) | |||
| 559 | if (graph) | 553 | if (graph) |
| 560 | unregister_ftrace_graph(); | 554 | unregister_ftrace_graph(); |
| 561 | else | 555 | else |
| 562 | unregister_ftrace_function(&trace_ops); | 556 | unregister_ftrace_function(tr->ops); |
| 563 | 557 | ||
| 564 | function_enabled = false; | 558 | function_enabled = false; |
| 565 | } | 559 | } |
| 566 | 560 | ||
| 567 | static void irqsoff_function_set(int set) | 561 | static void irqsoff_function_set(struct trace_array *tr, int set) |
| 568 | { | 562 | { |
| 569 | if (set) | 563 | if (set) |
| 570 | register_irqsoff_function(is_graph(), 1); | 564 | register_irqsoff_function(tr, is_graph(), 1); |
| 571 | else | 565 | else |
| 572 | unregister_irqsoff_function(is_graph()); | 566 | unregister_irqsoff_function(tr, is_graph()); |
| 573 | } | 567 | } |
| 574 | 568 | ||
| 575 | static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set) | 569 | static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set) |
| @@ -577,7 +571,7 @@ static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set) | |||
| 577 | struct tracer *tracer = tr->current_trace; | 571 | struct tracer *tracer = tr->current_trace; |
| 578 | 572 | ||
| 579 | if (mask & TRACE_ITER_FUNCTION) | 573 | if (mask & TRACE_ITER_FUNCTION) |
| 580 | irqsoff_function_set(set); | 574 | irqsoff_function_set(tr, set); |
| 581 | 575 | ||
| 582 | return trace_keep_overwrite(tracer, mask, set); | 576 | return trace_keep_overwrite(tracer, mask, set); |
| 583 | } | 577 | } |
| @@ -586,7 +580,7 @@ static int start_irqsoff_tracer(struct trace_array *tr, int graph) | |||
| 586 | { | 580 | { |
| 587 | int ret; | 581 | int ret; |
| 588 | 582 | ||
| 589 | ret = register_irqsoff_function(graph, 0); | 583 | ret = register_irqsoff_function(tr, graph, 0); |
| 590 | 584 | ||
| 591 | if (!ret && tracing_is_enabled()) | 585 | if (!ret && tracing_is_enabled()) |
| 592 | tracer_enabled = 1; | 586 | tracer_enabled = 1; |
| @@ -600,25 +594,37 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph) | |||
| 600 | { | 594 | { |
| 601 | tracer_enabled = 0; | 595 | tracer_enabled = 0; |
| 602 | 596 | ||
| 603 | unregister_irqsoff_function(graph); | 597 | unregister_irqsoff_function(tr, graph); |
| 604 | } | 598 | } |
| 605 | 599 | ||
| 606 | static void __irqsoff_tracer_init(struct trace_array *tr) | 600 | static bool irqsoff_busy; |
| 601 | |||
| 602 | static int __irqsoff_tracer_init(struct trace_array *tr) | ||
| 607 | { | 603 | { |
| 604 | if (irqsoff_busy) | ||
| 605 | return -EBUSY; | ||
| 606 | |||
| 608 | save_flags = trace_flags; | 607 | save_flags = trace_flags; |
| 609 | 608 | ||
| 610 | /* non overwrite screws up the latency tracers */ | 609 | /* non overwrite screws up the latency tracers */ |
| 611 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1); | 610 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1); |
| 612 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1); | 611 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1); |
| 613 | 612 | ||
| 614 | tracing_max_latency = 0; | 613 | tr->max_latency = 0; |
| 615 | irqsoff_trace = tr; | 614 | irqsoff_trace = tr; |
| 616 | /* make sure that the tracer is visible */ | 615 | /* make sure that the tracer is visible */ |
| 617 | smp_wmb(); | 616 | smp_wmb(); |
| 618 | tracing_reset_online_cpus(&tr->trace_buffer); | 617 | tracing_reset_online_cpus(&tr->trace_buffer); |
| 619 | 618 | ||
| 620 | if (start_irqsoff_tracer(tr, is_graph())) | 619 | ftrace_init_array_ops(tr, irqsoff_tracer_call); |
| 620 | |||
| 621 | /* Only toplevel instance supports graph tracing */ | ||
| 622 | if (start_irqsoff_tracer(tr, (tr->flags & TRACE_ARRAY_FL_GLOBAL && | ||
| 623 | is_graph()))) | ||
| 621 | printk(KERN_ERR "failed to start irqsoff tracer\n"); | 624 | printk(KERN_ERR "failed to start irqsoff tracer\n"); |
| 625 | |||
| 626 | irqsoff_busy = true; | ||
| 627 | return 0; | ||
| 622 | } | 628 | } |
| 623 | 629 | ||
| 624 | static void irqsoff_tracer_reset(struct trace_array *tr) | 630 | static void irqsoff_tracer_reset(struct trace_array *tr) |
| @@ -630,6 +636,9 @@ static void irqsoff_tracer_reset(struct trace_array *tr) | |||
| 630 | 636 | ||
| 631 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag); | 637 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag); |
| 632 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag); | 638 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag); |
| 639 | ftrace_reset_array_ops(tr); | ||
| 640 | |||
| 641 | irqsoff_busy = false; | ||
| 633 | } | 642 | } |
| 634 | 643 | ||
| 635 | static void irqsoff_tracer_start(struct trace_array *tr) | 644 | static void irqsoff_tracer_start(struct trace_array *tr) |
| @@ -647,8 +656,7 @@ static int irqsoff_tracer_init(struct trace_array *tr) | |||
| 647 | { | 656 | { |
| 648 | trace_type = TRACER_IRQS_OFF; | 657 | trace_type = TRACER_IRQS_OFF; |
| 649 | 658 | ||
| 650 | __irqsoff_tracer_init(tr); | 659 | return __irqsoff_tracer_init(tr); |
| 651 | return 0; | ||
| 652 | } | 660 | } |
| 653 | static struct tracer irqsoff_tracer __read_mostly = | 661 | static struct tracer irqsoff_tracer __read_mostly = |
| 654 | { | 662 | { |
| @@ -668,6 +676,7 @@ static struct tracer irqsoff_tracer __read_mostly = | |||
| 668 | #endif | 676 | #endif |
| 669 | .open = irqsoff_trace_open, | 677 | .open = irqsoff_trace_open, |
| 670 | .close = irqsoff_trace_close, | 678 | .close = irqsoff_trace_close, |
| 679 | .allow_instances = true, | ||
| 671 | .use_max_tr = true, | 680 | .use_max_tr = true, |
| 672 | }; | 681 | }; |
| 673 | # define register_irqsoff(trace) register_tracer(&trace) | 682 | # define register_irqsoff(trace) register_tracer(&trace) |
| @@ -680,8 +689,7 @@ static int preemptoff_tracer_init(struct trace_array *tr) | |||
| 680 | { | 689 | { |
| 681 | trace_type = TRACER_PREEMPT_OFF; | 690 | trace_type = TRACER_PREEMPT_OFF; |
| 682 | 691 | ||
| 683 | __irqsoff_tracer_init(tr); | 692 | return __irqsoff_tracer_init(tr); |
| 684 | return 0; | ||
| 685 | } | 693 | } |
| 686 | 694 | ||
| 687 | static struct tracer preemptoff_tracer __read_mostly = | 695 | static struct tracer preemptoff_tracer __read_mostly = |
| @@ -702,6 +710,7 @@ static struct tracer preemptoff_tracer __read_mostly = | |||
| 702 | #endif | 710 | #endif |
| 703 | .open = irqsoff_trace_open, | 711 | .open = irqsoff_trace_open, |
| 704 | .close = irqsoff_trace_close, | 712 | .close = irqsoff_trace_close, |
| 713 | .allow_instances = true, | ||
| 705 | .use_max_tr = true, | 714 | .use_max_tr = true, |
| 706 | }; | 715 | }; |
| 707 | # define register_preemptoff(trace) register_tracer(&trace) | 716 | # define register_preemptoff(trace) register_tracer(&trace) |
| @@ -716,8 +725,7 @@ static int preemptirqsoff_tracer_init(struct trace_array *tr) | |||
| 716 | { | 725 | { |
| 717 | trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF; | 726 | trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF; |
| 718 | 727 | ||
| 719 | __irqsoff_tracer_init(tr); | 728 | return __irqsoff_tracer_init(tr); |
| 720 | return 0; | ||
| 721 | } | 729 | } |
| 722 | 730 | ||
| 723 | static struct tracer preemptirqsoff_tracer __read_mostly = | 731 | static struct tracer preemptirqsoff_tracer __read_mostly = |
| @@ -738,6 +746,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly = | |||
| 738 | #endif | 746 | #endif |
| 739 | .open = irqsoff_trace_open, | 747 | .open = irqsoff_trace_open, |
| 740 | .close = irqsoff_trace_close, | 748 | .close = irqsoff_trace_close, |
| 749 | .allow_instances = true, | ||
| 741 | .use_max_tr = true, | 750 | .use_max_tr = true, |
| 742 | }; | 751 | }; |
| 743 | 752 | ||
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 903ae28962be..ef2fba1f46b5 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -1377,6 +1377,9 @@ static __init int kprobe_trace_self_tests_init(void) | |||
| 1377 | struct trace_kprobe *tk; | 1377 | struct trace_kprobe *tk; |
| 1378 | struct ftrace_event_file *file; | 1378 | struct ftrace_event_file *file; |
| 1379 | 1379 | ||
| 1380 | if (tracing_is_disabled()) | ||
| 1381 | return -ENODEV; | ||
| 1382 | |||
| 1380 | target = kprobe_trace_selftest_target; | 1383 | target = kprobe_trace_selftest_target; |
| 1381 | 1384 | ||
| 1382 | pr_info("Testing kprobe tracing: "); | 1385 | pr_info("Testing kprobe tracing: "); |
diff --git a/kernel/trace/trace_nop.c b/kernel/trace/trace_nop.c index 69a5cc94c01a..fcf0a9e48916 100644 --- a/kernel/trace/trace_nop.c +++ b/kernel/trace/trace_nop.c | |||
| @@ -91,7 +91,6 @@ struct tracer nop_trace __read_mostly = | |||
| 91 | .name = "nop", | 91 | .name = "nop", |
| 92 | .init = nop_trace_init, | 92 | .init = nop_trace_init, |
| 93 | .reset = nop_trace_reset, | 93 | .reset = nop_trace_reset, |
| 94 | .wait_pipe = poll_wait_pipe, | ||
| 95 | #ifdef CONFIG_FTRACE_SELFTEST | 94 | #ifdef CONFIG_FTRACE_SELFTEST |
| 96 | .selftest = trace_selftest_startup_nop, | 95 | .selftest = trace_selftest_startup_nop, |
| 97 | #endif | 96 | #endif |
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index a436de18aa99..f3dad80c20b2 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
| @@ -126,6 +126,34 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | |||
| 126 | EXPORT_SYMBOL_GPL(trace_seq_printf); | 126 | EXPORT_SYMBOL_GPL(trace_seq_printf); |
| 127 | 127 | ||
| 128 | /** | 128 | /** |
| 129 | * trace_seq_bitmask - put a list of longs as a bitmask print output | ||
| 130 | * @s: trace sequence descriptor | ||
| 131 | * @maskp: points to an array of unsigned longs that represent a bitmask | ||
| 132 | * @nmaskbits: The number of bits that are valid in @maskp | ||
| 133 | * | ||
| 134 | * It returns 0 if the trace oversizes the buffer's free | ||
| 135 | * space, 1 otherwise. | ||
| 136 | * | ||
| 137 | * Writes a ASCII representation of a bitmask string into @s. | ||
| 138 | */ | ||
| 139 | int | ||
| 140 | trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp, | ||
| 141 | int nmaskbits) | ||
| 142 | { | ||
| 143 | int len = (PAGE_SIZE - 1) - s->len; | ||
| 144 | int ret; | ||
| 145 | |||
| 146 | if (s->full || !len) | ||
| 147 | return 0; | ||
| 148 | |||
| 149 | ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits); | ||
| 150 | s->len += ret; | ||
| 151 | |||
| 152 | return 1; | ||
| 153 | } | ||
| 154 | EXPORT_SYMBOL_GPL(trace_seq_bitmask); | ||
| 155 | |||
| 156 | /** | ||
| 129 | * trace_seq_vprintf - sequence printing of trace information | 157 | * trace_seq_vprintf - sequence printing of trace information |
| 130 | * @s: trace sequence descriptor | 158 | * @s: trace sequence descriptor |
| 131 | * @fmt: printf format string | 159 | * @fmt: printf format string |
| @@ -399,6 +427,19 @@ EXPORT_SYMBOL(ftrace_print_symbols_seq_u64); | |||
| 399 | #endif | 427 | #endif |
| 400 | 428 | ||
| 401 | const char * | 429 | const char * |
| 430 | ftrace_print_bitmask_seq(struct trace_seq *p, void *bitmask_ptr, | ||
| 431 | unsigned int bitmask_size) | ||
| 432 | { | ||
| 433 | const char *ret = p->buffer + p->len; | ||
| 434 | |||
| 435 | trace_seq_bitmask(p, bitmask_ptr, bitmask_size * 8); | ||
| 436 | trace_seq_putc(p, 0); | ||
| 437 | |||
| 438 | return ret; | ||
| 439 | } | ||
| 440 | EXPORT_SYMBOL_GPL(ftrace_print_bitmask_seq); | ||
| 441 | |||
| 442 | const char * | ||
| 402 | ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len) | 443 | ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len) |
| 403 | { | 444 | { |
| 404 | int i; | 445 | int i; |
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index e14da5e97a69..19bd8928ce94 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c | |||
| @@ -130,15 +130,9 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip, | |||
| 130 | atomic_dec(&data->disabled); | 130 | atomic_dec(&data->disabled); |
| 131 | preempt_enable_notrace(); | 131 | preempt_enable_notrace(); |
| 132 | } | 132 | } |
| 133 | |||
| 134 | static struct ftrace_ops trace_ops __read_mostly = | ||
| 135 | { | ||
| 136 | .func = wakeup_tracer_call, | ||
| 137 | .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 138 | }; | ||
| 139 | #endif /* CONFIG_FUNCTION_TRACER */ | 133 | #endif /* CONFIG_FUNCTION_TRACER */ |
| 140 | 134 | ||
| 141 | static int register_wakeup_function(int graph, int set) | 135 | static int register_wakeup_function(struct trace_array *tr, int graph, int set) |
| 142 | { | 136 | { |
| 143 | int ret; | 137 | int ret; |
| 144 | 138 | ||
| @@ -150,7 +144,7 @@ static int register_wakeup_function(int graph, int set) | |||
| 150 | ret = register_ftrace_graph(&wakeup_graph_return, | 144 | ret = register_ftrace_graph(&wakeup_graph_return, |
| 151 | &wakeup_graph_entry); | 145 | &wakeup_graph_entry); |
| 152 | else | 146 | else |
| 153 | ret = register_ftrace_function(&trace_ops); | 147 | ret = register_ftrace_function(tr->ops); |
| 154 | 148 | ||
| 155 | if (!ret) | 149 | if (!ret) |
| 156 | function_enabled = true; | 150 | function_enabled = true; |
| @@ -158,7 +152,7 @@ static int register_wakeup_function(int graph, int set) | |||
| 158 | return ret; | 152 | return ret; |
| 159 | } | 153 | } |
| 160 | 154 | ||
| 161 | static void unregister_wakeup_function(int graph) | 155 | static void unregister_wakeup_function(struct trace_array *tr, int graph) |
| 162 | { | 156 | { |
| 163 | if (!function_enabled) | 157 | if (!function_enabled) |
| 164 | return; | 158 | return; |
| @@ -166,17 +160,17 @@ static void unregister_wakeup_function(int graph) | |||
| 166 | if (graph) | 160 | if (graph) |
| 167 | unregister_ftrace_graph(); | 161 | unregister_ftrace_graph(); |
| 168 | else | 162 | else |
| 169 | unregister_ftrace_function(&trace_ops); | 163 | unregister_ftrace_function(tr->ops); |
| 170 | 164 | ||
| 171 | function_enabled = false; | 165 | function_enabled = false; |
| 172 | } | 166 | } |
| 173 | 167 | ||
| 174 | static void wakeup_function_set(int set) | 168 | static void wakeup_function_set(struct trace_array *tr, int set) |
| 175 | { | 169 | { |
| 176 | if (set) | 170 | if (set) |
| 177 | register_wakeup_function(is_graph(), 1); | 171 | register_wakeup_function(tr, is_graph(), 1); |
| 178 | else | 172 | else |
| 179 | unregister_wakeup_function(is_graph()); | 173 | unregister_wakeup_function(tr, is_graph()); |
| 180 | } | 174 | } |
| 181 | 175 | ||
| 182 | static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set) | 176 | static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set) |
| @@ -184,16 +178,16 @@ static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set) | |||
| 184 | struct tracer *tracer = tr->current_trace; | 178 | struct tracer *tracer = tr->current_trace; |
| 185 | 179 | ||
| 186 | if (mask & TRACE_ITER_FUNCTION) | 180 | if (mask & TRACE_ITER_FUNCTION) |
| 187 | wakeup_function_set(set); | 181 | wakeup_function_set(tr, set); |
| 188 | 182 | ||
| 189 | return trace_keep_overwrite(tracer, mask, set); | 183 | return trace_keep_overwrite(tracer, mask, set); |
| 190 | } | 184 | } |
| 191 | 185 | ||
| 192 | static int start_func_tracer(int graph) | 186 | static int start_func_tracer(struct trace_array *tr, int graph) |
| 193 | { | 187 | { |
| 194 | int ret; | 188 | int ret; |
| 195 | 189 | ||
| 196 | ret = register_wakeup_function(graph, 0); | 190 | ret = register_wakeup_function(tr, graph, 0); |
| 197 | 191 | ||
| 198 | if (!ret && tracing_is_enabled()) | 192 | if (!ret && tracing_is_enabled()) |
| 199 | tracer_enabled = 1; | 193 | tracer_enabled = 1; |
| @@ -203,11 +197,11 @@ static int start_func_tracer(int graph) | |||
| 203 | return ret; | 197 | return ret; |
| 204 | } | 198 | } |
| 205 | 199 | ||
| 206 | static void stop_func_tracer(int graph) | 200 | static void stop_func_tracer(struct trace_array *tr, int graph) |
| 207 | { | 201 | { |
| 208 | tracer_enabled = 0; | 202 | tracer_enabled = 0; |
| 209 | 203 | ||
| 210 | unregister_wakeup_function(graph); | 204 | unregister_wakeup_function(tr, graph); |
| 211 | } | 205 | } |
| 212 | 206 | ||
| 213 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 207 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| @@ -221,12 +215,12 @@ wakeup_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) | |||
| 221 | if (!(is_graph() ^ set)) | 215 | if (!(is_graph() ^ set)) |
| 222 | return 0; | 216 | return 0; |
| 223 | 217 | ||
| 224 | stop_func_tracer(!set); | 218 | stop_func_tracer(tr, !set); |
| 225 | 219 | ||
| 226 | wakeup_reset(wakeup_trace); | 220 | wakeup_reset(wakeup_trace); |
| 227 | tracing_max_latency = 0; | 221 | tr->max_latency = 0; |
| 228 | 222 | ||
| 229 | return start_func_tracer(set); | 223 | return start_func_tracer(tr, set); |
| 230 | } | 224 | } |
| 231 | 225 | ||
| 232 | static int wakeup_graph_entry(struct ftrace_graph_ent *trace) | 226 | static int wakeup_graph_entry(struct ftrace_graph_ent *trace) |
| @@ -350,13 +344,13 @@ static void wakeup_print_header(struct seq_file *s) | |||
| 350 | /* | 344 | /* |
| 351 | * Should this new latency be reported/recorded? | 345 | * Should this new latency be reported/recorded? |
| 352 | */ | 346 | */ |
| 353 | static int report_latency(cycle_t delta) | 347 | static int report_latency(struct trace_array *tr, cycle_t delta) |
| 354 | { | 348 | { |
| 355 | if (tracing_thresh) { | 349 | if (tracing_thresh) { |
| 356 | if (delta < tracing_thresh) | 350 | if (delta < tracing_thresh) |
| 357 | return 0; | 351 | return 0; |
| 358 | } else { | 352 | } else { |
| 359 | if (delta <= tracing_max_latency) | 353 | if (delta <= tr->max_latency) |
| 360 | return 0; | 354 | return 0; |
| 361 | } | 355 | } |
| 362 | return 1; | 356 | return 1; |
| @@ -424,11 +418,11 @@ probe_wakeup_sched_switch(void *ignore, | |||
| 424 | T1 = ftrace_now(cpu); | 418 | T1 = ftrace_now(cpu); |
| 425 | delta = T1-T0; | 419 | delta = T1-T0; |
| 426 | 420 | ||
| 427 | if (!report_latency(delta)) | 421 | if (!report_latency(wakeup_trace, delta)) |
| 428 | goto out_unlock; | 422 | goto out_unlock; |
| 429 | 423 | ||
| 430 | if (likely(!is_tracing_stopped())) { | 424 | if (likely(!is_tracing_stopped())) { |
| 431 | tracing_max_latency = delta; | 425 | wakeup_trace->max_latency = delta; |
| 432 | update_max_tr(wakeup_trace, wakeup_task, wakeup_cpu); | 426 | update_max_tr(wakeup_trace, wakeup_task, wakeup_cpu); |
| 433 | } | 427 | } |
| 434 | 428 | ||
| @@ -587,7 +581,7 @@ static void start_wakeup_tracer(struct trace_array *tr) | |||
| 587 | */ | 581 | */ |
| 588 | smp_wmb(); | 582 | smp_wmb(); |
| 589 | 583 | ||
| 590 | if (start_func_tracer(is_graph())) | 584 | if (start_func_tracer(tr, is_graph())) |
| 591 | printk(KERN_ERR "failed to start wakeup tracer\n"); | 585 | printk(KERN_ERR "failed to start wakeup tracer\n"); |
| 592 | 586 | ||
| 593 | return; | 587 | return; |
| @@ -600,13 +594,15 @@ fail_deprobe: | |||
| 600 | static void stop_wakeup_tracer(struct trace_array *tr) | 594 | static void stop_wakeup_tracer(struct trace_array *tr) |
| 601 | { | 595 | { |
| 602 | tracer_enabled = 0; | 596 | tracer_enabled = 0; |
| 603 | stop_func_tracer(is_graph()); | 597 | stop_func_tracer(tr, is_graph()); |
| 604 | unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL); | 598 | unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL); |
| 605 | unregister_trace_sched_wakeup_new(probe_wakeup, NULL); | 599 | unregister_trace_sched_wakeup_new(probe_wakeup, NULL); |
| 606 | unregister_trace_sched_wakeup(probe_wakeup, NULL); | 600 | unregister_trace_sched_wakeup(probe_wakeup, NULL); |
| 607 | unregister_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL); | 601 | unregister_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL); |
| 608 | } | 602 | } |
| 609 | 603 | ||
| 604 | static bool wakeup_busy; | ||
| 605 | |||
| 610 | static int __wakeup_tracer_init(struct trace_array *tr) | 606 | static int __wakeup_tracer_init(struct trace_array *tr) |
| 611 | { | 607 | { |
| 612 | save_flags = trace_flags; | 608 | save_flags = trace_flags; |
| @@ -615,14 +611,20 @@ static int __wakeup_tracer_init(struct trace_array *tr) | |||
| 615 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1); | 611 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1); |
| 616 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1); | 612 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1); |
| 617 | 613 | ||
| 618 | tracing_max_latency = 0; | 614 | tr->max_latency = 0; |
| 619 | wakeup_trace = tr; | 615 | wakeup_trace = tr; |
| 616 | ftrace_init_array_ops(tr, wakeup_tracer_call); | ||
| 620 | start_wakeup_tracer(tr); | 617 | start_wakeup_tracer(tr); |
| 618 | |||
| 619 | wakeup_busy = true; | ||
| 621 | return 0; | 620 | return 0; |
| 622 | } | 621 | } |
| 623 | 622 | ||
| 624 | static int wakeup_tracer_init(struct trace_array *tr) | 623 | static int wakeup_tracer_init(struct trace_array *tr) |
| 625 | { | 624 | { |
| 625 | if (wakeup_busy) | ||
| 626 | return -EBUSY; | ||
| 627 | |||
| 626 | wakeup_dl = 0; | 628 | wakeup_dl = 0; |
| 627 | wakeup_rt = 0; | 629 | wakeup_rt = 0; |
| 628 | return __wakeup_tracer_init(tr); | 630 | return __wakeup_tracer_init(tr); |
| @@ -630,6 +632,9 @@ static int wakeup_tracer_init(struct trace_array *tr) | |||
| 630 | 632 | ||
| 631 | static int wakeup_rt_tracer_init(struct trace_array *tr) | 633 | static int wakeup_rt_tracer_init(struct trace_array *tr) |
| 632 | { | 634 | { |
| 635 | if (wakeup_busy) | ||
| 636 | return -EBUSY; | ||
| 637 | |||
| 633 | wakeup_dl = 0; | 638 | wakeup_dl = 0; |
| 634 | wakeup_rt = 1; | 639 | wakeup_rt = 1; |
| 635 | return __wakeup_tracer_init(tr); | 640 | return __wakeup_tracer_init(tr); |
| @@ -637,6 +642,9 @@ static int wakeup_rt_tracer_init(struct trace_array *tr) | |||
| 637 | 642 | ||
| 638 | static int wakeup_dl_tracer_init(struct trace_array *tr) | 643 | static int wakeup_dl_tracer_init(struct trace_array *tr) |
| 639 | { | 644 | { |
| 645 | if (wakeup_busy) | ||
| 646 | return -EBUSY; | ||
| 647 | |||
| 640 | wakeup_dl = 1; | 648 | wakeup_dl = 1; |
| 641 | wakeup_rt = 0; | 649 | wakeup_rt = 0; |
| 642 | return __wakeup_tracer_init(tr); | 650 | return __wakeup_tracer_init(tr); |
| @@ -653,6 +661,8 @@ static void wakeup_tracer_reset(struct trace_array *tr) | |||
| 653 | 661 | ||
| 654 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag); | 662 | set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag); |
| 655 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag); | 663 | set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag); |
| 664 | ftrace_reset_array_ops(tr); | ||
| 665 | wakeup_busy = false; | ||
| 656 | } | 666 | } |
| 657 | 667 | ||
| 658 | static void wakeup_tracer_start(struct trace_array *tr) | 668 | static void wakeup_tracer_start(struct trace_array *tr) |
| @@ -684,6 +694,7 @@ static struct tracer wakeup_tracer __read_mostly = | |||
| 684 | #endif | 694 | #endif |
| 685 | .open = wakeup_trace_open, | 695 | .open = wakeup_trace_open, |
| 686 | .close = wakeup_trace_close, | 696 | .close = wakeup_trace_close, |
| 697 | .allow_instances = true, | ||
| 687 | .use_max_tr = true, | 698 | .use_max_tr = true, |
| 688 | }; | 699 | }; |
| 689 | 700 | ||
| @@ -694,7 +705,6 @@ static struct tracer wakeup_rt_tracer __read_mostly = | |||
| 694 | .reset = wakeup_tracer_reset, | 705 | .reset = wakeup_tracer_reset, |
| 695 | .start = wakeup_tracer_start, | 706 | .start = wakeup_tracer_start, |
| 696 | .stop = wakeup_tracer_stop, | 707 | .stop = wakeup_tracer_stop, |
| 697 | .wait_pipe = poll_wait_pipe, | ||
| 698 | .print_max = true, | 708 | .print_max = true, |
| 699 | .print_header = wakeup_print_header, | 709 | .print_header = wakeup_print_header, |
| 700 | .print_line = wakeup_print_line, | 710 | .print_line = wakeup_print_line, |
| @@ -706,6 +716,7 @@ static struct tracer wakeup_rt_tracer __read_mostly = | |||
| 706 | #endif | 716 | #endif |
| 707 | .open = wakeup_trace_open, | 717 | .open = wakeup_trace_open, |
| 708 | .close = wakeup_trace_close, | 718 | .close = wakeup_trace_close, |
| 719 | .allow_instances = true, | ||
| 709 | .use_max_tr = true, | 720 | .use_max_tr = true, |
| 710 | }; | 721 | }; |
| 711 | 722 | ||
| @@ -716,7 +727,6 @@ static struct tracer wakeup_dl_tracer __read_mostly = | |||
| 716 | .reset = wakeup_tracer_reset, | 727 | .reset = wakeup_tracer_reset, |
| 717 | .start = wakeup_tracer_start, | 728 | .start = wakeup_tracer_start, |
| 718 | .stop = wakeup_tracer_stop, | 729 | .stop = wakeup_tracer_stop, |
| 719 | .wait_pipe = poll_wait_pipe, | ||
| 720 | .print_max = true, | 730 | .print_max = true, |
| 721 | .print_header = wakeup_print_header, | 731 | .print_header = wakeup_print_header, |
| 722 | .print_line = wakeup_print_line, | 732 | .print_line = wakeup_print_line, |
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index e98fca60974f..5ef60499dc8e 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
| @@ -65,7 +65,7 @@ static int trace_test_buffer(struct trace_buffer *buf, unsigned long *count) | |||
| 65 | 65 | ||
| 66 | /* Don't allow flipping of max traces now */ | 66 | /* Don't allow flipping of max traces now */ |
| 67 | local_irq_save(flags); | 67 | local_irq_save(flags); |
| 68 | arch_spin_lock(&ftrace_max_lock); | 68 | arch_spin_lock(&buf->tr->max_lock); |
| 69 | 69 | ||
| 70 | cnt = ring_buffer_entries(buf->buffer); | 70 | cnt = ring_buffer_entries(buf->buffer); |
| 71 | 71 | ||
| @@ -83,7 +83,7 @@ static int trace_test_buffer(struct trace_buffer *buf, unsigned long *count) | |||
| 83 | break; | 83 | break; |
| 84 | } | 84 | } |
| 85 | tracing_on(); | 85 | tracing_on(); |
| 86 | arch_spin_unlock(&ftrace_max_lock); | 86 | arch_spin_unlock(&buf->tr->max_lock); |
| 87 | local_irq_restore(flags); | 87 | local_irq_restore(flags); |
| 88 | 88 | ||
| 89 | if (count) | 89 | if (count) |
| @@ -161,11 +161,6 @@ static struct ftrace_ops test_probe3 = { | |||
| 161 | .flags = FTRACE_OPS_FL_RECURSION_SAFE, | 161 | .flags = FTRACE_OPS_FL_RECURSION_SAFE, |
| 162 | }; | 162 | }; |
| 163 | 163 | ||
| 164 | static struct ftrace_ops test_global = { | ||
| 165 | .func = trace_selftest_test_global_func, | ||
| 166 | .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 167 | }; | ||
| 168 | |||
| 169 | static void print_counts(void) | 164 | static void print_counts(void) |
| 170 | { | 165 | { |
| 171 | printk("(%d %d %d %d %d) ", | 166 | printk("(%d %d %d %d %d) ", |
| @@ -185,7 +180,7 @@ static void reset_counts(void) | |||
| 185 | trace_selftest_test_dyn_cnt = 0; | 180 | trace_selftest_test_dyn_cnt = 0; |
| 186 | } | 181 | } |
| 187 | 182 | ||
| 188 | static int trace_selftest_ops(int cnt) | 183 | static int trace_selftest_ops(struct trace_array *tr, int cnt) |
| 189 | { | 184 | { |
| 190 | int save_ftrace_enabled = ftrace_enabled; | 185 | int save_ftrace_enabled = ftrace_enabled; |
| 191 | struct ftrace_ops *dyn_ops; | 186 | struct ftrace_ops *dyn_ops; |
| @@ -220,7 +215,11 @@ static int trace_selftest_ops(int cnt) | |||
| 220 | register_ftrace_function(&test_probe1); | 215 | register_ftrace_function(&test_probe1); |
| 221 | register_ftrace_function(&test_probe2); | 216 | register_ftrace_function(&test_probe2); |
| 222 | register_ftrace_function(&test_probe3); | 217 | register_ftrace_function(&test_probe3); |
| 223 | register_ftrace_function(&test_global); | 218 | /* First time we are running with main function */ |
| 219 | if (cnt > 1) { | ||
| 220 | ftrace_init_array_ops(tr, trace_selftest_test_global_func); | ||
| 221 | register_ftrace_function(tr->ops); | ||
| 222 | } | ||
| 224 | 223 | ||
| 225 | DYN_FTRACE_TEST_NAME(); | 224 | DYN_FTRACE_TEST_NAME(); |
| 226 | 225 | ||
| @@ -232,8 +231,10 @@ static int trace_selftest_ops(int cnt) | |||
| 232 | goto out; | 231 | goto out; |
| 233 | if (trace_selftest_test_probe3_cnt != 1) | 232 | if (trace_selftest_test_probe3_cnt != 1) |
| 234 | goto out; | 233 | goto out; |
| 235 | if (trace_selftest_test_global_cnt == 0) | 234 | if (cnt > 1) { |
| 236 | goto out; | 235 | if (trace_selftest_test_global_cnt == 0) |
| 236 | goto out; | ||
| 237 | } | ||
| 237 | 238 | ||
| 238 | DYN_FTRACE_TEST_NAME2(); | 239 | DYN_FTRACE_TEST_NAME2(); |
| 239 | 240 | ||
| @@ -269,8 +270,10 @@ static int trace_selftest_ops(int cnt) | |||
| 269 | goto out_free; | 270 | goto out_free; |
| 270 | if (trace_selftest_test_probe3_cnt != 3) | 271 | if (trace_selftest_test_probe3_cnt != 3) |
| 271 | goto out_free; | 272 | goto out_free; |
| 272 | if (trace_selftest_test_global_cnt == 0) | 273 | if (cnt > 1) { |
| 273 | goto out; | 274 | if (trace_selftest_test_global_cnt == 0) |
| 275 | goto out; | ||
| 276 | } | ||
| 274 | if (trace_selftest_test_dyn_cnt == 0) | 277 | if (trace_selftest_test_dyn_cnt == 0) |
| 275 | goto out_free; | 278 | goto out_free; |
| 276 | 279 | ||
| @@ -295,7 +298,9 @@ static int trace_selftest_ops(int cnt) | |||
| 295 | unregister_ftrace_function(&test_probe1); | 298 | unregister_ftrace_function(&test_probe1); |
| 296 | unregister_ftrace_function(&test_probe2); | 299 | unregister_ftrace_function(&test_probe2); |
| 297 | unregister_ftrace_function(&test_probe3); | 300 | unregister_ftrace_function(&test_probe3); |
| 298 | unregister_ftrace_function(&test_global); | 301 | if (cnt > 1) |
| 302 | unregister_ftrace_function(tr->ops); | ||
| 303 | ftrace_reset_array_ops(tr); | ||
| 299 | 304 | ||
| 300 | /* Make sure everything is off */ | 305 | /* Make sure everything is off */ |
| 301 | reset_counts(); | 306 | reset_counts(); |
| @@ -315,9 +320,9 @@ static int trace_selftest_ops(int cnt) | |||
| 315 | } | 320 | } |
| 316 | 321 | ||
| 317 | /* Test dynamic code modification and ftrace filters */ | 322 | /* Test dynamic code modification and ftrace filters */ |
| 318 | int trace_selftest_startup_dynamic_tracing(struct tracer *trace, | 323 | static int trace_selftest_startup_dynamic_tracing(struct tracer *trace, |
| 319 | struct trace_array *tr, | 324 | struct trace_array *tr, |
| 320 | int (*func)(void)) | 325 | int (*func)(void)) |
| 321 | { | 326 | { |
| 322 | int save_ftrace_enabled = ftrace_enabled; | 327 | int save_ftrace_enabled = ftrace_enabled; |
| 323 | unsigned long count; | 328 | unsigned long count; |
| @@ -388,7 +393,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, | |||
| 388 | } | 393 | } |
| 389 | 394 | ||
| 390 | /* Test the ops with global tracing running */ | 395 | /* Test the ops with global tracing running */ |
| 391 | ret = trace_selftest_ops(1); | 396 | ret = trace_selftest_ops(tr, 1); |
| 392 | trace->reset(tr); | 397 | trace->reset(tr); |
| 393 | 398 | ||
| 394 | out: | 399 | out: |
| @@ -399,7 +404,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, | |||
| 399 | 404 | ||
| 400 | /* Test the ops with global tracing off */ | 405 | /* Test the ops with global tracing off */ |
| 401 | if (!ret) | 406 | if (!ret) |
| 402 | ret = trace_selftest_ops(2); | 407 | ret = trace_selftest_ops(tr, 2); |
| 403 | 408 | ||
| 404 | return ret; | 409 | return ret; |
| 405 | } | 410 | } |
| @@ -802,7 +807,7 @@ out: | |||
| 802 | int | 807 | int |
| 803 | trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) | 808 | trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) |
| 804 | { | 809 | { |
| 805 | unsigned long save_max = tracing_max_latency; | 810 | unsigned long save_max = tr->max_latency; |
| 806 | unsigned long count; | 811 | unsigned long count; |
| 807 | int ret; | 812 | int ret; |
| 808 | 813 | ||
| @@ -814,7 +819,7 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) | |||
| 814 | } | 819 | } |
| 815 | 820 | ||
| 816 | /* reset the max latency */ | 821 | /* reset the max latency */ |
| 817 | tracing_max_latency = 0; | 822 | tr->max_latency = 0; |
| 818 | /* disable interrupts for a bit */ | 823 | /* disable interrupts for a bit */ |
| 819 | local_irq_disable(); | 824 | local_irq_disable(); |
| 820 | udelay(100); | 825 | udelay(100); |
| @@ -841,7 +846,7 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) | |||
| 841 | ret = -1; | 846 | ret = -1; |
| 842 | } | 847 | } |
| 843 | 848 | ||
| 844 | tracing_max_latency = save_max; | 849 | tr->max_latency = save_max; |
| 845 | 850 | ||
| 846 | return ret; | 851 | return ret; |
| 847 | } | 852 | } |
| @@ -851,7 +856,7 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) | |||
| 851 | int | 856 | int |
| 852 | trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) | 857 | trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) |
| 853 | { | 858 | { |
| 854 | unsigned long save_max = tracing_max_latency; | 859 | unsigned long save_max = tr->max_latency; |
| 855 | unsigned long count; | 860 | unsigned long count; |
| 856 | int ret; | 861 | int ret; |
| 857 | 862 | ||
| @@ -876,7 +881,7 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) | |||
| 876 | } | 881 | } |
| 877 | 882 | ||
| 878 | /* reset the max latency */ | 883 | /* reset the max latency */ |
| 879 | tracing_max_latency = 0; | 884 | tr->max_latency = 0; |
| 880 | /* disable preemption for a bit */ | 885 | /* disable preemption for a bit */ |
| 881 | preempt_disable(); | 886 | preempt_disable(); |
| 882 | udelay(100); | 887 | udelay(100); |
| @@ -903,7 +908,7 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) | |||
| 903 | ret = -1; | 908 | ret = -1; |
| 904 | } | 909 | } |
| 905 | 910 | ||
| 906 | tracing_max_latency = save_max; | 911 | tr->max_latency = save_max; |
| 907 | 912 | ||
| 908 | return ret; | 913 | return ret; |
| 909 | } | 914 | } |
| @@ -913,7 +918,7 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) | |||
| 913 | int | 918 | int |
| 914 | trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *tr) | 919 | trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *tr) |
| 915 | { | 920 | { |
| 916 | unsigned long save_max = tracing_max_latency; | 921 | unsigned long save_max = tr->max_latency; |
| 917 | unsigned long count; | 922 | unsigned long count; |
| 918 | int ret; | 923 | int ret; |
| 919 | 924 | ||
| @@ -938,7 +943,7 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array * | |||
| 938 | } | 943 | } |
| 939 | 944 | ||
| 940 | /* reset the max latency */ | 945 | /* reset the max latency */ |
| 941 | tracing_max_latency = 0; | 946 | tr->max_latency = 0; |
| 942 | 947 | ||
| 943 | /* disable preemption and interrupts for a bit */ | 948 | /* disable preemption and interrupts for a bit */ |
| 944 | preempt_disable(); | 949 | preempt_disable(); |
| @@ -973,7 +978,7 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array * | |||
| 973 | } | 978 | } |
| 974 | 979 | ||
| 975 | /* do the test by disabling interrupts first this time */ | 980 | /* do the test by disabling interrupts first this time */ |
| 976 | tracing_max_latency = 0; | 981 | tr->max_latency = 0; |
| 977 | tracing_start(); | 982 | tracing_start(); |
| 978 | trace->start(tr); | 983 | trace->start(tr); |
| 979 | 984 | ||
| @@ -1004,7 +1009,7 @@ out: | |||
| 1004 | tracing_start(); | 1009 | tracing_start(); |
| 1005 | out_no_start: | 1010 | out_no_start: |
| 1006 | trace->reset(tr); | 1011 | trace->reset(tr); |
| 1007 | tracing_max_latency = save_max; | 1012 | tr->max_latency = save_max; |
| 1008 | 1013 | ||
| 1009 | return ret; | 1014 | return ret; |
| 1010 | } | 1015 | } |
| @@ -1057,7 +1062,7 @@ static int trace_wakeup_test_thread(void *data) | |||
| 1057 | int | 1062 | int |
| 1058 | trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) | 1063 | trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) |
| 1059 | { | 1064 | { |
| 1060 | unsigned long save_max = tracing_max_latency; | 1065 | unsigned long save_max = tr->max_latency; |
| 1061 | struct task_struct *p; | 1066 | struct task_struct *p; |
| 1062 | struct completion is_ready; | 1067 | struct completion is_ready; |
| 1063 | unsigned long count; | 1068 | unsigned long count; |
| @@ -1083,7 +1088,7 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) | |||
| 1083 | } | 1088 | } |
| 1084 | 1089 | ||
| 1085 | /* reset the max latency */ | 1090 | /* reset the max latency */ |
| 1086 | tracing_max_latency = 0; | 1091 | tr->max_latency = 0; |
| 1087 | 1092 | ||
| 1088 | while (p->on_rq) { | 1093 | while (p->on_rq) { |
| 1089 | /* | 1094 | /* |
| @@ -1113,7 +1118,7 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) | |||
| 1113 | trace->reset(tr); | 1118 | trace->reset(tr); |
| 1114 | tracing_start(); | 1119 | tracing_start(); |
| 1115 | 1120 | ||
| 1116 | tracing_max_latency = save_max; | 1121 | tr->max_latency = save_max; |
| 1117 | 1122 | ||
| 1118 | /* kill the thread */ | 1123 | /* kill the thread */ |
| 1119 | kthread_stop(p); | 1124 | kthread_stop(p); |
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 21b320e5d163..8a4e5cb66a4c 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c | |||
| @@ -51,11 +51,33 @@ static DEFINE_MUTEX(stack_sysctl_mutex); | |||
| 51 | int stack_tracer_enabled; | 51 | int stack_tracer_enabled; |
| 52 | static int last_stack_tracer_enabled; | 52 | static int last_stack_tracer_enabled; |
| 53 | 53 | ||
| 54 | static inline void print_max_stack(void) | ||
| 55 | { | ||
| 56 | long i; | ||
| 57 | int size; | ||
| 58 | |||
| 59 | pr_emerg(" Depth Size Location (%d entries)\n" | ||
| 60 | " ----- ---- --------\n", | ||
| 61 | max_stack_trace.nr_entries - 1); | ||
| 62 | |||
| 63 | for (i = 0; i < max_stack_trace.nr_entries; i++) { | ||
| 64 | if (stack_dump_trace[i] == ULONG_MAX) | ||
| 65 | break; | ||
| 66 | if (i+1 == max_stack_trace.nr_entries || | ||
| 67 | stack_dump_trace[i+1] == ULONG_MAX) | ||
| 68 | size = stack_dump_index[i]; | ||
| 69 | else | ||
| 70 | size = stack_dump_index[i] - stack_dump_index[i+1]; | ||
| 71 | |||
| 72 | pr_emerg("%3ld) %8d %5d %pS\n", i, stack_dump_index[i], | ||
| 73 | size, (void *)stack_dump_trace[i]); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 54 | static inline void | 77 | static inline void |
| 55 | check_stack(unsigned long ip, unsigned long *stack) | 78 | check_stack(unsigned long ip, unsigned long *stack) |
| 56 | { | 79 | { |
| 57 | unsigned long this_size, flags; | 80 | unsigned long this_size, flags; unsigned long *p, *top, *start; |
| 58 | unsigned long *p, *top, *start; | ||
| 59 | static int tracer_frame; | 81 | static int tracer_frame; |
| 60 | int frame_size = ACCESS_ONCE(tracer_frame); | 82 | int frame_size = ACCESS_ONCE(tracer_frame); |
| 61 | int i; | 83 | int i; |
| @@ -85,8 +107,12 @@ check_stack(unsigned long ip, unsigned long *stack) | |||
| 85 | 107 | ||
| 86 | max_stack_size = this_size; | 108 | max_stack_size = this_size; |
| 87 | 109 | ||
| 88 | max_stack_trace.nr_entries = 0; | 110 | max_stack_trace.nr_entries = 0; |
| 89 | max_stack_trace.skip = 3; | 111 | |
| 112 | if (using_ftrace_ops_list_func()) | ||
| 113 | max_stack_trace.skip = 4; | ||
| 114 | else | ||
| 115 | max_stack_trace.skip = 3; | ||
| 90 | 116 | ||
| 91 | save_stack_trace(&max_stack_trace); | 117 | save_stack_trace(&max_stack_trace); |
| 92 | 118 | ||
| @@ -145,8 +171,12 @@ check_stack(unsigned long ip, unsigned long *stack) | |||
| 145 | i++; | 171 | i++; |
| 146 | } | 172 | } |
| 147 | 173 | ||
| 148 | BUG_ON(current != &init_task && | 174 | if ((current != &init_task && |
| 149 | *(end_of_stack(current)) != STACK_END_MAGIC); | 175 | *(end_of_stack(current)) != STACK_END_MAGIC)) { |
| 176 | print_max_stack(); | ||
| 177 | BUG(); | ||
| 178 | } | ||
| 179 | |||
| 150 | out: | 180 | out: |
| 151 | arch_spin_unlock(&max_stack_lock); | 181 | arch_spin_unlock(&max_stack_lock); |
| 152 | local_irq_restore(flags); | 182 | local_irq_restore(flags); |
