diff options
28 files changed, 856 insertions, 518 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1d28812260cd..51138b3dc8cc 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -778,6 +778,13 @@ and is between 256 and 4096 characters. It is defined in the file | |||
| 778 | by the set_ftrace_notrace file in the debugfs | 778 | by the set_ftrace_notrace file in the debugfs |
| 779 | tracing directory. | 779 | tracing directory. |
| 780 | 780 | ||
| 781 | ftrace_graph_filter=[function-list] | ||
| 782 | [FTRACE] Limit the top level callers functions traced | ||
| 783 | by the function graph tracer at boot up. | ||
| 784 | function-list is a comma separated list of functions | ||
| 785 | that can be changed at run time by the | ||
| 786 | set_graph_function file in the debugfs tracing directory. | ||
| 787 | |||
| 781 | gamecon.map[2|3]= | 788 | gamecon.map[2|3]= |
| 782 | [HW,JOY] Multisystem joystick and NES/SNES/PSX pad | 789 | [HW,JOY] Multisystem joystick and NES/SNES/PSX pad |
| 783 | support via parallel port (up to 5 devices per port) | 790 | support via parallel port (up to 5 devices per port) |
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt index 7003e10f10f5..641a1ef2a7ff 100644 --- a/Documentation/trace/ftrace-design.txt +++ b/Documentation/trace/ftrace-design.txt | |||
| @@ -213,10 +213,19 @@ If you can't trace NMI functions, then skip this option. | |||
| 213 | <details to be filled> | 213 | <details to be filled> |
| 214 | 214 | ||
| 215 | 215 | ||
| 216 | HAVE_FTRACE_SYSCALLS | 216 | HAVE_SYSCALL_TRACEPOINTS |
| 217 | --------------------- | 217 | --------------------- |
| 218 | 218 | ||
| 219 | <details to be filled> | 219 | You need very few things to get the syscalls tracing in an arch. |
| 220 | |||
| 221 | - Have a NR_syscalls variable in <asm/unistd.h> that provides the number | ||
| 222 | of syscalls supported by the arch. | ||
| 223 | - Implement arch_syscall_addr() that resolves a syscall address from a | ||
| 224 | syscall number. | ||
| 225 | - Support the TIF_SYSCALL_TRACEPOINT thread flags | ||
| 226 | - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace | ||
| 227 | in the ptrace syscalls tracing path. | ||
| 228 | - Tag this arch as HAVE_SYSCALL_TRACEPOINTS. | ||
| 220 | 229 | ||
| 221 | 230 | ||
| 222 | HAVE_FTRACE_MCOUNT_RECORD | 231 | HAVE_FTRACE_MCOUNT_RECORD |
| @@ -379,6 +379,7 @@ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exc | |||
| 379 | PHONY += scripts_basic | 379 | PHONY += scripts_basic |
| 380 | scripts_basic: | 380 | scripts_basic: |
| 381 | $(Q)$(MAKE) $(build)=scripts/basic | 381 | $(Q)$(MAKE) $(build)=scripts/basic |
| 382 | $(Q)rm -f .tmp_quiet_recordmcount | ||
| 382 | 383 | ||
| 383 | # To avoid any implicit rule to kick in, define an empty command. | 384 | # To avoid any implicit rule to kick in, define an empty command. |
| 384 | scripts/basic/%: scripts_basic ; | 385 | scripts/basic/%: scripts_basic ; |
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index f5fe34dd821b..5a82bc68193e 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
| @@ -203,73 +203,10 @@ out: | |||
| 203 | 203 | ||
| 204 | #ifdef CONFIG_FTRACE_SYSCALLS | 204 | #ifdef CONFIG_FTRACE_SYSCALLS |
| 205 | 205 | ||
| 206 | extern unsigned long __start_syscalls_metadata[]; | ||
| 207 | extern unsigned long __stop_syscalls_metadata[]; | ||
| 208 | extern unsigned int sys_call_table[]; | 206 | extern unsigned int sys_call_table[]; |
| 209 | 207 | ||
| 210 | static struct syscall_metadata **syscalls_metadata; | 208 | unsigned long __init arch_syscall_addr(int nr) |
| 211 | |||
| 212 | struct syscall_metadata *syscall_nr_to_meta(int nr) | ||
| 213 | { | ||
| 214 | if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) | ||
| 215 | return NULL; | ||
| 216 | |||
| 217 | return syscalls_metadata[nr]; | ||
| 218 | } | ||
| 219 | |||
| 220 | int syscall_name_to_nr(char *name) | ||
| 221 | { | ||
| 222 | int i; | ||
| 223 | |||
| 224 | if (!syscalls_metadata) | ||
| 225 | return -1; | ||
| 226 | for (i = 0; i < NR_syscalls; i++) | ||
| 227 | if (syscalls_metadata[i]) | ||
| 228 | if (!strcmp(syscalls_metadata[i]->name, name)) | ||
| 229 | return i; | ||
| 230 | return -1; | ||
| 231 | } | ||
| 232 | |||
| 233 | void set_syscall_enter_id(int num, int id) | ||
| 234 | { | ||
| 235 | syscalls_metadata[num]->enter_id = id; | ||
| 236 | } | ||
| 237 | |||
| 238 | void set_syscall_exit_id(int num, int id) | ||
| 239 | { | 209 | { |
| 240 | syscalls_metadata[num]->exit_id = id; | 210 | return (unsigned long)sys_call_table[nr]; |
| 241 | } | ||
| 242 | |||
| 243 | static struct syscall_metadata *find_syscall_meta(unsigned long syscall) | ||
| 244 | { | ||
| 245 | struct syscall_metadata *start; | ||
| 246 | struct syscall_metadata *stop; | ||
| 247 | char str[KSYM_SYMBOL_LEN]; | ||
| 248 | |||
| 249 | start = (struct syscall_metadata *)__start_syscalls_metadata; | ||
| 250 | stop = (struct syscall_metadata *)__stop_syscalls_metadata; | ||
| 251 | kallsyms_lookup(syscall, NULL, NULL, NULL, str); | ||
| 252 | |||
| 253 | for ( ; start < stop; start++) { | ||
| 254 | if (start->name && !strcmp(start->name + 3, str + 3)) | ||
| 255 | return start; | ||
| 256 | } | ||
| 257 | return NULL; | ||
| 258 | } | ||
| 259 | |||
| 260 | static int __init arch_init_ftrace_syscalls(void) | ||
| 261 | { | ||
| 262 | struct syscall_metadata *meta; | ||
| 263 | int i; | ||
| 264 | syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls, | ||
| 265 | GFP_KERNEL); | ||
| 266 | if (!syscalls_metadata) | ||
| 267 | return -ENOMEM; | ||
| 268 | for (i = 0; i < NR_syscalls; i++) { | ||
| 269 | meta = find_syscall_meta((unsigned long)sys_call_table[i]); | ||
| 270 | syscalls_metadata[i] = meta; | ||
| 271 | } | ||
| 272 | return 0; | ||
| 273 | } | 211 | } |
| 274 | arch_initcall(arch_init_ftrace_syscalls); | ||
| 275 | #endif | 212 | #endif |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index c097e7d607c6..7d52e9da5e0c 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
| @@ -1185,17 +1185,14 @@ END(ftrace_graph_caller) | |||
| 1185 | 1185 | ||
| 1186 | .globl return_to_handler | 1186 | .globl return_to_handler |
| 1187 | return_to_handler: | 1187 | return_to_handler: |
| 1188 | pushl $0 | ||
| 1189 | pushl %eax | 1188 | pushl %eax |
| 1190 | pushl %ecx | ||
| 1191 | pushl %edx | 1189 | pushl %edx |
| 1192 | movl %ebp, %eax | 1190 | movl %ebp, %eax |
| 1193 | call ftrace_return_to_handler | 1191 | call ftrace_return_to_handler |
| 1194 | movl %eax, 0xc(%esp) | 1192 | movl %eax, %ecx |
| 1195 | popl %edx | 1193 | popl %edx |
| 1196 | popl %ecx | ||
| 1197 | popl %eax | 1194 | popl %eax |
| 1198 | ret | 1195 | jmp *%ecx |
| 1199 | #endif | 1196 | #endif |
| 1200 | 1197 | ||
| 1201 | .section .rodata,"a" | 1198 | .section .rodata,"a" |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index b5c061f8f358..bd5bbddddf91 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -155,11 +155,11 @@ GLOBAL(return_to_handler) | |||
| 155 | 155 | ||
| 156 | call ftrace_return_to_handler | 156 | call ftrace_return_to_handler |
| 157 | 157 | ||
| 158 | movq %rax, 16(%rsp) | 158 | movq %rax, %rdi |
| 159 | movq 8(%rsp), %rdx | 159 | movq 8(%rsp), %rdx |
| 160 | movq (%rsp), %rax | 160 | movq (%rsp), %rax |
| 161 | addq $16, %rsp | 161 | addq $24, %rsp |
| 162 | retq | 162 | jmp *%rdi |
| 163 | #endif | 163 | #endif |
| 164 | 164 | ||
| 165 | 165 | ||
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 9dbb527e1652..5a1b9758fd62 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | * the dangers of modifying code on the run. | 9 | * the dangers of modifying code on the run. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 13 | |||
| 12 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
| 13 | #include <linux/hardirq.h> | 15 | #include <linux/hardirq.h> |
| 14 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
| @@ -336,15 +338,15 @@ int __init ftrace_dyn_arch_init(void *data) | |||
| 336 | 338 | ||
| 337 | switch (faulted) { | 339 | switch (faulted) { |
| 338 | case 0: | 340 | case 0: |
| 339 | pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n"); | 341 | pr_info("converting mcount calls to 0f 1f 44 00 00\n"); |
| 340 | memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE); | 342 | memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE); |
| 341 | break; | 343 | break; |
| 342 | case 1: | 344 | case 1: |
| 343 | pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n"); | 345 | pr_info("converting mcount calls to 66 66 66 66 90\n"); |
| 344 | memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE); | 346 | memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE); |
| 345 | break; | 347 | break; |
| 346 | case 2: | 348 | case 2: |
| 347 | pr_info("ftrace: converting mcount calls to jmp . + 5\n"); | 349 | pr_info("converting mcount calls to jmp . + 5\n"); |
| 348 | memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE); | 350 | memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE); |
| 349 | break; | 351 | break; |
| 350 | } | 352 | } |
| @@ -468,82 +470,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
| 468 | 470 | ||
| 469 | #ifdef CONFIG_FTRACE_SYSCALLS | 471 | #ifdef CONFIG_FTRACE_SYSCALLS |
| 470 | 472 | ||
| 471 | extern unsigned long __start_syscalls_metadata[]; | ||
| 472 | extern unsigned long __stop_syscalls_metadata[]; | ||
| 473 | extern unsigned long *sys_call_table; | 473 | extern unsigned long *sys_call_table; |
| 474 | 474 | ||
| 475 | static struct syscall_metadata **syscalls_metadata; | 475 | unsigned long __init arch_syscall_addr(int nr) |
| 476 | |||
| 477 | static struct syscall_metadata *find_syscall_meta(unsigned long *syscall) | ||
| 478 | { | ||
| 479 | struct syscall_metadata *start; | ||
| 480 | struct syscall_metadata *stop; | ||
| 481 | char str[KSYM_SYMBOL_LEN]; | ||
| 482 | |||
| 483 | |||
| 484 | start = (struct syscall_metadata *)__start_syscalls_metadata; | ||
| 485 | stop = (struct syscall_metadata *)__stop_syscalls_metadata; | ||
| 486 | kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str); | ||
| 487 | |||
| 488 | for ( ; start < stop; start++) { | ||
| 489 | if (start->name && !strcmp(start->name, str)) | ||
| 490 | return start; | ||
| 491 | } | ||
| 492 | return NULL; | ||
| 493 | } | ||
| 494 | |||
| 495 | struct syscall_metadata *syscall_nr_to_meta(int nr) | ||
| 496 | { | ||
| 497 | if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) | ||
| 498 | return NULL; | ||
| 499 | |||
| 500 | return syscalls_metadata[nr]; | ||
| 501 | } | ||
| 502 | |||
| 503 | int syscall_name_to_nr(char *name) | ||
| 504 | { | 476 | { |
| 505 | int i; | 477 | return (unsigned long)(&sys_call_table)[nr]; |
| 506 | |||
| 507 | if (!syscalls_metadata) | ||
| 508 | return -1; | ||
| 509 | |||
| 510 | for (i = 0; i < NR_syscalls; i++) { | ||
| 511 | if (syscalls_metadata[i]) { | ||
| 512 | if (!strcmp(syscalls_metadata[i]->name, name)) | ||
| 513 | return i; | ||
| 514 | } | ||
| 515 | } | ||
| 516 | return -1; | ||
| 517 | } | ||
| 518 | |||
| 519 | void set_syscall_enter_id(int num, int id) | ||
| 520 | { | ||
| 521 | syscalls_metadata[num]->enter_id = id; | ||
| 522 | } | ||
| 523 | |||
| 524 | void set_syscall_exit_id(int num, int id) | ||
| 525 | { | ||
| 526 | syscalls_metadata[num]->exit_id = id; | ||
| 527 | } | ||
| 528 | |||
| 529 | static int __init arch_init_ftrace_syscalls(void) | ||
| 530 | { | ||
| 531 | int i; | ||
| 532 | struct syscall_metadata *meta; | ||
| 533 | unsigned long **psys_syscall_table = &sys_call_table; | ||
| 534 | |||
| 535 | syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * | ||
| 536 | NR_syscalls, GFP_KERNEL); | ||
| 537 | if (!syscalls_metadata) { | ||
| 538 | WARN_ON(1); | ||
| 539 | return -ENOMEM; | ||
| 540 | } | ||
| 541 | |||
| 542 | for (i = 0; i < NR_syscalls; i++) { | ||
| 543 | meta = find_syscall_meta(psys_syscall_table[i]); | ||
| 544 | syscalls_metadata[i] = meta; | ||
| 545 | } | ||
| 546 | return 0; | ||
| 547 | } | 478 | } |
| 548 | arch_initcall(arch_init_ftrace_syscalls); | ||
| 549 | #endif | 479 | #endif |
diff --git a/arch/x86/mm/testmmiotrace.c b/arch/x86/mm/testmmiotrace.c index 427fd1b56df5..8565d944f7cf 100644 --- a/arch/x86/mm/testmmiotrace.c +++ b/arch/x86/mm/testmmiotrace.c | |||
| @@ -1,12 +1,13 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Written by Pekka Paalanen, 2008-2009 <pq@iki.fi> | 2 | * Written by Pekka Paalanen, 2008-2009 <pq@iki.fi> |
| 3 | */ | 3 | */ |
| 4 | |||
| 5 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 6 | |||
| 4 | #include <linux/module.h> | 7 | #include <linux/module.h> |
| 5 | #include <linux/io.h> | 8 | #include <linux/io.h> |
| 6 | #include <linux/mmiotrace.h> | 9 | #include <linux/mmiotrace.h> |
| 7 | 10 | ||
| 8 | #define MODULE_NAME "testmmiotrace" | ||
| 9 | |||
| 10 | static unsigned long mmio_address; | 11 | static unsigned long mmio_address; |
| 11 | module_param(mmio_address, ulong, 0); | 12 | module_param(mmio_address, ulong, 0); |
| 12 | MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB " | 13 | MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB " |
| @@ -30,7 +31,7 @@ static unsigned v32(unsigned i) | |||
| 30 | static void do_write_test(void __iomem *p) | 31 | static void do_write_test(void __iomem *p) |
| 31 | { | 32 | { |
| 32 | unsigned int i; | 33 | unsigned int i; |
| 33 | pr_info(MODULE_NAME ": write test.\n"); | 34 | pr_info("write test.\n"); |
| 34 | mmiotrace_printk("Write test.\n"); | 35 | mmiotrace_printk("Write test.\n"); |
| 35 | 36 | ||
| 36 | for (i = 0; i < 256; i++) | 37 | for (i = 0; i < 256; i++) |
| @@ -47,7 +48,7 @@ static void do_read_test(void __iomem *p) | |||
| 47 | { | 48 | { |
| 48 | unsigned int i; | 49 | unsigned int i; |
| 49 | unsigned errs[3] = { 0 }; | 50 | unsigned errs[3] = { 0 }; |
| 50 | pr_info(MODULE_NAME ": read test.\n"); | 51 | pr_info("read test.\n"); |
| 51 | mmiotrace_printk("Read test.\n"); | 52 | mmiotrace_printk("Read test.\n"); |
| 52 | 53 | ||
| 53 | for (i = 0; i < 256; i++) | 54 | for (i = 0; i < 256; i++) |
| @@ -68,7 +69,7 @@ static void do_read_test(void __iomem *p) | |||
| 68 | 69 | ||
| 69 | static void do_read_far_test(void __iomem *p) | 70 | static void do_read_far_test(void __iomem *p) |
| 70 | { | 71 | { |
| 71 | pr_info(MODULE_NAME ": read far test.\n"); | 72 | pr_info("read far test.\n"); |
| 72 | mmiotrace_printk("Read far test.\n"); | 73 | mmiotrace_printk("Read far test.\n"); |
| 73 | 74 | ||
| 74 | ioread32(p + read_far); | 75 | ioread32(p + read_far); |
| @@ -78,7 +79,7 @@ static void do_test(unsigned long size) | |||
| 78 | { | 79 | { |
| 79 | void __iomem *p = ioremap_nocache(mmio_address, size); | 80 | void __iomem *p = ioremap_nocache(mmio_address, size); |
| 80 | if (!p) { | 81 | if (!p) { |
| 81 | pr_err(MODULE_NAME ": could not ioremap, aborting.\n"); | 82 | pr_err("could not ioremap, aborting.\n"); |
| 82 | return; | 83 | return; |
| 83 | } | 84 | } |
| 84 | mmiotrace_printk("ioremap returned %p.\n", p); | 85 | mmiotrace_printk("ioremap returned %p.\n", p); |
| @@ -94,24 +95,22 @@ static int __init init(void) | |||
| 94 | unsigned long size = (read_far) ? (8 << 20) : (16 << 10); | 95 | unsigned long size = (read_far) ? (8 << 20) : (16 << 10); |
| 95 | 96 | ||
| 96 | if (mmio_address == 0) { | 97 | if (mmio_address == 0) { |
| 97 | pr_err(MODULE_NAME ": you have to use the module argument " | 98 | pr_err("you have to use the module argument mmio_address.\n"); |
| 98 | "mmio_address.\n"); | 99 | pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n"); |
| 99 | pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS" | ||
| 100 | " YOU REALLY KNOW WHAT YOU ARE DOING!\n"); | ||
| 101 | return -ENXIO; | 100 | return -ENXIO; |
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI " | 103 | pr_warning("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, " |
| 105 | "address space, and writing 16 kB of rubbish in there.\n", | 104 | "and writing 16 kB of rubbish in there.\n", |
| 106 | size >> 10, mmio_address); | 105 | size >> 10, mmio_address); |
| 107 | do_test(size); | 106 | do_test(size); |
| 108 | pr_info(MODULE_NAME ": All done.\n"); | 107 | pr_info("All done.\n"); |
| 109 | return 0; | 108 | return 0; |
| 110 | } | 109 | } |
| 111 | 110 | ||
| 112 | static void __exit cleanup(void) | 111 | static void __exit cleanup(void) |
| 113 | { | 112 | { |
| 114 | pr_debug(MODULE_NAME ": unloaded.\n"); | 113 | pr_debug("unloaded.\n"); |
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | module_init(init); | 116 | module_init(init); |
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index a3ed7cb8ca34..73dcf804bc94 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h | |||
| @@ -79,6 +79,7 @@ | |||
| 79 | #define noinline __attribute__((noinline)) | 79 | #define noinline __attribute__((noinline)) |
| 80 | #define __attribute_const__ __attribute__((__const__)) | 80 | #define __attribute_const__ __attribute__((__const__)) |
| 81 | #define __maybe_unused __attribute__((unused)) | 81 | #define __maybe_unused __attribute__((unused)) |
| 82 | #define __always_unused __attribute__((unused)) | ||
| 82 | 83 | ||
| 83 | #define __gcc_header(x) #x | 84 | #define __gcc_header(x) #x |
| 84 | #define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h) | 85 | #define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h) |
diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 59f208926d13..acbd654cc850 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h | |||
| @@ -218,6 +218,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); | |||
| 218 | # define __maybe_unused /* unimplemented */ | 218 | # define __maybe_unused /* unimplemented */ |
| 219 | #endif | 219 | #endif |
| 220 | 220 | ||
| 221 | #ifndef __always_unused | ||
| 222 | # define __always_unused /* unimplemented */ | ||
| 223 | #endif | ||
| 224 | |||
| 221 | #ifndef noinline | 225 | #ifndef noinline |
| 222 | #define noinline | 226 | #define noinline |
| 223 | #endif | 227 | #endif |
diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h index 813be59bf345..2ea1dd1ba21c 100644 --- a/include/linux/smp_lock.h +++ b/include/linux/smp_lock.h | |||
| @@ -24,8 +24,21 @@ static inline int reacquire_kernel_lock(struct task_struct *task) | |||
| 24 | return 0; | 24 | return 0; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | extern void __lockfunc lock_kernel(void) __acquires(kernel_lock); | 27 | extern void __lockfunc |
| 28 | extern void __lockfunc unlock_kernel(void) __releases(kernel_lock); | 28 | _lock_kernel(const char *func, const char *file, int line) |
| 29 | __acquires(kernel_lock); | ||
| 30 | |||
| 31 | extern void __lockfunc | ||
| 32 | _unlock_kernel(const char *func, const char *file, int line) | ||
| 33 | __releases(kernel_lock); | ||
| 34 | |||
| 35 | #define lock_kernel() do { \ | ||
| 36 | _lock_kernel(__func__, __FILE__, __LINE__); \ | ||
| 37 | } while (0) | ||
| 38 | |||
| 39 | #define unlock_kernel() do { \ | ||
| 40 | _unlock_kernel(__func__, __FILE__, __LINE__); \ | ||
| 41 | } while (0) | ||
| 29 | 42 | ||
| 30 | /* | 43 | /* |
| 31 | * Various legacy drivers don't really need the BKL in a specific | 44 | * Various legacy drivers don't really need the BKL in a specific |
| @@ -41,8 +54,8 @@ static inline void cycle_kernel_lock(void) | |||
| 41 | 54 | ||
| 42 | #else | 55 | #else |
| 43 | 56 | ||
| 44 | #define lock_kernel() do { } while(0) | 57 | #define lock_kernel() |
| 45 | #define unlock_kernel() do { } while(0) | 58 | #define unlock_kernel() |
| 46 | #define release_kernel_lock(task) do { } while(0) | 59 | #define release_kernel_lock(task) do { } while(0) |
| 47 | #define cycle_kernel_lock() do { } while(0) | 60 | #define cycle_kernel_lock() do { } while(0) |
| 48 | #define reacquire_kernel_lock(task) 0 | 61 | #define reacquire_kernel_lock(task) 0 |
diff --git a/include/trace/events/bkl.h b/include/trace/events/bkl.h new file mode 100644 index 000000000000..8abd620a490e --- /dev/null +++ b/include/trace/events/bkl.h | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM bkl | ||
| 3 | |||
| 4 | #if !defined(_TRACE_BKL_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define _TRACE_BKL_H | ||
| 6 | |||
| 7 | #include <linux/tracepoint.h> | ||
| 8 | |||
| 9 | TRACE_EVENT(lock_kernel, | ||
| 10 | |||
| 11 | TP_PROTO(const char *func, const char *file, int line), | ||
| 12 | |||
| 13 | TP_ARGS(func, file, line), | ||
| 14 | |||
| 15 | TP_STRUCT__entry( | ||
| 16 | __field( int, lock_depth ) | ||
| 17 | __field_ext( const char *, func, FILTER_PTR_STRING ) | ||
| 18 | __field_ext( const char *, file, FILTER_PTR_STRING ) | ||
| 19 | __field( int, line ) | ||
| 20 | ), | ||
| 21 | |||
| 22 | TP_fast_assign( | ||
| 23 | /* We want to record the lock_depth after lock is acquired */ | ||
| 24 | __entry->lock_depth = current->lock_depth + 1; | ||
| 25 | __entry->func = func; | ||
| 26 | __entry->file = file; | ||
| 27 | __entry->line = line; | ||
| 28 | ), | ||
| 29 | |||
| 30 | TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth, | ||
| 31 | __entry->file, __entry->line, __entry->func) | ||
| 32 | ); | ||
| 33 | |||
| 34 | TRACE_EVENT(unlock_kernel, | ||
| 35 | |||
| 36 | TP_PROTO(const char *func, const char *file, int line), | ||
| 37 | |||
| 38 | TP_ARGS(func, file, line), | ||
| 39 | |||
| 40 | TP_STRUCT__entry( | ||
| 41 | __field(int, lock_depth) | ||
| 42 | __field(const char *, func) | ||
| 43 | __field(const char *, file) | ||
| 44 | __field(int, line) | ||
| 45 | ), | ||
| 46 | |||
| 47 | TP_fast_assign( | ||
| 48 | __entry->lock_depth = current->lock_depth; | ||
| 49 | __entry->func = func; | ||
| 50 | __entry->file = file; | ||
| 51 | __entry->line = line; | ||
| 52 | ), | ||
| 53 | |||
| 54 | TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth, | ||
| 55 | __entry->file, __entry->line, __entry->func) | ||
| 56 | ); | ||
| 57 | |||
| 58 | #endif /* _TRACE_BKL_H */ | ||
| 59 | |||
| 60 | /* This part must be outside protection */ | ||
| 61 | #include <trace/define_trace.h> | ||
diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h index 397dff2dbd5a..fb726ac7caee 100644 --- a/include/trace/events/syscalls.h +++ b/include/trace/events/syscalls.h | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #undef TRACE_SYSTEM | 1 | #undef TRACE_SYSTEM |
| 2 | #define TRACE_SYSTEM syscalls | 2 | #define TRACE_SYSTEM raw_syscalls |
| 3 | #define TRACE_INCLUDE_FILE syscalls | ||
| 3 | 4 | ||
| 4 | #if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ) | 5 | #if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ) |
| 5 | #define _TRACE_EVENTS_SYSCALLS_H | 6 | #define _TRACE_EVENTS_SYSCALLS_H |
diff --git a/include/trace/power.h b/include/trace/power.h deleted file mode 100644 index ef204666e983..000000000000 --- a/include/trace/power.h +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | #ifndef _TRACE_POWER_H | ||
| 2 | #define _TRACE_POWER_H | ||
| 3 | |||
| 4 | #include <linux/ktime.h> | ||
| 5 | #include <linux/tracepoint.h> | ||
| 6 | |||
| 7 | enum { | ||
| 8 | POWER_NONE = 0, | ||
| 9 | POWER_CSTATE = 1, | ||
| 10 | POWER_PSTATE = 2, | ||
| 11 | }; | ||
| 12 | |||
| 13 | struct power_trace { | ||
| 14 | ktime_t stamp; | ||
| 15 | ktime_t end; | ||
| 16 | int type; | ||
| 17 | int state; | ||
| 18 | }; | ||
| 19 | |||
| 20 | DECLARE_TRACE(power_start, | ||
| 21 | TP_PROTO(struct power_trace *it, unsigned int type, unsigned int state), | ||
| 22 | TP_ARGS(it, type, state)); | ||
| 23 | |||
| 24 | DECLARE_TRACE(power_mark, | ||
| 25 | TP_PROTO(struct power_trace *it, unsigned int type, unsigned int state), | ||
| 26 | TP_ARGS(it, type, state)); | ||
| 27 | |||
| 28 | DECLARE_TRACE(power_end, | ||
| 29 | TP_PROTO(struct power_trace *it), | ||
| 30 | TP_ARGS(it)); | ||
| 31 | |||
| 32 | #endif /* _TRACE_POWER_H */ | ||
diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 5dc283ba5ae0..e972f0a40f8d 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h | |||
| @@ -33,7 +33,7 @@ struct syscall_metadata { | |||
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | #ifdef CONFIG_FTRACE_SYSCALLS | 35 | #ifdef CONFIG_FTRACE_SYSCALLS |
| 36 | extern struct syscall_metadata *syscall_nr_to_meta(int nr); | 36 | extern unsigned long arch_syscall_addr(int nr); |
| 37 | extern int syscall_name_to_nr(char *name); | 37 | extern int syscall_name_to_nr(char *name); |
| 38 | void set_syscall_enter_id(int num, int id); | 38 | void set_syscall_enter_id(int num, int id); |
| 39 | void set_syscall_exit_id(int num, int id); | 39 | void set_syscall_exit_id(int num, int id); |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 5240d75f4c60..1494e85b35f2 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -1014,9 +1014,9 @@ int __kprobes register_kretprobe(struct kretprobe *rp) | |||
| 1014 | /* Pre-allocate memory for max kretprobe instances */ | 1014 | /* Pre-allocate memory for max kretprobe instances */ |
| 1015 | if (rp->maxactive <= 0) { | 1015 | if (rp->maxactive <= 0) { |
| 1016 | #ifdef CONFIG_PREEMPT | 1016 | #ifdef CONFIG_PREEMPT |
| 1017 | rp->maxactive = max(10, 2 * NR_CPUS); | 1017 | rp->maxactive = max(10, 2 * num_possible_cpus()); |
| 1018 | #else | 1018 | #else |
| 1019 | rp->maxactive = NR_CPUS; | 1019 | rp->maxactive = num_possible_cpus(); |
| 1020 | #endif | 1020 | #endif |
| 1021 | } | 1021 | } |
| 1022 | spin_lock_init(&rp->lock); | 1022 | spin_lock_init(&rp->lock); |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6dc4e5ef7a01..e51a1bcb7bed 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -60,6 +60,13 @@ static int last_ftrace_enabled; | |||
| 60 | /* Quick disabling of function tracer. */ | 60 | /* Quick disabling of function tracer. */ |
| 61 | int function_trace_stop; | 61 | int function_trace_stop; |
| 62 | 62 | ||
| 63 | /* List for set_ftrace_pid's pids. */ | ||
| 64 | LIST_HEAD(ftrace_pids); | ||
| 65 | struct ftrace_pid { | ||
| 66 | struct list_head list; | ||
| 67 | struct pid *pid; | ||
| 68 | }; | ||
| 69 | |||
| 63 | /* | 70 | /* |
| 64 | * ftrace_disabled is set when an anomaly is discovered. | 71 | * ftrace_disabled is set when an anomaly is discovered. |
| 65 | * ftrace_disabled is much stronger than ftrace_enabled. | 72 | * ftrace_disabled is much stronger than ftrace_enabled. |
| @@ -78,6 +85,10 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | |||
| 78 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; | 85 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; |
| 79 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; | 86 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; |
| 80 | 87 | ||
| 88 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 89 | static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); | ||
| 90 | #endif | ||
| 91 | |||
| 81 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) | 92 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) |
| 82 | { | 93 | { |
| 83 | struct ftrace_ops *op = ftrace_list; | 94 | struct ftrace_ops *op = ftrace_list; |
| @@ -155,7 +166,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
| 155 | else | 166 | else |
| 156 | func = ftrace_list_func; | 167 | func = ftrace_list_func; |
| 157 | 168 | ||
| 158 | if (ftrace_pid_trace) { | 169 | if (!list_empty(&ftrace_pids)) { |
| 159 | set_ftrace_pid_function(func); | 170 | set_ftrace_pid_function(func); |
| 160 | func = ftrace_pid_func; | 171 | func = ftrace_pid_func; |
| 161 | } | 172 | } |
| @@ -203,7 +214,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
| 203 | if (ftrace_list->next == &ftrace_list_end) { | 214 | if (ftrace_list->next == &ftrace_list_end) { |
| 204 | ftrace_func_t func = ftrace_list->func; | 215 | ftrace_func_t func = ftrace_list->func; |
| 205 | 216 | ||
| 206 | if (ftrace_pid_trace) { | 217 | if (!list_empty(&ftrace_pids)) { |
| 207 | set_ftrace_pid_function(func); | 218 | set_ftrace_pid_function(func); |
| 208 | func = ftrace_pid_func; | 219 | func = ftrace_pid_func; |
| 209 | } | 220 | } |
| @@ -231,7 +242,7 @@ static void ftrace_update_pid_func(void) | |||
| 231 | func = __ftrace_trace_function; | 242 | func = __ftrace_trace_function; |
| 232 | #endif | 243 | #endif |
| 233 | 244 | ||
| 234 | if (ftrace_pid_trace) { | 245 | if (!list_empty(&ftrace_pids)) { |
| 235 | set_ftrace_pid_function(func); | 246 | set_ftrace_pid_function(func); |
| 236 | func = ftrace_pid_func; | 247 | func = ftrace_pid_func; |
| 237 | } else { | 248 | } else { |
| @@ -821,8 +832,6 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer) | |||
| 821 | } | 832 | } |
| 822 | #endif /* CONFIG_FUNCTION_PROFILER */ | 833 | #endif /* CONFIG_FUNCTION_PROFILER */ |
| 823 | 834 | ||
| 824 | /* set when tracing only a pid */ | ||
| 825 | struct pid *ftrace_pid_trace; | ||
| 826 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; | 835 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; |
| 827 | 836 | ||
| 828 | #ifdef CONFIG_DYNAMIC_FTRACE | 837 | #ifdef CONFIG_DYNAMIC_FTRACE |
| @@ -1261,12 +1270,34 @@ static int ftrace_update_code(struct module *mod) | |||
| 1261 | ftrace_new_addrs = p->newlist; | 1270 | ftrace_new_addrs = p->newlist; |
| 1262 | p->flags = 0L; | 1271 | p->flags = 0L; |
| 1263 | 1272 | ||
| 1264 | /* convert record (i.e, patch mcount-call with NOP) */ | 1273 | /* |
| 1265 | if (ftrace_code_disable(mod, p)) { | 1274 | * Do the initial record convertion from mcount jump |
| 1266 | p->flags |= FTRACE_FL_CONVERTED; | 1275 | * to the NOP instructions. |
| 1267 | ftrace_update_cnt++; | 1276 | */ |
| 1268 | } else | 1277 | if (!ftrace_code_disable(mod, p)) { |
| 1269 | ftrace_free_rec(p); | 1278 | ftrace_free_rec(p); |
| 1279 | continue; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | p->flags |= FTRACE_FL_CONVERTED; | ||
| 1283 | ftrace_update_cnt++; | ||
| 1284 | |||
| 1285 | /* | ||
| 1286 | * If the tracing is enabled, go ahead and enable the record. | ||
| 1287 | * | ||
| 1288 | * The reason not to enable the record immediatelly is the | ||
| 1289 | * inherent check of ftrace_make_nop/ftrace_make_call for | ||
| 1290 | * correct previous instructions. Making first the NOP | ||
| 1291 | * conversion puts the module to the correct state, thus | ||
| 1292 | * passing the ftrace_make_call check. | ||
| 1293 | */ | ||
| 1294 | if (ftrace_start_up) { | ||
| 1295 | int failed = __ftrace_replace_code(p, 1); | ||
| 1296 | if (failed) { | ||
| 1297 | ftrace_bug(failed, p->ip); | ||
| 1298 | ftrace_free_rec(p); | ||
| 1299 | } | ||
| 1300 | } | ||
| 1270 | } | 1301 | } |
| 1271 | 1302 | ||
| 1272 | stop = ftrace_now(raw_smp_processor_id()); | 1303 | stop = ftrace_now(raw_smp_processor_id()); |
| @@ -1656,60 +1687,6 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin) | |||
| 1656 | return ret; | 1687 | return ret; |
| 1657 | } | 1688 | } |
| 1658 | 1689 | ||
| 1659 | enum { | ||
| 1660 | MATCH_FULL, | ||
| 1661 | MATCH_FRONT_ONLY, | ||
| 1662 | MATCH_MIDDLE_ONLY, | ||
| 1663 | MATCH_END_ONLY, | ||
| 1664 | }; | ||
| 1665 | |||
| 1666 | /* | ||
| 1667 | * (static function - no need for kernel doc) | ||
| 1668 | * | ||
| 1669 | * Pass in a buffer containing a glob and this function will | ||
| 1670 | * set search to point to the search part of the buffer and | ||
| 1671 | * return the type of search it is (see enum above). | ||
| 1672 | * This does modify buff. | ||
| 1673 | * | ||
| 1674 | * Returns enum type. | ||
| 1675 | * search returns the pointer to use for comparison. | ||
| 1676 | * not returns 1 if buff started with a '!' | ||
| 1677 | * 0 otherwise. | ||
| 1678 | */ | ||
| 1679 | static int | ||
| 1680 | ftrace_setup_glob(char *buff, int len, char **search, int *not) | ||
| 1681 | { | ||
| 1682 | int type = MATCH_FULL; | ||
| 1683 | int i; | ||
| 1684 | |||
| 1685 | if (buff[0] == '!') { | ||
| 1686 | *not = 1; | ||
| 1687 | buff++; | ||
| 1688 | len--; | ||
| 1689 | } else | ||
| 1690 | *not = 0; | ||
| 1691 | |||
| 1692 | *search = buff; | ||
| 1693 | |||
| 1694 | for (i = 0; i < len; i++) { | ||
| 1695 | if (buff[i] == '*') { | ||
| 1696 | if (!i) { | ||
| 1697 | *search = buff + 1; | ||
| 1698 | type = MATCH_END_ONLY; | ||
| 1699 | } else { | ||
| 1700 | if (type == MATCH_END_ONLY) | ||
| 1701 | type = MATCH_MIDDLE_ONLY; | ||
| 1702 | else | ||
| 1703 | type = MATCH_FRONT_ONLY; | ||
| 1704 | buff[i] = 0; | ||
| 1705 | break; | ||
| 1706 | } | ||
| 1707 | } | ||
| 1708 | } | ||
| 1709 | |||
| 1710 | return type; | ||
| 1711 | } | ||
| 1712 | |||
| 1713 | static int ftrace_match(char *str, char *regex, int len, int type) | 1690 | static int ftrace_match(char *str, char *regex, int len, int type) |
| 1714 | { | 1691 | { |
| 1715 | int matched = 0; | 1692 | int matched = 0; |
| @@ -1758,7 +1735,7 @@ static void ftrace_match_records(char *buff, int len, int enable) | |||
| 1758 | int not; | 1735 | int not; |
| 1759 | 1736 | ||
| 1760 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | 1737 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; |
| 1761 | type = ftrace_setup_glob(buff, len, &search, ¬); | 1738 | type = filter_parse_regex(buff, len, &search, ¬); |
| 1762 | 1739 | ||
| 1763 | search_len = strlen(search); | 1740 | search_len = strlen(search); |
| 1764 | 1741 | ||
| @@ -1826,7 +1803,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) | |||
| 1826 | } | 1803 | } |
| 1827 | 1804 | ||
| 1828 | if (strlen(buff)) { | 1805 | if (strlen(buff)) { |
| 1829 | type = ftrace_setup_glob(buff, strlen(buff), &search, ¬); | 1806 | type = filter_parse_regex(buff, strlen(buff), &search, ¬); |
| 1830 | search_len = strlen(search); | 1807 | search_len = strlen(search); |
| 1831 | } | 1808 | } |
| 1832 | 1809 | ||
| @@ -1991,7 +1968,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
| 1991 | int count = 0; | 1968 | int count = 0; |
| 1992 | char *search; | 1969 | char *search; |
| 1993 | 1970 | ||
| 1994 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 1971 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
| 1995 | len = strlen(search); | 1972 | len = strlen(search); |
| 1996 | 1973 | ||
| 1997 | /* we do not support '!' for function probes */ | 1974 | /* we do not support '!' for function probes */ |
| @@ -2068,7 +2045,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
| 2068 | else if (glob) { | 2045 | else if (glob) { |
| 2069 | int not; | 2046 | int not; |
| 2070 | 2047 | ||
| 2071 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 2048 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
| 2072 | len = strlen(search); | 2049 | len = strlen(search); |
| 2073 | 2050 | ||
| 2074 | /* we do not support '!' for function probes */ | 2051 | /* we do not support '!' for function probes */ |
| @@ -2312,6 +2289,32 @@ static int __init set_ftrace_filter(char *str) | |||
| 2312 | } | 2289 | } |
| 2313 | __setup("ftrace_filter=", set_ftrace_filter); | 2290 | __setup("ftrace_filter=", set_ftrace_filter); |
| 2314 | 2291 | ||
| 2292 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 2293 | static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; | ||
| 2294 | static int __init set_graph_function(char *str) | ||
| 2295 | { | ||
| 2296 | strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); | ||
| 2297 | return 1; | ||
| 2298 | } | ||
| 2299 | __setup("ftrace_graph_filter=", set_graph_function); | ||
| 2300 | |||
| 2301 | static void __init set_ftrace_early_graph(char *buf) | ||
| 2302 | { | ||
| 2303 | int ret; | ||
| 2304 | char *func; | ||
| 2305 | |||
| 2306 | while (buf) { | ||
| 2307 | func = strsep(&buf, ","); | ||
| 2308 | /* we allow only one expression at a time */ | ||
| 2309 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, | ||
| 2310 | func); | ||
| 2311 | if (ret) | ||
| 2312 | printk(KERN_DEBUG "ftrace: function %s not " | ||
| 2313 | "traceable\n", func); | ||
| 2314 | } | ||
| 2315 | } | ||
| 2316 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
| 2317 | |||
| 2315 | static void __init set_ftrace_early_filter(char *buf, int enable) | 2318 | static void __init set_ftrace_early_filter(char *buf, int enable) |
| 2316 | { | 2319 | { |
| 2317 | char *func; | 2320 | char *func; |
| @@ -2328,6 +2331,10 @@ static void __init set_ftrace_early_filters(void) | |||
| 2328 | set_ftrace_early_filter(ftrace_filter_buf, 1); | 2331 | set_ftrace_early_filter(ftrace_filter_buf, 1); |
| 2329 | if (ftrace_notrace_buf[0]) | 2332 | if (ftrace_notrace_buf[0]) |
| 2330 | set_ftrace_early_filter(ftrace_notrace_buf, 0); | 2333 | set_ftrace_early_filter(ftrace_notrace_buf, 0); |
| 2334 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 2335 | if (ftrace_graph_buf[0]) | ||
| 2336 | set_ftrace_early_graph(ftrace_graph_buf); | ||
| 2337 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
| 2331 | } | 2338 | } |
| 2332 | 2339 | ||
| 2333 | static int | 2340 | static int |
| @@ -2513,7 +2520,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
| 2513 | return -ENODEV; | 2520 | return -ENODEV; |
| 2514 | 2521 | ||
| 2515 | /* decode regex */ | 2522 | /* decode regex */ |
| 2516 | type = ftrace_setup_glob(buffer, strlen(buffer), &search, ¬); | 2523 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
| 2517 | if (not) | 2524 | if (not) |
| 2518 | return -EINVAL; | 2525 | return -EINVAL; |
| 2519 | 2526 | ||
| @@ -2624,7 +2631,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) | |||
| 2624 | return 0; | 2631 | return 0; |
| 2625 | } | 2632 | } |
| 2626 | 2633 | ||
| 2627 | static int ftrace_convert_nops(struct module *mod, | 2634 | static int ftrace_process_locs(struct module *mod, |
| 2628 | unsigned long *start, | 2635 | unsigned long *start, |
| 2629 | unsigned long *end) | 2636 | unsigned long *end) |
| 2630 | { | 2637 | { |
| @@ -2684,7 +2691,7 @@ static void ftrace_init_module(struct module *mod, | |||
| 2684 | { | 2691 | { |
| 2685 | if (ftrace_disabled || start == end) | 2692 | if (ftrace_disabled || start == end) |
| 2686 | return; | 2693 | return; |
| 2687 | ftrace_convert_nops(mod, start, end); | 2694 | ftrace_process_locs(mod, start, end); |
| 2688 | } | 2695 | } |
| 2689 | 2696 | ||
| 2690 | static int ftrace_module_notify(struct notifier_block *self, | 2697 | static int ftrace_module_notify(struct notifier_block *self, |
| @@ -2745,7 +2752,7 @@ void __init ftrace_init(void) | |||
| 2745 | 2752 | ||
| 2746 | last_ftrace_enabled = ftrace_enabled = 1; | 2753 | last_ftrace_enabled = ftrace_enabled = 1; |
| 2747 | 2754 | ||
| 2748 | ret = ftrace_convert_nops(NULL, | 2755 | ret = ftrace_process_locs(NULL, |
| 2749 | __start_mcount_loc, | 2756 | __start_mcount_loc, |
| 2750 | __stop_mcount_loc); | 2757 | __stop_mcount_loc); |
| 2751 | 2758 | ||
| @@ -2778,23 +2785,6 @@ static inline void ftrace_startup_enable(int command) { } | |||
| 2778 | # define ftrace_shutdown_sysctl() do { } while (0) | 2785 | # define ftrace_shutdown_sysctl() do { } while (0) |
| 2779 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 2786 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
| 2780 | 2787 | ||
| 2781 | static ssize_t | ||
| 2782 | ftrace_pid_read(struct file *file, char __user *ubuf, | ||
| 2783 | size_t cnt, loff_t *ppos) | ||
| 2784 | { | ||
| 2785 | char buf[64]; | ||
| 2786 | int r; | ||
| 2787 | |||
| 2788 | if (ftrace_pid_trace == ftrace_swapper_pid) | ||
| 2789 | r = sprintf(buf, "swapper tasks\n"); | ||
| 2790 | else if (ftrace_pid_trace) | ||
| 2791 | r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace)); | ||
| 2792 | else | ||
| 2793 | r = sprintf(buf, "no pid\n"); | ||
| 2794 | |||
| 2795 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
| 2796 | } | ||
| 2797 | |||
| 2798 | static void clear_ftrace_swapper(void) | 2788 | static void clear_ftrace_swapper(void) |
| 2799 | { | 2789 | { |
| 2800 | struct task_struct *p; | 2790 | struct task_struct *p; |
| @@ -2845,14 +2835,12 @@ static void set_ftrace_pid(struct pid *pid) | |||
| 2845 | rcu_read_unlock(); | 2835 | rcu_read_unlock(); |
| 2846 | } | 2836 | } |
| 2847 | 2837 | ||
| 2848 | static void clear_ftrace_pid_task(struct pid **pid) | 2838 | static void clear_ftrace_pid_task(struct pid *pid) |
| 2849 | { | 2839 | { |
| 2850 | if (*pid == ftrace_swapper_pid) | 2840 | if (pid == ftrace_swapper_pid) |
| 2851 | clear_ftrace_swapper(); | 2841 | clear_ftrace_swapper(); |
| 2852 | else | 2842 | else |
| 2853 | clear_ftrace_pid(*pid); | 2843 | clear_ftrace_pid(pid); |
| 2854 | |||
| 2855 | *pid = NULL; | ||
| 2856 | } | 2844 | } |
| 2857 | 2845 | ||
| 2858 | static void set_ftrace_pid_task(struct pid *pid) | 2846 | static void set_ftrace_pid_task(struct pid *pid) |
| @@ -2863,74 +2851,184 @@ static void set_ftrace_pid_task(struct pid *pid) | |||
| 2863 | set_ftrace_pid(pid); | 2851 | set_ftrace_pid(pid); |
| 2864 | } | 2852 | } |
| 2865 | 2853 | ||
| 2866 | static ssize_t | 2854 | static int ftrace_pid_add(int p) |
| 2867 | ftrace_pid_write(struct file *filp, const char __user *ubuf, | ||
| 2868 | size_t cnt, loff_t *ppos) | ||
| 2869 | { | 2855 | { |
| 2870 | struct pid *pid; | 2856 | struct pid *pid; |
| 2871 | char buf[64]; | 2857 | struct ftrace_pid *fpid; |
| 2872 | long val; | 2858 | int ret = -EINVAL; |
| 2873 | int ret; | ||
| 2874 | 2859 | ||
| 2875 | if (cnt >= sizeof(buf)) | 2860 | mutex_lock(&ftrace_lock); |
| 2876 | return -EINVAL; | ||
| 2877 | 2861 | ||
| 2878 | if (copy_from_user(&buf, ubuf, cnt)) | 2862 | if (!p) |
| 2879 | return -EFAULT; | 2863 | pid = ftrace_swapper_pid; |
| 2864 | else | ||
| 2865 | pid = find_get_pid(p); | ||
| 2880 | 2866 | ||
| 2881 | buf[cnt] = 0; | 2867 | if (!pid) |
| 2868 | goto out; | ||
| 2882 | 2869 | ||
| 2883 | ret = strict_strtol(buf, 10, &val); | 2870 | ret = 0; |
| 2884 | if (ret < 0) | ||
| 2885 | return ret; | ||
| 2886 | 2871 | ||
| 2887 | mutex_lock(&ftrace_lock); | 2872 | list_for_each_entry(fpid, &ftrace_pids, list) |
| 2888 | if (val < 0) { | 2873 | if (fpid->pid == pid) |
| 2889 | /* disable pid tracing */ | 2874 | goto out_put; |
| 2890 | if (!ftrace_pid_trace) | ||
| 2891 | goto out; | ||
| 2892 | 2875 | ||
| 2893 | clear_ftrace_pid_task(&ftrace_pid_trace); | 2876 | ret = -ENOMEM; |
| 2894 | 2877 | ||
| 2895 | } else { | 2878 | fpid = kmalloc(sizeof(*fpid), GFP_KERNEL); |
| 2896 | /* swapper task is special */ | 2879 | if (!fpid) |
| 2897 | if (!val) { | 2880 | goto out_put; |
| 2898 | pid = ftrace_swapper_pid; | ||
| 2899 | if (pid == ftrace_pid_trace) | ||
| 2900 | goto out; | ||
| 2901 | } else { | ||
| 2902 | pid = find_get_pid(val); | ||
| 2903 | 2881 | ||
| 2904 | if (pid == ftrace_pid_trace) { | 2882 | list_add(&fpid->list, &ftrace_pids); |
| 2905 | put_pid(pid); | 2883 | fpid->pid = pid; |
| 2906 | goto out; | ||
| 2907 | } | ||
| 2908 | } | ||
| 2909 | 2884 | ||
| 2910 | if (ftrace_pid_trace) | 2885 | set_ftrace_pid_task(pid); |
| 2911 | clear_ftrace_pid_task(&ftrace_pid_trace); | ||
| 2912 | 2886 | ||
| 2913 | if (!pid) | 2887 | ftrace_update_pid_func(); |
| 2914 | goto out; | 2888 | ftrace_startup_enable(0); |
| 2889 | |||
| 2890 | mutex_unlock(&ftrace_lock); | ||
| 2891 | return 0; | ||
| 2892 | |||
| 2893 | out_put: | ||
| 2894 | if (pid != ftrace_swapper_pid) | ||
| 2895 | put_pid(pid); | ||
| 2915 | 2896 | ||
| 2916 | ftrace_pid_trace = pid; | 2897 | out: |
| 2898 | mutex_unlock(&ftrace_lock); | ||
| 2899 | return ret; | ||
| 2900 | } | ||
| 2901 | |||
| 2902 | static void ftrace_pid_reset(void) | ||
| 2903 | { | ||
| 2904 | struct ftrace_pid *fpid, *safe; | ||
| 2917 | 2905 | ||
| 2918 | set_ftrace_pid_task(ftrace_pid_trace); | 2906 | mutex_lock(&ftrace_lock); |
| 2907 | list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) { | ||
| 2908 | struct pid *pid = fpid->pid; | ||
| 2909 | |||
| 2910 | clear_ftrace_pid_task(pid); | ||
| 2911 | |||
| 2912 | list_del(&fpid->list); | ||
| 2913 | kfree(fpid); | ||
| 2919 | } | 2914 | } |
| 2920 | 2915 | ||
| 2921 | /* update the function call */ | ||
| 2922 | ftrace_update_pid_func(); | 2916 | ftrace_update_pid_func(); |
| 2923 | ftrace_startup_enable(0); | 2917 | ftrace_startup_enable(0); |
| 2924 | 2918 | ||
| 2925 | out: | ||
| 2926 | mutex_unlock(&ftrace_lock); | 2919 | mutex_unlock(&ftrace_lock); |
| 2920 | } | ||
| 2927 | 2921 | ||
| 2928 | return cnt; | 2922 | static void *fpid_start(struct seq_file *m, loff_t *pos) |
| 2923 | { | ||
| 2924 | mutex_lock(&ftrace_lock); | ||
| 2925 | |||
| 2926 | if (list_empty(&ftrace_pids) && (!*pos)) | ||
| 2927 | return (void *) 1; | ||
| 2928 | |||
| 2929 | return seq_list_start(&ftrace_pids, *pos); | ||
| 2930 | } | ||
| 2931 | |||
| 2932 | static void *fpid_next(struct seq_file *m, void *v, loff_t *pos) | ||
| 2933 | { | ||
| 2934 | if (v == (void *)1) | ||
| 2935 | return NULL; | ||
| 2936 | |||
| 2937 | return seq_list_next(v, &ftrace_pids, pos); | ||
| 2938 | } | ||
| 2939 | |||
| 2940 | static void fpid_stop(struct seq_file *m, void *p) | ||
| 2941 | { | ||
| 2942 | mutex_unlock(&ftrace_lock); | ||
| 2943 | } | ||
| 2944 | |||
| 2945 | static int fpid_show(struct seq_file *m, void *v) | ||
| 2946 | { | ||
| 2947 | const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list); | ||
| 2948 | |||
| 2949 | if (v == (void *)1) { | ||
| 2950 | seq_printf(m, "no pid\n"); | ||
| 2951 | return 0; | ||
| 2952 | } | ||
| 2953 | |||
| 2954 | if (fpid->pid == ftrace_swapper_pid) | ||
| 2955 | seq_printf(m, "swapper tasks\n"); | ||
| 2956 | else | ||
| 2957 | seq_printf(m, "%u\n", pid_vnr(fpid->pid)); | ||
| 2958 | |||
| 2959 | return 0; | ||
| 2960 | } | ||
| 2961 | |||
| 2962 | static const struct seq_operations ftrace_pid_sops = { | ||
| 2963 | .start = fpid_start, | ||
| 2964 | .next = fpid_next, | ||
| 2965 | .stop = fpid_stop, | ||
| 2966 | .show = fpid_show, | ||
| 2967 | }; | ||
| 2968 | |||
| 2969 | static int | ||
| 2970 | ftrace_pid_open(struct inode *inode, struct file *file) | ||
| 2971 | { | ||
| 2972 | int ret = 0; | ||
| 2973 | |||
| 2974 | if ((file->f_mode & FMODE_WRITE) && | ||
| 2975 | (file->f_flags & O_TRUNC)) | ||
| 2976 | ftrace_pid_reset(); | ||
| 2977 | |||
| 2978 | if (file->f_mode & FMODE_READ) | ||
| 2979 | ret = seq_open(file, &ftrace_pid_sops); | ||
| 2980 | |||
| 2981 | return ret; | ||
| 2982 | } | ||
| 2983 | |||
| 2984 | static ssize_t | ||
| 2985 | ftrace_pid_write(struct file *filp, const char __user *ubuf, | ||
| 2986 | size_t cnt, loff_t *ppos) | ||
| 2987 | { | ||
| 2988 | char buf[64], *tmp; | ||
| 2989 | long val; | ||
| 2990 | int ret; | ||
| 2991 | |||
| 2992 | if (cnt >= sizeof(buf)) | ||
| 2993 | return -EINVAL; | ||
| 2994 | |||
| 2995 | if (copy_from_user(&buf, ubuf, cnt)) | ||
| 2996 | return -EFAULT; | ||
| 2997 | |||
| 2998 | buf[cnt] = 0; | ||
| 2999 | |||
| 3000 | /* | ||
| 3001 | * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid" | ||
| 3002 | * to clean the filter quietly. | ||
| 3003 | */ | ||
| 3004 | tmp = strstrip(buf); | ||
| 3005 | if (strlen(tmp) == 0) | ||
| 3006 | return 1; | ||
| 3007 | |||
| 3008 | ret = strict_strtol(tmp, 10, &val); | ||
| 3009 | if (ret < 0) | ||
| 3010 | return ret; | ||
| 3011 | |||
| 3012 | ret = ftrace_pid_add(val); | ||
| 3013 | |||
| 3014 | return ret ? ret : cnt; | ||
| 3015 | } | ||
| 3016 | |||
| 3017 | static int | ||
| 3018 | ftrace_pid_release(struct inode *inode, struct file *file) | ||
| 3019 | { | ||
| 3020 | if (file->f_mode & FMODE_READ) | ||
| 3021 | seq_release(inode, file); | ||
| 3022 | |||
| 3023 | return 0; | ||
| 2929 | } | 3024 | } |
| 2930 | 3025 | ||
| 2931 | static const struct file_operations ftrace_pid_fops = { | 3026 | static const struct file_operations ftrace_pid_fops = { |
| 2932 | .read = ftrace_pid_read, | 3027 | .open = ftrace_pid_open, |
| 2933 | .write = ftrace_pid_write, | 3028 | .write = ftrace_pid_write, |
| 3029 | .read = seq_read, | ||
| 3030 | .llseek = seq_lseek, | ||
| 3031 | .release = ftrace_pid_release, | ||
| 2934 | }; | 3032 | }; |
| 2935 | 3033 | ||
| 2936 | static __init int ftrace_init_debugfs(void) | 3034 | static __init int ftrace_init_debugfs(void) |
| @@ -3293,4 +3391,3 @@ void ftrace_graph_stop(void) | |||
| 3293 | ftrace_stop(); | 3391 | ftrace_stop(); |
| 3294 | } | 3392 | } |
| 3295 | #endif | 3393 | #endif |
| 3296 | |||
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 5dd017fea6f5..a72c6e03deec 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
| @@ -1787,9 +1787,9 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, | |||
| 1787 | static struct ring_buffer_event * | 1787 | static struct ring_buffer_event * |
| 1788 | rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, | 1788 | rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, |
| 1789 | unsigned long length, unsigned long tail, | 1789 | unsigned long length, unsigned long tail, |
| 1790 | struct buffer_page *commit_page, | ||
| 1791 | struct buffer_page *tail_page, u64 *ts) | 1790 | struct buffer_page *tail_page, u64 *ts) |
| 1792 | { | 1791 | { |
| 1792 | struct buffer_page *commit_page = cpu_buffer->commit_page; | ||
| 1793 | struct ring_buffer *buffer = cpu_buffer->buffer; | 1793 | struct ring_buffer *buffer = cpu_buffer->buffer; |
| 1794 | struct buffer_page *next_page; | 1794 | struct buffer_page *next_page; |
| 1795 | int ret; | 1795 | int ret; |
| @@ -1892,13 +1892,10 @@ static struct ring_buffer_event * | |||
| 1892 | __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, | 1892 | __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, |
| 1893 | unsigned type, unsigned long length, u64 *ts) | 1893 | unsigned type, unsigned long length, u64 *ts) |
| 1894 | { | 1894 | { |
| 1895 | struct buffer_page *tail_page, *commit_page; | 1895 | struct buffer_page *tail_page; |
| 1896 | struct ring_buffer_event *event; | 1896 | struct ring_buffer_event *event; |
| 1897 | unsigned long tail, write; | 1897 | unsigned long tail, write; |
| 1898 | 1898 | ||
| 1899 | commit_page = cpu_buffer->commit_page; | ||
| 1900 | /* we just need to protect against interrupts */ | ||
| 1901 | barrier(); | ||
| 1902 | tail_page = cpu_buffer->tail_page; | 1899 | tail_page = cpu_buffer->tail_page; |
| 1903 | write = local_add_return(length, &tail_page->write); | 1900 | write = local_add_return(length, &tail_page->write); |
| 1904 | 1901 | ||
| @@ -1909,7 +1906,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, | |||
| 1909 | /* See if we shot pass the end of this buffer page */ | 1906 | /* See if we shot pass the end of this buffer page */ |
| 1910 | if (write > BUF_PAGE_SIZE) | 1907 | if (write > BUF_PAGE_SIZE) |
| 1911 | return rb_move_tail(cpu_buffer, length, tail, | 1908 | return rb_move_tail(cpu_buffer, length, tail, |
| 1912 | commit_page, tail_page, ts); | 1909 | tail_page, ts); |
| 1913 | 1910 | ||
| 1914 | /* We reserved something on the buffer */ | 1911 | /* We reserved something on the buffer */ |
| 1915 | 1912 | ||
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c index 573d3cc762c3..b2477caf09c2 100644 --- a/kernel/trace/ring_buffer_benchmark.c +++ b/kernel/trace/ring_buffer_benchmark.c | |||
| @@ -35,6 +35,28 @@ static int disable_reader; | |||
| 35 | module_param(disable_reader, uint, 0644); | 35 | module_param(disable_reader, uint, 0644); |
| 36 | MODULE_PARM_DESC(disable_reader, "only run producer"); | 36 | MODULE_PARM_DESC(disable_reader, "only run producer"); |
| 37 | 37 | ||
| 38 | static int write_iteration = 50; | ||
| 39 | module_param(write_iteration, uint, 0644); | ||
| 40 | MODULE_PARM_DESC(write_iteration, "# of writes between timestamp readings"); | ||
| 41 | |||
| 42 | static int producer_nice = 19; | ||
| 43 | static int consumer_nice = 19; | ||
| 44 | |||
| 45 | static int producer_fifo = -1; | ||
| 46 | static int consumer_fifo = -1; | ||
| 47 | |||
| 48 | module_param(producer_nice, uint, 0644); | ||
| 49 | MODULE_PARM_DESC(producer_nice, "nice prio for producer"); | ||
| 50 | |||
| 51 | module_param(consumer_nice, uint, 0644); | ||
| 52 | MODULE_PARM_DESC(consumer_nice, "nice prio for consumer"); | ||
| 53 | |||
| 54 | module_param(producer_fifo, uint, 0644); | ||
| 55 | MODULE_PARM_DESC(producer_fifo, "fifo prio for producer"); | ||
| 56 | |||
| 57 | module_param(consumer_fifo, uint, 0644); | ||
| 58 | MODULE_PARM_DESC(consumer_fifo, "fifo prio for consumer"); | ||
| 59 | |||
| 38 | static int read_events; | 60 | static int read_events; |
| 39 | 61 | ||
| 40 | static int kill_test; | 62 | static int kill_test; |
| @@ -208,15 +230,18 @@ static void ring_buffer_producer(void) | |||
| 208 | do { | 230 | do { |
| 209 | struct ring_buffer_event *event; | 231 | struct ring_buffer_event *event; |
| 210 | int *entry; | 232 | int *entry; |
| 211 | 233 | int i; | |
| 212 | event = ring_buffer_lock_reserve(buffer, 10); | 234 | |
| 213 | if (!event) { | 235 | for (i = 0; i < write_iteration; i++) { |
| 214 | missed++; | 236 | event = ring_buffer_lock_reserve(buffer, 10); |
| 215 | } else { | 237 | if (!event) { |
| 216 | hit++; | 238 | missed++; |
| 217 | entry = ring_buffer_event_data(event); | 239 | } else { |
| 218 | *entry = smp_processor_id(); | 240 | hit++; |
| 219 | ring_buffer_unlock_commit(buffer, event); | 241 | entry = ring_buffer_event_data(event); |
| 242 | *entry = smp_processor_id(); | ||
| 243 | ring_buffer_unlock_commit(buffer, event); | ||
| 244 | } | ||
| 220 | } | 245 | } |
| 221 | do_gettimeofday(&end_tv); | 246 | do_gettimeofday(&end_tv); |
| 222 | 247 | ||
| @@ -263,6 +288,27 @@ static void ring_buffer_producer(void) | |||
| 263 | 288 | ||
| 264 | if (kill_test) | 289 | if (kill_test) |
| 265 | trace_printk("ERROR!\n"); | 290 | trace_printk("ERROR!\n"); |
| 291 | |||
| 292 | if (!disable_reader) { | ||
| 293 | if (consumer_fifo < 0) | ||
| 294 | trace_printk("Running Consumer at nice: %d\n", | ||
| 295 | consumer_nice); | ||
| 296 | else | ||
| 297 | trace_printk("Running Consumer at SCHED_FIFO %d\n", | ||
| 298 | consumer_fifo); | ||
| 299 | } | ||
| 300 | if (producer_fifo < 0) | ||
| 301 | trace_printk("Running Producer at nice: %d\n", | ||
| 302 | producer_nice); | ||
| 303 | else | ||
| 304 | trace_printk("Running Producer at SCHED_FIFO %d\n", | ||
| 305 | producer_fifo); | ||
| 306 | |||
| 307 | /* Let the user know that the test is running at low priority */ | ||
| 308 | if (producer_fifo < 0 && consumer_fifo < 0 && | ||
| 309 | producer_nice == 19 && consumer_nice == 19) | ||
| 310 | trace_printk("WARNING!!! This test is running at lowest priority.\n"); | ||
| 311 | |||
| 266 | trace_printk("Time: %lld (usecs)\n", time); | 312 | trace_printk("Time: %lld (usecs)\n", time); |
| 267 | trace_printk("Overruns: %lld\n", overruns); | 313 | trace_printk("Overruns: %lld\n", overruns); |
| 268 | if (disable_reader) | 314 | if (disable_reader) |
| @@ -392,6 +438,27 @@ static int __init ring_buffer_benchmark_init(void) | |||
| 392 | if (IS_ERR(producer)) | 438 | if (IS_ERR(producer)) |
| 393 | goto out_kill; | 439 | goto out_kill; |
| 394 | 440 | ||
| 441 | /* | ||
| 442 | * Run them as low-prio background tasks by default: | ||
| 443 | */ | ||
| 444 | if (!disable_reader) { | ||
| 445 | if (consumer_fifo >= 0) { | ||
| 446 | struct sched_param param = { | ||
| 447 | .sched_priority = consumer_fifo | ||
| 448 | }; | ||
| 449 | sched_setscheduler(consumer, SCHED_FIFO, ¶m); | ||
| 450 | } else | ||
| 451 | set_user_nice(consumer, consumer_nice); | ||
| 452 | } | ||
| 453 | |||
| 454 | if (producer_fifo >= 0) { | ||
| 455 | struct sched_param param = { | ||
| 456 | .sched_priority = consumer_fifo | ||
| 457 | }; | ||
| 458 | sched_setscheduler(producer, SCHED_FIFO, ¶m); | ||
| 459 | } else | ||
| 460 | set_user_nice(producer, producer_nice); | ||
| 461 | |||
| 395 | return 0; | 462 | return 0; |
| 396 | 463 | ||
| 397 | out_kill: | 464 | out_kill: |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 12b49caedf82..874f2893cff0 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf); | |||
| 129 | static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; | 129 | static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; |
| 130 | static char *default_bootup_tracer; | 130 | static char *default_bootup_tracer; |
| 131 | 131 | ||
| 132 | static int __init set_ftrace(char *str) | 132 | static int __init set_cmdline_ftrace(char *str) |
| 133 | { | 133 | { |
| 134 | strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); | 134 | strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); |
| 135 | default_bootup_tracer = bootup_tracer_buf; | 135 | default_bootup_tracer = bootup_tracer_buf; |
| @@ -137,7 +137,7 @@ static int __init set_ftrace(char *str) | |||
| 137 | ring_buffer_expanded = 1; | 137 | ring_buffer_expanded = 1; |
| 138 | return 1; | 138 | return 1; |
| 139 | } | 139 | } |
| 140 | __setup("ftrace=", set_ftrace); | 140 | __setup("ftrace=", set_cmdline_ftrace); |
| 141 | 141 | ||
| 142 | static int __init set_ftrace_dump_on_oops(char *str) | 142 | static int __init set_ftrace_dump_on_oops(char *str) |
| 143 | { | 143 | { |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 405cb850b75d..acef8b4636f0 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -483,10 +483,6 @@ static inline int ftrace_graph_addr(unsigned long addr) | |||
| 483 | return 0; | 483 | return 0; |
| 484 | } | 484 | } |
| 485 | #else | 485 | #else |
| 486 | static inline int ftrace_trace_addr(unsigned long addr) | ||
| 487 | { | ||
| 488 | return 1; | ||
| 489 | } | ||
| 490 | static inline int ftrace_graph_addr(unsigned long addr) | 486 | static inline int ftrace_graph_addr(unsigned long addr) |
| 491 | { | 487 | { |
| 492 | return 1; | 488 | return 1; |
| @@ -500,12 +496,12 @@ print_graph_function(struct trace_iterator *iter) | |||
| 500 | } | 496 | } |
| 501 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 497 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
| 502 | 498 | ||
| 503 | extern struct pid *ftrace_pid_trace; | 499 | extern struct list_head ftrace_pids; |
| 504 | 500 | ||
| 505 | #ifdef CONFIG_FUNCTION_TRACER | 501 | #ifdef CONFIG_FUNCTION_TRACER |
| 506 | static inline int ftrace_trace_task(struct task_struct *task) | 502 | static inline int ftrace_trace_task(struct task_struct *task) |
| 507 | { | 503 | { |
| 508 | if (!ftrace_pid_trace) | 504 | if (list_empty(&ftrace_pids)) |
| 509 | return 1; | 505 | return 1; |
| 510 | 506 | ||
| 511 | return test_tsk_trace_trace(task); | 507 | return test_tsk_trace_trace(task); |
| @@ -699,22 +695,40 @@ struct event_subsystem { | |||
| 699 | }; | 695 | }; |
| 700 | 696 | ||
| 701 | struct filter_pred; | 697 | struct filter_pred; |
| 698 | struct regex; | ||
| 702 | 699 | ||
| 703 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, | 700 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, |
| 704 | int val1, int val2); | 701 | int val1, int val2); |
| 705 | 702 | ||
| 703 | typedef int (*regex_match_func)(char *str, struct regex *r, int len); | ||
| 704 | |||
| 705 | enum regex_type { | ||
| 706 | MATCH_FULL, | ||
| 707 | MATCH_FRONT_ONLY, | ||
| 708 | MATCH_MIDDLE_ONLY, | ||
| 709 | MATCH_END_ONLY, | ||
| 710 | }; | ||
| 711 | |||
| 712 | struct regex { | ||
| 713 | char pattern[MAX_FILTER_STR_VAL]; | ||
| 714 | int len; | ||
| 715 | int field_len; | ||
| 716 | regex_match_func match; | ||
| 717 | }; | ||
| 718 | |||
| 706 | struct filter_pred { | 719 | struct filter_pred { |
| 707 | filter_pred_fn_t fn; | 720 | filter_pred_fn_t fn; |
| 708 | u64 val; | 721 | u64 val; |
| 709 | char str_val[MAX_FILTER_STR_VAL]; | 722 | struct regex regex; |
| 710 | int str_len; | 723 | char *field_name; |
| 711 | char *field_name; | 724 | int offset; |
| 712 | int offset; | 725 | int not; |
| 713 | int not; | 726 | int op; |
| 714 | int op; | 727 | int pop_n; |
| 715 | int pop_n; | ||
| 716 | }; | 728 | }; |
| 717 | 729 | ||
| 730 | extern enum regex_type | ||
| 731 | filter_parse_regex(char *buff, int len, char **search, int *not); | ||
| 718 | extern void print_event_filter(struct ftrace_event_call *call, | 732 | extern void print_event_filter(struct ftrace_event_call *call, |
| 719 | struct trace_seq *s); | 733 | struct trace_seq *s); |
| 720 | extern int apply_event_filter(struct ftrace_event_call *call, | 734 | extern int apply_event_filter(struct ftrace_event_call *call, |
diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c index 20c5f92e28a8..878c03f386ba 100644 --- a/kernel/trace/trace_clock.c +++ b/kernel/trace/trace_clock.c | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | #include <linux/ktime.h> | 20 | #include <linux/ktime.h> |
| 21 | #include <linux/trace_clock.h> | 21 | #include <linux/trace_clock.h> |
| 22 | 22 | ||
| 23 | #include "trace.h" | ||
| 24 | |||
| 23 | /* | 25 | /* |
| 24 | * trace_clock_local(): the simplest and least coherent tracing clock. | 26 | * trace_clock_local(): the simplest and least coherent tracing clock. |
| 25 | * | 27 | * |
| @@ -28,17 +30,17 @@ | |||
| 28 | */ | 30 | */ |
| 29 | u64 notrace trace_clock_local(void) | 31 | u64 notrace trace_clock_local(void) |
| 30 | { | 32 | { |
| 31 | unsigned long flags; | ||
| 32 | u64 clock; | 33 | u64 clock; |
| 34 | int resched; | ||
| 33 | 35 | ||
| 34 | /* | 36 | /* |
| 35 | * sched_clock() is an architecture implemented, fast, scalable, | 37 | * sched_clock() is an architecture implemented, fast, scalable, |
| 36 | * lockless clock. It is not guaranteed to be coherent across | 38 | * lockless clock. It is not guaranteed to be coherent across |
| 37 | * CPUs, nor across CPU idle events. | 39 | * CPUs, nor across CPU idle events. |
| 38 | */ | 40 | */ |
| 39 | raw_local_irq_save(flags); | 41 | resched = ftrace_preempt_disable(); |
| 40 | clock = sched_clock(); | 42 | clock = sched_clock(); |
| 41 | raw_local_irq_restore(flags); | 43 | ftrace_preempt_enable(resched); |
| 42 | 44 | ||
| 43 | return clock; | 45 | return clock; |
| 44 | } | 46 | } |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index d128f65778e6..5e9ffc33f6db 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -878,9 +878,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
| 878 | "'%s/filter' entry\n", name); | 878 | "'%s/filter' entry\n", name); |
| 879 | } | 879 | } |
| 880 | 880 | ||
| 881 | entry = trace_create_file("enable", 0644, system->entry, | 881 | trace_create_file("enable", 0644, system->entry, |
| 882 | (void *)system->name, | 882 | (void *)system->name, |
| 883 | &ftrace_system_enable_fops); | 883 | &ftrace_system_enable_fops); |
| 884 | 884 | ||
| 885 | return system->entry; | 885 | return system->entry; |
| 886 | } | 886 | } |
| @@ -892,7 +892,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 892 | const struct file_operations *filter, | 892 | const struct file_operations *filter, |
| 893 | const struct file_operations *format) | 893 | const struct file_operations *format) |
| 894 | { | 894 | { |
| 895 | struct dentry *entry; | ||
| 896 | int ret; | 895 | int ret; |
| 897 | 896 | ||
| 898 | /* | 897 | /* |
| @@ -910,12 +909,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 910 | } | 909 | } |
| 911 | 910 | ||
| 912 | if (call->regfunc) | 911 | if (call->regfunc) |
| 913 | entry = trace_create_file("enable", 0644, call->dir, call, | 912 | trace_create_file("enable", 0644, call->dir, call, |
| 914 | enable); | 913 | enable); |
| 915 | 914 | ||
| 916 | if (call->id && call->profile_enable) | 915 | if (call->id && call->profile_enable) |
| 917 | entry = trace_create_file("id", 0444, call->dir, call, | 916 | trace_create_file("id", 0444, call->dir, call, |
| 918 | id); | 917 | id); |
| 919 | 918 | ||
| 920 | if (call->define_fields) { | 919 | if (call->define_fields) { |
| 921 | ret = call->define_fields(call); | 920 | ret = call->define_fields(call); |
| @@ -924,16 +923,16 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 924 | " events/%s\n", call->name); | 923 | " events/%s\n", call->name); |
| 925 | return ret; | 924 | return ret; |
| 926 | } | 925 | } |
| 927 | entry = trace_create_file("filter", 0644, call->dir, call, | 926 | trace_create_file("filter", 0644, call->dir, call, |
| 928 | filter); | 927 | filter); |
| 929 | } | 928 | } |
| 930 | 929 | ||
| 931 | /* A trace may not want to export its format */ | 930 | /* A trace may not want to export its format */ |
| 932 | if (!call->show_format) | 931 | if (!call->show_format) |
| 933 | return 0; | 932 | return 0; |
| 934 | 933 | ||
| 935 | entry = trace_create_file("format", 0444, call->dir, call, | 934 | trace_create_file("format", 0444, call->dir, call, |
| 936 | format); | 935 | format); |
| 937 | 936 | ||
| 938 | return 0; | 937 | return 0; |
| 939 | } | 938 | } |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 98a6cc5c64ed..92672016da28 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
| @@ -18,8 +18,6 @@ | |||
| 18 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> | 18 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/debugfs.h> | ||
| 22 | #include <linux/uaccess.h> | ||
| 23 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 24 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
| 25 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
| @@ -197,9 +195,9 @@ static int filter_pred_string(struct filter_pred *pred, void *event, | |||
| 197 | char *addr = (char *)(event + pred->offset); | 195 | char *addr = (char *)(event + pred->offset); |
| 198 | int cmp, match; | 196 | int cmp, match; |
| 199 | 197 | ||
| 200 | cmp = strncmp(addr, pred->str_val, pred->str_len); | 198 | cmp = pred->regex.match(addr, &pred->regex, pred->regex.field_len); |
| 201 | 199 | ||
| 202 | match = (!cmp) ^ pred->not; | 200 | match = cmp ^ pred->not; |
| 203 | 201 | ||
| 204 | return match; | 202 | return match; |
| 205 | } | 203 | } |
| @@ -211,9 +209,9 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event, | |||
| 211 | char **addr = (char **)(event + pred->offset); | 209 | char **addr = (char **)(event + pred->offset); |
| 212 | int cmp, match; | 210 | int cmp, match; |
| 213 | 211 | ||
| 214 | cmp = strncmp(*addr, pred->str_val, pred->str_len); | 212 | cmp = pred->regex.match(*addr, &pred->regex, pred->regex.field_len); |
| 215 | 213 | ||
| 216 | match = (!cmp) ^ pred->not; | 214 | match = cmp ^ pred->not; |
| 217 | 215 | ||
| 218 | return match; | 216 | return match; |
| 219 | } | 217 | } |
| @@ -237,9 +235,9 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event, | |||
| 237 | char *addr = (char *)(event + str_loc); | 235 | char *addr = (char *)(event + str_loc); |
| 238 | int cmp, match; | 236 | int cmp, match; |
| 239 | 237 | ||
| 240 | cmp = strncmp(addr, pred->str_val, str_len); | 238 | cmp = pred->regex.match(addr, &pred->regex, str_len); |
| 241 | 239 | ||
| 242 | match = (!cmp) ^ pred->not; | 240 | match = cmp ^ pred->not; |
| 243 | 241 | ||
| 244 | return match; | 242 | return match; |
| 245 | } | 243 | } |
| @@ -250,6 +248,124 @@ static int filter_pred_none(struct filter_pred *pred, void *event, | |||
| 250 | return 0; | 248 | return 0; |
| 251 | } | 249 | } |
| 252 | 250 | ||
| 251 | /* Basic regex callbacks */ | ||
| 252 | static int regex_match_full(char *str, struct regex *r, int len) | ||
| 253 | { | ||
| 254 | if (strncmp(str, r->pattern, len) == 0) | ||
| 255 | return 1; | ||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int regex_match_front(char *str, struct regex *r, int len) | ||
| 260 | { | ||
| 261 | if (strncmp(str, r->pattern, len) == 0) | ||
| 262 | return 1; | ||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int regex_match_middle(char *str, struct regex *r, int len) | ||
| 267 | { | ||
| 268 | if (strstr(str, r->pattern)) | ||
| 269 | return 1; | ||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | static int regex_match_end(char *str, struct regex *r, int len) | ||
| 274 | { | ||
| 275 | char *ptr = strstr(str, r->pattern); | ||
| 276 | |||
| 277 | if (ptr && (ptr[r->len] == 0)) | ||
| 278 | return 1; | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | /** | ||
| 283 | * filter_parse_regex - parse a basic regex | ||
| 284 | * @buff: the raw regex | ||
| 285 | * @len: length of the regex | ||
| 286 | * @search: will point to the beginning of the string to compare | ||
| 287 | * @not: tell whether the match will have to be inverted | ||
| 288 | * | ||
| 289 | * This passes in a buffer containing a regex and this function will | ||
| 290 | * set search to point to the search part of the buffer and | ||
| 291 | * return the type of search it is (see enum above). | ||
| 292 | * This does modify buff. | ||
| 293 | * | ||
| 294 | * Returns enum type. | ||
| 295 | * search returns the pointer to use for comparison. | ||
| 296 | * not returns 1 if buff started with a '!' | ||
| 297 | * 0 otherwise. | ||
| 298 | */ | ||
| 299 | enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not) | ||
| 300 | { | ||
| 301 | int type = MATCH_FULL; | ||
| 302 | int i; | ||
| 303 | |||
| 304 | if (buff[0] == '!') { | ||
| 305 | *not = 1; | ||
| 306 | buff++; | ||
| 307 | len--; | ||
| 308 | } else | ||
| 309 | *not = 0; | ||
| 310 | |||
| 311 | *search = buff; | ||
| 312 | |||
| 313 | for (i = 0; i < len; i++) { | ||
| 314 | if (buff[i] == '*') { | ||
| 315 | if (!i) { | ||
| 316 | *search = buff + 1; | ||
| 317 | type = MATCH_END_ONLY; | ||
| 318 | } else { | ||
| 319 | if (type == MATCH_END_ONLY) | ||
| 320 | type = MATCH_MIDDLE_ONLY; | ||
| 321 | else | ||
| 322 | type = MATCH_FRONT_ONLY; | ||
| 323 | buff[i] = 0; | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | return type; | ||
| 330 | } | ||
| 331 | |||
| 332 | static int filter_build_regex(struct filter_pred *pred) | ||
| 333 | { | ||
| 334 | struct regex *r = &pred->regex; | ||
| 335 | char *search, *dup; | ||
| 336 | enum regex_type type; | ||
| 337 | int not; | ||
| 338 | |||
| 339 | type = filter_parse_regex(r->pattern, r->len, &search, ¬); | ||
| 340 | dup = kstrdup(search, GFP_KERNEL); | ||
| 341 | if (!dup) | ||
| 342 | return -ENOMEM; | ||
| 343 | |||
| 344 | strcpy(r->pattern, dup); | ||
| 345 | kfree(dup); | ||
| 346 | |||
| 347 | r->len = strlen(r->pattern); | ||
| 348 | |||
| 349 | switch (type) { | ||
| 350 | case MATCH_FULL: | ||
| 351 | r->match = regex_match_full; | ||
| 352 | break; | ||
| 353 | case MATCH_FRONT_ONLY: | ||
| 354 | r->match = regex_match_front; | ||
| 355 | break; | ||
| 356 | case MATCH_MIDDLE_ONLY: | ||
| 357 | r->match = regex_match_middle; | ||
| 358 | break; | ||
| 359 | case MATCH_END_ONLY: | ||
| 360 | r->match = regex_match_end; | ||
| 361 | break; | ||
| 362 | } | ||
| 363 | |||
| 364 | pred->not ^= not; | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 253 | /* return 1 if event matches, 0 otherwise (discard) */ | 369 | /* return 1 if event matches, 0 otherwise (discard) */ |
| 254 | int filter_match_preds(struct ftrace_event_call *call, void *rec) | 370 | int filter_match_preds(struct ftrace_event_call *call, void *rec) |
| 255 | { | 371 | { |
| @@ -396,7 +512,7 @@ static void filter_clear_pred(struct filter_pred *pred) | |||
| 396 | { | 512 | { |
| 397 | kfree(pred->field_name); | 513 | kfree(pred->field_name); |
| 398 | pred->field_name = NULL; | 514 | pred->field_name = NULL; |
| 399 | pred->str_len = 0; | 515 | pred->regex.len = 0; |
| 400 | } | 516 | } |
| 401 | 517 | ||
| 402 | static int filter_set_pred(struct filter_pred *dest, | 518 | static int filter_set_pred(struct filter_pred *dest, |
| @@ -660,21 +776,24 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
| 660 | } | 776 | } |
| 661 | 777 | ||
| 662 | if (is_string_field(field)) { | 778 | if (is_string_field(field)) { |
| 663 | pred->str_len = field->size; | 779 | ret = filter_build_regex(pred); |
| 780 | if (ret) | ||
| 781 | return ret; | ||
| 664 | 782 | ||
| 665 | if (field->filter_type == FILTER_STATIC_STRING) | 783 | if (field->filter_type == FILTER_STATIC_STRING) { |
| 666 | fn = filter_pred_string; | 784 | fn = filter_pred_string; |
| 667 | else if (field->filter_type == FILTER_DYN_STRING) | 785 | pred->regex.field_len = field->size; |
| 668 | fn = filter_pred_strloc; | 786 | } else if (field->filter_type == FILTER_DYN_STRING) |
| 787 | fn = filter_pred_strloc; | ||
| 669 | else { | 788 | else { |
| 670 | fn = filter_pred_pchar; | 789 | fn = filter_pred_pchar; |
| 671 | pred->str_len = strlen(pred->str_val); | 790 | pred->regex.field_len = strlen(pred->regex.pattern); |
| 672 | } | 791 | } |
| 673 | } else { | 792 | } else { |
| 674 | if (field->is_signed) | 793 | if (field->is_signed) |
| 675 | ret = strict_strtoll(pred->str_val, 0, &val); | 794 | ret = strict_strtoll(pred->regex.pattern, 0, &val); |
| 676 | else | 795 | else |
| 677 | ret = strict_strtoull(pred->str_val, 0, &val); | 796 | ret = strict_strtoull(pred->regex.pattern, 0, &val); |
| 678 | if (ret) { | 797 | if (ret) { |
| 679 | parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); | 798 | parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); |
| 680 | return -EINVAL; | 799 | return -EINVAL; |
| @@ -1045,8 +1164,8 @@ static struct filter_pred *create_pred(int op, char *operand1, char *operand2) | |||
| 1045 | return NULL; | 1164 | return NULL; |
| 1046 | } | 1165 | } |
| 1047 | 1166 | ||
| 1048 | strcpy(pred->str_val, operand2); | 1167 | strcpy(pred->regex.pattern, operand2); |
| 1049 | pred->str_len = strlen(operand2); | 1168 | pred->regex.len = strlen(pred->regex.pattern); |
| 1050 | 1169 | ||
| 1051 | pred->op = op; | 1170 | pred->op = op; |
| 1052 | 1171 | ||
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 9753fcc61bc5..c74848ddb85a 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c | |||
| @@ -48,11 +48,11 @@ | |||
| 48 | struct ____ftrace_##name { \ | 48 | struct ____ftrace_##name { \ |
| 49 | tstruct \ | 49 | tstruct \ |
| 50 | }; \ | 50 | }; \ |
| 51 | static void __used ____ftrace_check_##name(void) \ | 51 | static void __always_unused ____ftrace_check_##name(void) \ |
| 52 | { \ | 52 | { \ |
| 53 | struct ____ftrace_##name *__entry = NULL; \ | 53 | struct ____ftrace_##name *__entry = NULL; \ |
| 54 | \ | 54 | \ |
| 55 | /* force cmpile-time check on F_printk() */ \ | 55 | /* force compile-time check on F_printk() */ \ |
| 56 | printk(print); \ | 56 | printk(print); \ |
| 57 | } | 57 | } |
| 58 | 58 | ||
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 527e17eae575..ddee9c593732 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
| @@ -14,6 +14,69 @@ static int sys_refcount_exit; | |||
| 14 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); | 14 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); |
| 15 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); | 15 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); |
| 16 | 16 | ||
| 17 | extern unsigned long __start_syscalls_metadata[]; | ||
| 18 | extern unsigned long __stop_syscalls_metadata[]; | ||
| 19 | |||
| 20 | static struct syscall_metadata **syscalls_metadata; | ||
| 21 | |||
| 22 | static struct syscall_metadata *find_syscall_meta(unsigned long syscall) | ||
| 23 | { | ||
| 24 | struct syscall_metadata *start; | ||
| 25 | struct syscall_metadata *stop; | ||
| 26 | char str[KSYM_SYMBOL_LEN]; | ||
| 27 | |||
| 28 | |||
| 29 | start = (struct syscall_metadata *)__start_syscalls_metadata; | ||
| 30 | stop = (struct syscall_metadata *)__stop_syscalls_metadata; | ||
| 31 | kallsyms_lookup(syscall, NULL, NULL, NULL, str); | ||
| 32 | |||
| 33 | for ( ; start < stop; start++) { | ||
| 34 | /* | ||
| 35 | * Only compare after the "sys" prefix. Archs that use | ||
| 36 | * syscall wrappers may have syscalls symbols aliases prefixed | ||
| 37 | * with "SyS" instead of "sys", leading to an unwanted | ||
| 38 | * mismatch. | ||
| 39 | */ | ||
| 40 | if (start->name && !strcmp(start->name + 3, str + 3)) | ||
| 41 | return start; | ||
| 42 | } | ||
| 43 | return NULL; | ||
| 44 | } | ||
| 45 | |||
| 46 | static struct syscall_metadata *syscall_nr_to_meta(int nr) | ||
| 47 | { | ||
| 48 | if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) | ||
| 49 | return NULL; | ||
| 50 | |||
| 51 | return syscalls_metadata[nr]; | ||
| 52 | } | ||
| 53 | |||
| 54 | int syscall_name_to_nr(char *name) | ||
| 55 | { | ||
| 56 | int i; | ||
| 57 | |||
| 58 | if (!syscalls_metadata) | ||
| 59 | return -1; | ||
| 60 | |||
| 61 | for (i = 0; i < NR_syscalls; i++) { | ||
| 62 | if (syscalls_metadata[i]) { | ||
| 63 | if (!strcmp(syscalls_metadata[i]->name, name)) | ||
| 64 | return i; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | return -1; | ||
| 68 | } | ||
| 69 | |||
| 70 | void set_syscall_enter_id(int num, int id) | ||
| 71 | { | ||
| 72 | syscalls_metadata[num]->enter_id = id; | ||
| 73 | } | ||
| 74 | |||
| 75 | void set_syscall_exit_id(int num, int id) | ||
| 76 | { | ||
| 77 | syscalls_metadata[num]->exit_id = id; | ||
| 78 | } | ||
| 79 | |||
| 17 | enum print_line_t | 80 | enum print_line_t |
| 18 | print_syscall_enter(struct trace_iterator *iter, int flags) | 81 | print_syscall_enter(struct trace_iterator *iter, int flags) |
| 19 | { | 82 | { |
| @@ -375,6 +438,29 @@ struct trace_event event_syscall_exit = { | |||
| 375 | .trace = print_syscall_exit, | 438 | .trace = print_syscall_exit, |
| 376 | }; | 439 | }; |
| 377 | 440 | ||
| 441 | int __init init_ftrace_syscalls(void) | ||
| 442 | { | ||
| 443 | struct syscall_metadata *meta; | ||
| 444 | unsigned long addr; | ||
| 445 | int i; | ||
| 446 | |||
| 447 | syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * | ||
| 448 | NR_syscalls, GFP_KERNEL); | ||
| 449 | if (!syscalls_metadata) { | ||
| 450 | WARN_ON(1); | ||
| 451 | return -ENOMEM; | ||
| 452 | } | ||
| 453 | |||
| 454 | for (i = 0; i < NR_syscalls; i++) { | ||
| 455 | addr = arch_syscall_addr(i); | ||
| 456 | meta = find_syscall_meta(addr); | ||
| 457 | syscalls_metadata[i] = meta; | ||
| 458 | } | ||
| 459 | |||
| 460 | return 0; | ||
| 461 | } | ||
| 462 | core_initcall(init_ftrace_syscalls); | ||
| 463 | |||
| 378 | #ifdef CONFIG_EVENT_PROFILE | 464 | #ifdef CONFIG_EVENT_PROFILE |
| 379 | 465 | ||
| 380 | static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); | 466 | static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); |
diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c index 39f1029e3525..4ebfa5a164d7 100644 --- a/lib/kernel_lock.c +++ b/lib/kernel_lock.c | |||
| @@ -5,10 +5,13 @@ | |||
| 5 | * relegated to obsolescence, but used by various less | 5 | * relegated to obsolescence, but used by various less |
| 6 | * important (or lazy) subsystems. | 6 | * important (or lazy) subsystems. |
| 7 | */ | 7 | */ |
| 8 | #include <linux/smp_lock.h> | ||
| 9 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 10 | #include <linux/kallsyms.h> | 9 | #include <linux/kallsyms.h> |
| 11 | #include <linux/semaphore.h> | 10 | #include <linux/semaphore.h> |
| 11 | #include <linux/smp_lock.h> | ||
| 12 | |||
| 13 | #define CREATE_TRACE_POINTS | ||
| 14 | #include <trace/events/bkl.h> | ||
| 12 | 15 | ||
| 13 | /* | 16 | /* |
| 14 | * The 'big kernel lock' | 17 | * The 'big kernel lock' |
| @@ -113,21 +116,26 @@ static inline void __unlock_kernel(void) | |||
| 113 | * This cannot happen asynchronously, so we only need to | 116 | * This cannot happen asynchronously, so we only need to |
| 114 | * worry about other CPU's. | 117 | * worry about other CPU's. |
| 115 | */ | 118 | */ |
| 116 | void __lockfunc lock_kernel(void) | 119 | void __lockfunc _lock_kernel(const char *func, const char *file, int line) |
| 117 | { | 120 | { |
| 118 | int depth = current->lock_depth+1; | 121 | int depth = current->lock_depth + 1; |
| 122 | |||
| 123 | trace_lock_kernel(func, file, line); | ||
| 124 | |||
| 119 | if (likely(!depth)) | 125 | if (likely(!depth)) |
| 120 | __lock_kernel(); | 126 | __lock_kernel(); |
| 121 | current->lock_depth = depth; | 127 | current->lock_depth = depth; |
| 122 | } | 128 | } |
| 123 | 129 | ||
| 124 | void __lockfunc unlock_kernel(void) | 130 | void __lockfunc _unlock_kernel(const char *func, const char *file, int line) |
| 125 | { | 131 | { |
| 126 | BUG_ON(current->lock_depth < 0); | 132 | BUG_ON(current->lock_depth < 0); |
| 127 | if (likely(--current->lock_depth < 0)) | 133 | if (likely(--current->lock_depth < 0)) |
| 128 | __unlock_kernel(); | 134 | __unlock_kernel(); |
| 135 | |||
| 136 | trace_unlock_kernel(func, file, line); | ||
| 129 | } | 137 | } |
| 130 | 138 | ||
| 131 | EXPORT_SYMBOL(lock_kernel); | 139 | EXPORT_SYMBOL(_lock_kernel); |
| 132 | EXPORT_SYMBOL(unlock_kernel); | 140 | EXPORT_SYMBOL(_unlock_kernel); |
| 133 | 141 | ||
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 090d300d7394..f0d14452632b 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl | |||
| @@ -6,77 +6,93 @@ | |||
| 6 | # all the offsets to the calls to mcount. | 6 | # all the offsets to the calls to mcount. |
| 7 | # | 7 | # |
| 8 | # | 8 | # |
| 9 | # What we want to end up with is a section in vmlinux called | 9 | # What we want to end up with this is that each object file will have a |
| 10 | # __mcount_loc that contains a list of pointers to all the | 10 | # section called __mcount_loc that will hold the list of pointers to mcount |
| 11 | # call sites in the kernel that call mcount. Later on boot up, the kernel | 11 | # callers. After final linking, the vmlinux will have within .init.data the |
| 12 | # will read this list, save the locations and turn them into nops. | 12 | # list of all callers to mcount between __start_mcount_loc and __stop_mcount_loc. |
| 13 | # When tracing or profiling is later enabled, these locations will then | 13 | # Later on boot up, the kernel will read this list, save the locations and turn |
| 14 | # be converted back to pointers to some function. | 14 | # them into nops. When tracing or profiling is later enabled, these locations |
| 15 | # will then be converted back to pointers to some function. | ||
| 15 | # | 16 | # |
| 16 | # This is no easy feat. This script is called just after the original | 17 | # This is no easy feat. This script is called just after the original |
| 17 | # object is compiled and before it is linked. | 18 | # object is compiled and before it is linked. |
| 18 | # | 19 | # |
| 19 | # The references to the call sites are offsets from the section of text | 20 | # When parse this object file using 'objdump', the references to the call |
| 20 | # that the call site is in. Hence, all functions in a section that | 21 | # sites are offsets from the section that the call site is in. Hence, all |
| 21 | # has a call site to mcount, will have the offset from the beginning of | 22 | # functions in a section that has a call site to mcount, will have the |
| 22 | # the section and not the beginning of the function. | 23 | # offset from the beginning of the section and not the beginning of the |
| 24 | # function. | ||
| 25 | # | ||
| 26 | # But where this section will reside finally in vmlinx is undetermined at | ||
| 27 | # this point. So we can't use this kind of offsets to record the final | ||
| 28 | # address of this call site. | ||
| 29 | # | ||
| 30 | # The trick is to change the call offset referring the start of a section to | ||
| 31 | # referring a function symbol in this section. During the link step, 'ld' will | ||
| 32 | # compute the final address according to the information we record. | ||
| 23 | # | 33 | # |
| 24 | # The trick is to find a way to record the beginning of the section. | ||
| 25 | # The way we do this is to look at the first function in the section | ||
| 26 | # which will also be the location of that section after final link. | ||
| 27 | # e.g. | 34 | # e.g. |
| 28 | # | 35 | # |
| 29 | # .section ".sched.text", "ax" | 36 | # .section ".sched.text", "ax" |
| 30 | # .globl my_func | ||
| 31 | # my_func: | ||
| 32 | # [...] | 37 | # [...] |
| 33 | # call mcount (offset: 0x5) | 38 | # func1: |
| 39 | # [...] | ||
| 40 | # call mcount (offset: 0x10) | ||
| 34 | # [...] | 41 | # [...] |
| 35 | # ret | 42 | # ret |
| 36 | # other_func: | 43 | # .globl fun2 |
| 44 | # func2: (offset: 0x20) | ||
| 37 | # [...] | 45 | # [...] |
| 38 | # call mcount (offset: 0x1b) | 46 | # [...] |
| 47 | # ret | ||
| 48 | # func3: | ||
| 49 | # [...] | ||
| 50 | # call mcount (offset: 0x30) | ||
| 39 | # [...] | 51 | # [...] |
| 40 | # | 52 | # |
| 41 | # Both relocation offsets for the mcounts in the above example will be | 53 | # Both relocation offsets for the mcounts in the above example will be |
| 42 | # offset from .sched.text. If we make another file called tmp.s with: | 54 | # offset from .sched.text. If we choose global symbol func2 as a reference and |
| 55 | # make another file called tmp.s with the new offsets: | ||
| 43 | # | 56 | # |
| 44 | # .section __mcount_loc | 57 | # .section __mcount_loc |
| 45 | # .quad my_func + 0x5 | 58 | # .quad func2 - 0x10 |
| 46 | # .quad my_func + 0x1b | 59 | # .quad func2 + 0x10 |
| 47 | # | 60 | # |
| 48 | # We can then compile this tmp.s into tmp.o, and link it to the original | 61 | # We can then compile this tmp.s into tmp.o, and link it back to the original |
| 49 | # object. | 62 | # object. |
| 50 | # | 63 | # |
| 51 | # But this gets hard if my_func is not globl (a static function). | 64 | # In our algorithm, we will choose the first global function we meet in this |
| 52 | # In such a case we have: | 65 | # section as the reference. But this gets hard if there is no global functions |
| 66 | # in this section. In such a case we have to select a local one. E.g. func1: | ||
| 53 | # | 67 | # |
| 54 | # .section ".sched.text", "ax" | 68 | # .section ".sched.text", "ax" |
| 55 | # my_func: | 69 | # func1: |
| 56 | # [...] | 70 | # [...] |
| 57 | # call mcount (offset: 0x5) | 71 | # call mcount (offset: 0x10) |
| 58 | # [...] | 72 | # [...] |
| 59 | # ret | 73 | # ret |
| 60 | # other_func: | 74 | # func2: |
| 61 | # [...] | 75 | # [...] |
| 62 | # call mcount (offset: 0x1b) | 76 | # call mcount (offset: 0x20) |
| 63 | # [...] | 77 | # [...] |
| 78 | # .section "other.section" | ||
| 64 | # | 79 | # |
| 65 | # If we make the tmp.s the same as above, when we link together with | 80 | # If we make the tmp.s the same as above, when we link together with |
| 66 | # the original object, we will end up with two symbols for my_func: | 81 | # the original object, we will end up with two symbols for func1: |
| 67 | # one local, one global. After final compile, we will end up with | 82 | # one local, one global. After final compile, we will end up with |
| 68 | # an undefined reference to my_func. | 83 | # an undefined reference to func1 or a wrong reference to another global |
| 84 | # func1 in other files. | ||
| 69 | # | 85 | # |
| 70 | # Since local objects can reference local variables, we need to find | 86 | # Since local objects can reference local variables, we need to find |
| 71 | # a way to make tmp.o reference the local objects of the original object | 87 | # a way to make tmp.o reference the local objects of the original object |
| 72 | # file after it is linked together. To do this, we convert the my_func | 88 | # file after it is linked together. To do this, we convert func1 |
| 73 | # into a global symbol before linking tmp.o. Then after we link tmp.o | 89 | # into a global symbol before linking tmp.o. Then after we link tmp.o |
| 74 | # we will only have a single symbol for my_func that is global. | 90 | # we will only have a single symbol for func1 that is global. |
| 75 | # We can convert my_func back into a local symbol and we are done. | 91 | # We can convert func1 back into a local symbol and we are done. |
| 76 | # | 92 | # |
| 77 | # Here are the steps we take: | 93 | # Here are the steps we take: |
| 78 | # | 94 | # |
| 79 | # 1) Record all the local symbols by using 'nm' | 95 | # 1) Record all the local and weak symbols by using 'nm' |
| 80 | # 2) Use objdump to find all the call site offsets and sections for | 96 | # 2) Use objdump to find all the call site offsets and sections for |
| 81 | # mcount. | 97 | # mcount. |
| 82 | # 3) Compile the list into its own object. | 98 | # 3) Compile the list into its own object. |
| @@ -86,10 +102,8 @@ | |||
| 86 | # 6) Link together this new object with the list object. | 102 | # 6) Link together this new object with the list object. |
| 87 | # 7) Convert the local functions back to local symbols and rename | 103 | # 7) Convert the local functions back to local symbols and rename |
| 88 | # the result as the original object. | 104 | # the result as the original object. |
| 89 | # End. | ||
| 90 | # 8) Link the object with the list object. | 105 | # 8) Link the object with the list object. |
| 91 | # 9) Move the result back to the original object. | 106 | # 9) Move the result back to the original object. |
| 92 | # End. | ||
| 93 | # | 107 | # |
| 94 | 108 | ||
| 95 | use strict; | 109 | use strict; |
| @@ -99,7 +113,7 @@ $P =~ s@.*/@@g; | |||
| 99 | 113 | ||
| 100 | my $V = '0.1'; | 114 | my $V = '0.1'; |
| 101 | 115 | ||
| 102 | if ($#ARGV < 7) { | 116 | if ($#ARGV != 10) { |
| 103 | print "usage: $P arch bits objdump objcopy cc ld nm rm mv is_module inputfile\n"; | 117 | print "usage: $P arch bits objdump objcopy cc ld nm rm mv is_module inputfile\n"; |
| 104 | print "version: $V\n"; | 118 | print "version: $V\n"; |
| 105 | exit(1); | 119 | exit(1); |
| @@ -109,7 +123,7 @@ my ($arch, $bits, $objdump, $objcopy, $cc, | |||
| 109 | $ld, $nm, $rm, $mv, $is_module, $inputfile) = @ARGV; | 123 | $ld, $nm, $rm, $mv, $is_module, $inputfile) = @ARGV; |
| 110 | 124 | ||
| 111 | # This file refers to mcount and shouldn't be ftraced, so lets' ignore it | 125 | # This file refers to mcount and shouldn't be ftraced, so lets' ignore it |
| 112 | if ($inputfile eq "kernel/trace/ftrace.o") { | 126 | if ($inputfile =~ m,kernel/trace/ftrace\.o$,) { |
| 113 | exit(0); | 127 | exit(0); |
| 114 | } | 128 | } |
| 115 | 129 | ||
| @@ -119,6 +133,7 @@ my %text_sections = ( | |||
| 119 | ".sched.text" => 1, | 133 | ".sched.text" => 1, |
| 120 | ".spinlock.text" => 1, | 134 | ".spinlock.text" => 1, |
| 121 | ".irqentry.text" => 1, | 135 | ".irqentry.text" => 1, |
| 136 | ".text.unlikely" => 1, | ||
| 122 | ); | 137 | ); |
| 123 | 138 | ||
| 124 | $objdump = "objdump" if ((length $objdump) == 0); | 139 | $objdump = "objdump" if ((length $objdump) == 0); |
| @@ -137,13 +152,47 @@ my %weak; # List of weak functions | |||
| 137 | my %convert; # List of local functions used that needs conversion | 152 | my %convert; # List of local functions used that needs conversion |
| 138 | 153 | ||
| 139 | my $type; | 154 | my $type; |
| 140 | my $nm_regex; # Find the local functions (return function) | 155 | my $local_regex; # Match a local function (return function) |
| 156 | my $weak_regex; # Match a weak function (return function) | ||
| 141 | my $section_regex; # Find the start of a section | 157 | my $section_regex; # Find the start of a section |
| 142 | my $function_regex; # Find the name of a function | 158 | my $function_regex; # Find the name of a function |
| 143 | # (return offset and func name) | 159 | # (return offset and func name) |
| 144 | my $mcount_regex; # Find the call site to mcount (return offset) | 160 | my $mcount_regex; # Find the call site to mcount (return offset) |
| 145 | my $alignment; # The .align value to use for $mcount_section | 161 | my $alignment; # The .align value to use for $mcount_section |
| 146 | my $section_type; # Section header plus possible alignment command | 162 | my $section_type; # Section header plus possible alignment command |
| 163 | my $can_use_local = 0; # If we can use local function references | ||
| 164 | |||
| 165 | # Shut up recordmcount if user has older objcopy | ||
| 166 | my $quiet_recordmcount = ".tmp_quiet_recordmcount"; | ||
| 167 | my $print_warning = 1; | ||
| 168 | $print_warning = 0 if ( -f $quiet_recordmcount); | ||
| 169 | |||
| 170 | ## | ||
| 171 | # check_objcopy - whether objcopy supports --globalize-symbols | ||
| 172 | # | ||
| 173 | # --globalize-symbols came out in 2.17, we must test the version | ||
| 174 | # of objcopy, and if it is less than 2.17, then we can not | ||
| 175 | # record local functions. | ||
| 176 | sub check_objcopy | ||
| 177 | { | ||
| 178 | open (IN, "$objcopy --version |") or die "error running $objcopy"; | ||
| 179 | while (<IN>) { | ||
| 180 | if (/objcopy.*\s(\d+)\.(\d+)/) { | ||
| 181 | $can_use_local = 1 if ($1 > 2 || ($1 == 2 && $2 >= 17)); | ||
| 182 | last; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | close (IN); | ||
| 186 | |||
| 187 | if (!$can_use_local && $print_warning) { | ||
| 188 | print STDERR "WARNING: could not find objcopy version or version " . | ||
| 189 | "is less than 2.17.\n" . | ||
| 190 | "\tLocal function references are disabled.\n"; | ||
| 191 | open (QUIET, ">$quiet_recordmcount"); | ||
| 192 | printf QUIET "Disables the warning from recordmcount.pl\n"; | ||
| 193 | close QUIET; | ||
| 194 | } | ||
| 195 | } | ||
| 147 | 196 | ||
| 148 | if ($arch eq "x86") { | 197 | if ($arch eq "x86") { |
| 149 | if ($bits == 64) { | 198 | if ($bits == 64) { |
| @@ -157,7 +206,8 @@ if ($arch eq "x86") { | |||
| 157 | # We base the defaults off of i386, the other archs may | 206 | # We base the defaults off of i386, the other archs may |
| 158 | # feel free to change them in the below if statements. | 207 | # feel free to change them in the below if statements. |
| 159 | # | 208 | # |
| 160 | $nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; | 209 | $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; |
| 210 | $weak_regex = "^[0-9a-fA-F]+\\s+([wW])\\s+(\\S+)"; | ||
| 161 | $section_regex = "Disassembly of section\\s+(\\S+):"; | 211 | $section_regex = "Disassembly of section\\s+(\\S+):"; |
| 162 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; | 212 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; |
| 163 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; | 213 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; |
| @@ -206,7 +256,7 @@ if ($arch eq "x86_64") { | |||
| 206 | $cc .= " -m32"; | 256 | $cc .= " -m32"; |
| 207 | 257 | ||
| 208 | } elsif ($arch eq "powerpc") { | 258 | } elsif ($arch eq "powerpc") { |
| 209 | $nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; | 259 | $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; |
| 210 | $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?.*?)>:"; | 260 | $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?.*?)>:"; |
| 211 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$"; | 261 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$"; |
| 212 | 262 | ||
| @@ -278,44 +328,17 @@ if ($filename =~ m,^(.*)(\.\S),) { | |||
| 278 | my $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s"; | 328 | my $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s"; |
| 279 | my $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o"; | 329 | my $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o"; |
| 280 | 330 | ||
| 281 | # | 331 | check_objcopy(); |
| 282 | # --globalize-symbols came out in 2.17, we must test the version | ||
| 283 | # of objcopy, and if it is less than 2.17, then we can not | ||
| 284 | # record local functions. | ||
| 285 | my $use_locals = 01; | ||
| 286 | my $local_warn_once = 0; | ||
| 287 | my $found_version = 0; | ||
| 288 | |||
| 289 | open (IN, "$objcopy --version |") || die "error running $objcopy"; | ||
| 290 | while (<IN>) { | ||
| 291 | if (/objcopy.*\s(\d+)\.(\d+)/) { | ||
| 292 | my $major = $1; | ||
| 293 | my $minor = $2; | ||
| 294 | |||
| 295 | $found_version = 1; | ||
| 296 | if ($major < 2 || | ||
| 297 | ($major == 2 && $minor < 17)) { | ||
| 298 | $use_locals = 0; | ||
| 299 | } | ||
| 300 | last; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | close (IN); | ||
| 304 | |||
| 305 | if (!$found_version) { | ||
| 306 | print STDERR "WARNING: could not find objcopy version.\n" . | ||
| 307 | "\tDisabling local function references.\n"; | ||
| 308 | } | ||
| 309 | 332 | ||
| 310 | # | 333 | # |
| 311 | # Step 1: find all the local (static functions) and weak symbols. | 334 | # Step 1: find all the local (static functions) and weak symbols. |
| 312 | # 't' is local, 'w/W' is weak (we never use a weak function) | 335 | # 't' is local, 'w/W' is weak |
| 313 | # | 336 | # |
| 314 | open (IN, "$nm $inputfile|") || die "error running $nm"; | 337 | open (IN, "$nm $inputfile|") || die "error running $nm"; |
| 315 | while (<IN>) { | 338 | while (<IN>) { |
| 316 | if (/$nm_regex/) { | 339 | if (/$local_regex/) { |
| 317 | $locals{$1} = 1; | 340 | $locals{$1} = 1; |
| 318 | } elsif (/^[0-9a-fA-F]+\s+([wW])\s+(\S+)/) { | 341 | } elsif (/$weak_regex/) { |
| 319 | $weak{$2} = $1; | 342 | $weak{$2} = $1; |
| 320 | } | 343 | } |
| 321 | } | 344 | } |
| @@ -333,26 +356,20 @@ my $offset = 0; # offset of ref_func to section beginning | |||
| 333 | # | 356 | # |
| 334 | sub update_funcs | 357 | sub update_funcs |
| 335 | { | 358 | { |
| 336 | return if ($#offsets < 0); | 359 | return unless ($ref_func and @offsets); |
| 337 | |||
| 338 | defined($ref_func) || die "No function to reference"; | ||
| 339 | 360 | ||
| 340 | # A section only had a weak function, to represent it. | 361 | # Sanity check on weak function. A weak function may be overwritten by |
| 341 | # Unfortunately, a weak function may be overwritten by another | 362 | # another function of the same name, making all these offsets incorrect. |
| 342 | # function of the same name, making all these offsets incorrect. | ||
| 343 | # To be safe, we simply print a warning and bail. | ||
| 344 | if (defined $weak{$ref_func}) { | 363 | if (defined $weak{$ref_func}) { |
| 345 | print STDERR | 364 | die "$inputfile: ERROR: referencing weak function" . |
| 346 | "$inputfile: WARNING: referencing weak function" . | ||
| 347 | " $ref_func for mcount\n"; | 365 | " $ref_func for mcount\n"; |
| 348 | return; | ||
| 349 | } | 366 | } |
| 350 | 367 | ||
| 351 | # is this function static? If so, note this fact. | 368 | # is this function static? If so, note this fact. |
| 352 | if (defined $locals{$ref_func}) { | 369 | if (defined $locals{$ref_func}) { |
| 353 | 370 | ||
| 354 | # only use locals if objcopy supports globalize-symbols | 371 | # only use locals if objcopy supports globalize-symbols |
| 355 | if (!$use_locals) { | 372 | if (!$can_use_local) { |
| 356 | return; | 373 | return; |
| 357 | } | 374 | } |
| 358 | $convert{$ref_func} = 1; | 375 | $convert{$ref_func} = 1; |
| @@ -378,9 +395,27 @@ open(IN, "$objdump -hdr $inputfile|") || die "error running $objdump"; | |||
| 378 | 395 | ||
| 379 | my $text; | 396 | my $text; |
| 380 | 397 | ||
| 398 | |||
| 399 | # read headers first | ||
| 381 | my $read_headers = 1; | 400 | my $read_headers = 1; |
| 382 | 401 | ||
| 383 | while (<IN>) { | 402 | while (<IN>) { |
| 403 | |||
| 404 | if ($read_headers && /$mcount_section/) { | ||
| 405 | # | ||
| 406 | # Somehow the make process can execute this script on an | ||
| 407 | # object twice. If it does, we would duplicate the mcount | ||
| 408 | # section and it will cause the function tracer self test | ||
| 409 | # to fail. Check if the mcount section exists, and if it does, | ||
| 410 | # warn and exit. | ||
| 411 | # | ||
| 412 | print STDERR "ERROR: $mcount_section already in $inputfile\n" . | ||
| 413 | "\tThis may be an indication that your build is corrupted.\n" . | ||
| 414 | "\tDelete $inputfile and try again. If the same object file\n" . | ||
| 415 | "\tstill causes an issue, then disable CONFIG_DYNAMIC_FTRACE.\n"; | ||
| 416 | exit(-1); | ||
| 417 | } | ||
| 418 | |||
| 384 | # is it a section? | 419 | # is it a section? |
| 385 | if (/$section_regex/) { | 420 | if (/$section_regex/) { |
| 386 | $read_headers = 0; | 421 | $read_headers = 0; |
| @@ -392,7 +427,7 @@ while (<IN>) { | |||
| 392 | $read_function = 0; | 427 | $read_function = 0; |
| 393 | } | 428 | } |
| 394 | # print out any recorded offsets | 429 | # print out any recorded offsets |
| 395 | update_funcs() if (defined($ref_func)); | 430 | update_funcs(); |
| 396 | 431 | ||
| 397 | # reset all markers and arrays | 432 | # reset all markers and arrays |
| 398 | $text_found = 0; | 433 | $text_found = 0; |
| @@ -421,21 +456,7 @@ while (<IN>) { | |||
| 421 | $offset = hex $1; | 456 | $offset = hex $1; |
| 422 | } | 457 | } |
| 423 | } | 458 | } |
| 424 | } elsif ($read_headers && /$mcount_section/) { | ||
| 425 | # | ||
| 426 | # Somehow the make process can execute this script on an | ||
| 427 | # object twice. If it does, we would duplicate the mcount | ||
| 428 | # section and it will cause the function tracer self test | ||
| 429 | # to fail. Check if the mcount section exists, and if it does, | ||
| 430 | # warn and exit. | ||
| 431 | # | ||
| 432 | print STDERR "ERROR: $mcount_section already in $inputfile\n" . | ||
| 433 | "\tThis may be an indication that your build is corrupted.\n" . | ||
| 434 | "\tDelete $inputfile and try again. If the same object file\n" . | ||
| 435 | "\tstill causes an issue, then disable CONFIG_DYNAMIC_FTRACE.\n"; | ||
| 436 | exit(-1); | ||
| 437 | } | 459 | } |
| 438 | |||
| 439 | # is this a call site to mcount? If so, record it to print later | 460 | # is this a call site to mcount? If so, record it to print later |
| 440 | if ($text_found && /$mcount_regex/) { | 461 | if ($text_found && /$mcount_regex/) { |
| 441 | $offsets[$#offsets + 1] = hex $1; | 462 | $offsets[$#offsets + 1] = hex $1; |
| @@ -443,7 +464,7 @@ while (<IN>) { | |||
| 443 | } | 464 | } |
| 444 | 465 | ||
| 445 | # dump out anymore offsets that may have been found | 466 | # dump out anymore offsets that may have been found |
| 446 | update_funcs() if (defined($ref_func)); | 467 | update_funcs(); |
| 447 | 468 | ||
| 448 | # If we did not find any mcount callers, we are done (do nothing). | 469 | # If we did not find any mcount callers, we are done (do nothing). |
| 449 | if (!$opened) { | 470 | if (!$opened) { |
