diff options
34 files changed, 359 insertions, 106 deletions
diff --git a/arch/blackfin/mm/maccess.c b/arch/blackfin/mm/maccess.c index b71cebc1f8a3..e2532114c5fd 100644 --- a/arch/blackfin/mm/maccess.c +++ b/arch/blackfin/mm/maccess.c | |||
| @@ -16,7 +16,7 @@ static int validate_memory_access_address(unsigned long addr, int size) | |||
| 16 | return bfin_mem_access_type(addr, size); | 16 | return bfin_mem_access_type(addr, size); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | long probe_kernel_read(void *dst, void *src, size_t size) | 19 | long probe_kernel_read(void *dst, const void *src, size_t size) |
| 20 | { | 20 | { |
| 21 | unsigned long lsrc = (unsigned long)src; | 21 | unsigned long lsrc = (unsigned long)src; |
| 22 | int mem_type; | 22 | int mem_type; |
| @@ -55,7 +55,7 @@ long probe_kernel_read(void *dst, void *src, size_t size) | |||
| 55 | return -EFAULT; | 55 | return -EFAULT; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | long probe_kernel_write(void *dst, void *src, size_t size) | 58 | long probe_kernel_write(void *dst, const void *src, size_t size) |
| 59 | { | 59 | { |
| 60 | unsigned long ldst = (unsigned long)dst; | 60 | unsigned long ldst = (unsigned long)dst; |
| 61 | int mem_type; | 61 | int mem_type; |
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index 71a4b0d34be0..51e5cd9b906a 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | * using the stura instruction. | 19 | * using the stura instruction. |
| 20 | * Returns the number of bytes copied or -EFAULT. | 20 | * Returns the number of bytes copied or -EFAULT. |
| 21 | */ | 21 | */ |
| 22 | static long probe_kernel_write_odd(void *dst, void *src, size_t size) | 22 | static long probe_kernel_write_odd(void *dst, const void *src, size_t size) |
| 23 | { | 23 | { |
| 24 | unsigned long count, aligned; | 24 | unsigned long count, aligned; |
| 25 | int offset, mask; | 25 | int offset, mask; |
| @@ -45,7 +45,7 @@ static long probe_kernel_write_odd(void *dst, void *src, size_t size) | |||
| 45 | return rc ? rc : count; | 45 | return rc ? rc : count; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | long probe_kernel_write(void *dst, void *src, size_t size) | 48 | long probe_kernel_write(void *dst, const void *src, size_t size) |
| 49 | { | 49 | { |
| 50 | long copied = 0; | 50 | long copied = 0; |
| 51 | 51 | ||
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 0ba15a6cc57e..c9a281f272fd 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
| @@ -123,7 +123,7 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | |||
| 123 | static atomic_t nmi_running = ATOMIC_INIT(0); | 123 | static atomic_t nmi_running = ATOMIC_INIT(0); |
| 124 | static int mod_code_status; /* holds return value of text write */ | 124 | static int mod_code_status; /* holds return value of text write */ |
| 125 | static void *mod_code_ip; /* holds the IP to write to */ | 125 | static void *mod_code_ip; /* holds the IP to write to */ |
| 126 | static void *mod_code_newcode; /* holds the text to write to the IP */ | 126 | static const void *mod_code_newcode; /* holds the text to write to the IP */ |
| 127 | 127 | ||
| 128 | static unsigned nmi_wait_count; | 128 | static unsigned nmi_wait_count; |
| 129 | static atomic_t nmi_update_count = ATOMIC_INIT(0); | 129 | static atomic_t nmi_update_count = ATOMIC_INIT(0); |
| @@ -225,7 +225,7 @@ within(unsigned long addr, unsigned long start, unsigned long end) | |||
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | static int | 227 | static int |
| 228 | do_ftrace_mod_code(unsigned long ip, void *new_code) | 228 | do_ftrace_mod_code(unsigned long ip, const void *new_code) |
| 229 | { | 229 | { |
| 230 | /* | 230 | /* |
| 231 | * On x86_64, kernel text mappings are mapped read-only with | 231 | * On x86_64, kernel text mappings are mapped read-only with |
| @@ -266,8 +266,8 @@ static const unsigned char *ftrace_nop_replace(void) | |||
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | static int | 268 | static int |
| 269 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, | 269 | ftrace_modify_code(unsigned long ip, unsigned const char *old_code, |
| 270 | unsigned char *new_code) | 270 | unsigned const char *new_code) |
| 271 | { | 271 | { |
| 272 | unsigned char replaced[MCOUNT_INSN_SIZE]; | 272 | unsigned char replaced[MCOUNT_INSN_SIZE]; |
| 273 | 273 | ||
| @@ -301,7 +301,7 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, | |||
| 301 | int ftrace_make_nop(struct module *mod, | 301 | int ftrace_make_nop(struct module *mod, |
| 302 | struct dyn_ftrace *rec, unsigned long addr) | 302 | struct dyn_ftrace *rec, unsigned long addr) |
| 303 | { | 303 | { |
| 304 | unsigned char *new, *old; | 304 | unsigned const char *new, *old; |
| 305 | unsigned long ip = rec->ip; | 305 | unsigned long ip = rec->ip; |
| 306 | 306 | ||
| 307 | old = ftrace_call_replace(ip, addr); | 307 | old = ftrace_call_replace(ip, addr); |
| @@ -312,7 +312,7 @@ int ftrace_make_nop(struct module *mod, | |||
| 312 | 312 | ||
| 313 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | 313 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) |
| 314 | { | 314 | { |
| 315 | unsigned char *new, *old; | 315 | unsigned const char *new, *old; |
| 316 | unsigned long ip = rec->ip; | 316 | unsigned long ip = rec->ip; |
| 317 | 317 | ||
| 318 | old = ftrace_nop_replace(); | 318 | old = ftrace_nop_replace(); |
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index c3b8e24f2b16..9fd8a567fe1e 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c | |||
| @@ -316,16 +316,23 @@ static void op_amd_stop_ibs(void) | |||
| 316 | wrmsrl(MSR_AMD64_IBSOPCTL, 0); | 316 | wrmsrl(MSR_AMD64_IBSOPCTL, 0); |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | static inline int eilvt_is_available(int offset) | 319 | static inline int get_eilvt(int offset) |
| 320 | { | 320 | { |
| 321 | /* check if we may assign a vector */ | ||
| 322 | return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1); | 321 | return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1); |
| 323 | } | 322 | } |
| 324 | 323 | ||
| 324 | static inline int put_eilvt(int offset) | ||
| 325 | { | ||
| 326 | return !setup_APIC_eilvt(offset, 0, 0, 1); | ||
| 327 | } | ||
| 328 | |||
| 325 | static inline int ibs_eilvt_valid(void) | 329 | static inline int ibs_eilvt_valid(void) |
| 326 | { | 330 | { |
| 327 | int offset; | 331 | int offset; |
| 328 | u64 val; | 332 | u64 val; |
| 333 | int valid = 0; | ||
| 334 | |||
| 335 | preempt_disable(); | ||
| 329 | 336 | ||
| 330 | rdmsrl(MSR_AMD64_IBSCTL, val); | 337 | rdmsrl(MSR_AMD64_IBSCTL, val); |
| 331 | offset = val & IBSCTL_LVT_OFFSET_MASK; | 338 | offset = val & IBSCTL_LVT_OFFSET_MASK; |
| @@ -333,16 +340,20 @@ static inline int ibs_eilvt_valid(void) | |||
| 333 | if (!(val & IBSCTL_LVT_OFFSET_VALID)) { | 340 | if (!(val & IBSCTL_LVT_OFFSET_VALID)) { |
| 334 | pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n", | 341 | pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n", |
| 335 | smp_processor_id(), offset, MSR_AMD64_IBSCTL, val); | 342 | smp_processor_id(), offset, MSR_AMD64_IBSCTL, val); |
| 336 | return 0; | 343 | goto out; |
| 337 | } | 344 | } |
| 338 | 345 | ||
| 339 | if (!eilvt_is_available(offset)) { | 346 | if (!get_eilvt(offset)) { |
| 340 | pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n", | 347 | pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n", |
| 341 | smp_processor_id(), offset, MSR_AMD64_IBSCTL, val); | 348 | smp_processor_id(), offset, MSR_AMD64_IBSCTL, val); |
| 342 | return 0; | 349 | goto out; |
| 343 | } | 350 | } |
| 344 | 351 | ||
| 345 | return 1; | 352 | valid = 1; |
| 353 | out: | ||
| 354 | preempt_enable(); | ||
| 355 | |||
| 356 | return valid; | ||
| 346 | } | 357 | } |
| 347 | 358 | ||
| 348 | static inline int get_ibs_offset(void) | 359 | static inline int get_ibs_offset(void) |
| @@ -600,67 +611,69 @@ static int setup_ibs_ctl(int ibs_eilvt_off) | |||
| 600 | 611 | ||
| 601 | static int force_ibs_eilvt_setup(void) | 612 | static int force_ibs_eilvt_setup(void) |
| 602 | { | 613 | { |
| 603 | int i; | 614 | int offset; |
| 604 | int ret; | 615 | int ret; |
| 605 | 616 | ||
| 606 | /* find the next free available EILVT entry */ | 617 | /* |
| 607 | for (i = 1; i < 4; i++) { | 618 | * find the next free available EILVT entry, skip offset 0, |
| 608 | if (!eilvt_is_available(i)) | 619 | * pin search to this cpu |
| 609 | continue; | 620 | */ |
| 610 | ret = setup_ibs_ctl(i); | 621 | preempt_disable(); |
| 611 | if (ret) | 622 | for (offset = 1; offset < APIC_EILVT_NR_MAX; offset++) { |
| 612 | return ret; | 623 | if (get_eilvt(offset)) |
| 613 | pr_err(FW_BUG "using offset %d for IBS interrupts\n", i); | 624 | break; |
| 614 | return 0; | ||
| 615 | } | 625 | } |
| 626 | preempt_enable(); | ||
| 616 | 627 | ||
| 617 | printk(KERN_DEBUG "No EILVT entry available\n"); | 628 | if (offset == APIC_EILVT_NR_MAX) { |
| 618 | 629 | printk(KERN_DEBUG "No EILVT entry available\n"); | |
| 619 | return -EBUSY; | 630 | return -EBUSY; |
| 620 | } | 631 | } |
| 621 | |||
| 622 | static int __init_ibs_nmi(void) | ||
| 623 | { | ||
| 624 | int ret; | ||
| 625 | |||
| 626 | if (ibs_eilvt_valid()) | ||
| 627 | return 0; | ||
| 628 | 632 | ||
| 629 | ret = force_ibs_eilvt_setup(); | 633 | ret = setup_ibs_ctl(offset); |
| 630 | if (ret) | 634 | if (ret) |
| 631 | return ret; | 635 | goto out; |
| 632 | 636 | ||
| 633 | if (!ibs_eilvt_valid()) | 637 | if (!ibs_eilvt_valid()) { |
| 634 | return -EFAULT; | 638 | ret = -EFAULT; |
| 639 | goto out; | ||
| 640 | } | ||
| 635 | 641 | ||
| 642 | pr_err(FW_BUG "using offset %d for IBS interrupts\n", offset); | ||
| 636 | pr_err(FW_BUG "workaround enabled for IBS LVT offset\n"); | 643 | pr_err(FW_BUG "workaround enabled for IBS LVT offset\n"); |
| 637 | 644 | ||
| 638 | return 0; | 645 | return 0; |
| 646 | out: | ||
| 647 | preempt_disable(); | ||
| 648 | put_eilvt(offset); | ||
| 649 | preempt_enable(); | ||
| 650 | return ret; | ||
| 639 | } | 651 | } |
| 640 | 652 | ||
| 641 | /* | 653 | /* |
| 642 | * check and reserve APIC extended interrupt LVT offset for IBS if | 654 | * check and reserve APIC extended interrupt LVT offset for IBS if |
| 643 | * available | 655 | * available |
| 644 | * | ||
| 645 | * init_ibs() preforms implicitly cpu-local operations, so pin this | ||
| 646 | * thread to its current CPU | ||
| 647 | */ | 656 | */ |
| 648 | 657 | ||
| 649 | static void init_ibs(void) | 658 | static void init_ibs(void) |
| 650 | { | 659 | { |
| 651 | preempt_disable(); | ||
| 652 | |||
| 653 | ibs_caps = get_ibs_caps(); | 660 | ibs_caps = get_ibs_caps(); |
| 661 | |||
| 654 | if (!ibs_caps) | 662 | if (!ibs_caps) |
| 663 | return; | ||
| 664 | |||
| 665 | if (ibs_eilvt_valid()) | ||
| 655 | goto out; | 666 | goto out; |
| 656 | 667 | ||
| 657 | if (__init_ibs_nmi() < 0) | 668 | if (!force_ibs_eilvt_setup()) |
| 658 | ibs_caps = 0; | 669 | goto out; |
| 659 | else | 670 | |
| 660 | printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps); | 671 | /* Failed to setup ibs */ |
| 672 | ibs_caps = 0; | ||
| 673 | return; | ||
| 661 | 674 | ||
| 662 | out: | 675 | out: |
| 663 | preempt_enable(); | 676 | printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps); |
| 664 | } | 677 | } |
| 665 | 678 | ||
| 666 | static int (*create_arch_files)(struct super_block *sb, struct dentry *root); | 679 | static int (*create_arch_files)(struct super_block *sb, struct dentry *root); |
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h index 4e70749f8d16..a8d5bb3cba89 100644 --- a/drivers/oprofile/event_buffer.h +++ b/drivers/oprofile/event_buffer.h | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #define EVENT_BUFFER_H | 11 | #define EVENT_BUFFER_H |
| 12 | 12 | ||
| 13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 14 | #include <asm/mutex.h> | 14 | #include <linux/mutex.h> |
| 15 | 15 | ||
| 16 | int alloc_event_buffer(void); | 16 | int alloc_event_buffer(void); |
| 17 | 17 | ||
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index f9bda64fcd1b..dccd8636095c 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | #include <linux/moduleparam.h> | 14 | #include <linux/moduleparam.h> |
| 15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
| 16 | #include <linux/time.h> | 16 | #include <linux/time.h> |
| 17 | #include <asm/mutex.h> | 17 | #include <linux/mutex.h> |
| 18 | 18 | ||
| 19 | #include "oprof.h" | 19 | #include "oprof.h" |
| 20 | #include "event_buffer.h" | 20 | #include "event_buffer.h" |
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index b5a550a39a70..59d3ef100eb9 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
| @@ -16,6 +16,11 @@ struct trace_print_flags { | |||
| 16 | const char *name; | 16 | const char *name; |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | struct trace_print_flags_u64 { | ||
| 20 | unsigned long long mask; | ||
| 21 | const char *name; | ||
| 22 | }; | ||
| 23 | |||
| 19 | const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim, | 24 | const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim, |
| 20 | unsigned long flags, | 25 | unsigned long flags, |
| 21 | const struct trace_print_flags *flag_array); | 26 | const struct trace_print_flags *flag_array); |
| @@ -23,6 +28,13 @@ const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim, | |||
| 23 | const char *ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val, | 28 | const char *ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val, |
| 24 | const struct trace_print_flags *symbol_array); | 29 | const struct trace_print_flags *symbol_array); |
| 25 | 30 | ||
| 31 | #if BITS_PER_LONG == 32 | ||
| 32 | const char *ftrace_print_symbols_seq_u64(struct trace_seq *p, | ||
| 33 | unsigned long long val, | ||
| 34 | const struct trace_print_flags_u64 | ||
| 35 | *symbol_array); | ||
| 36 | #endif | ||
| 37 | |||
| 26 | const char *ftrace_print_hex_seq(struct trace_seq *p, | 38 | const char *ftrace_print_hex_seq(struct trace_seq *p, |
| 27 | const unsigned char *buf, int len); | 39 | const unsigned char *buf, int len); |
| 28 | 40 | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index dc8871295a5a..8f441d1c6550 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1546,7 +1546,7 @@ struct task_struct { | |||
| 1546 | #ifdef CONFIG_TRACING | 1546 | #ifdef CONFIG_TRACING |
| 1547 | /* state flags for use by tracers */ | 1547 | /* state flags for use by tracers */ |
| 1548 | unsigned long trace; | 1548 | unsigned long trace; |
| 1549 | /* bitmask of trace recursion */ | 1549 | /* bitmask and counter of trace recursion */ |
| 1550 | unsigned long trace_recursion; | 1550 | unsigned long trace_recursion; |
| 1551 | #endif /* CONFIG_TRACING */ | 1551 | #endif /* CONFIG_TRACING */ |
| 1552 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR /* memcg uses this to do batch job */ | 1552 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR /* memcg uses this to do batch job */ |
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index d512d98dfb7d..5ca0951e1855 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h | |||
| @@ -93,8 +93,8 @@ static inline unsigned long __copy_from_user_nocache(void *to, | |||
| 93 | * Safely read from address @src to the buffer at @dst. If a kernel fault | 93 | * Safely read from address @src to the buffer at @dst. If a kernel fault |
| 94 | * happens, handle that and return -EFAULT. | 94 | * happens, handle that and return -EFAULT. |
| 95 | */ | 95 | */ |
| 96 | extern long probe_kernel_read(void *dst, void *src, size_t size); | 96 | extern long probe_kernel_read(void *dst, const void *src, size_t size); |
| 97 | extern long __probe_kernel_read(void *dst, void *src, size_t size); | 97 | extern long __probe_kernel_read(void *dst, const void *src, size_t size); |
| 98 | 98 | ||
| 99 | /* | 99 | /* |
| 100 | * probe_kernel_write(): safely attempt to write to a location | 100 | * probe_kernel_write(): safely attempt to write to a location |
| @@ -105,7 +105,7 @@ extern long __probe_kernel_read(void *dst, void *src, size_t size); | |||
| 105 | * Safely write to address @dst from the buffer at @src. If a kernel fault | 105 | * Safely write to address @dst from the buffer at @src. If a kernel fault |
| 106 | * happens, handle that and return -EFAULT. | 106 | * happens, handle that and return -EFAULT. |
| 107 | */ | 107 | */ |
| 108 | extern long notrace probe_kernel_write(void *dst, void *src, size_t size); | 108 | extern long notrace probe_kernel_write(void *dst, const void *src, size_t size); |
| 109 | extern long notrace __probe_kernel_write(void *dst, void *src, size_t size); | 109 | extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size); |
| 110 | 110 | ||
| 111 | #endif /* __LINUX_UACCESS_H__ */ | 111 | #endif /* __LINUX_UACCESS_H__ */ |
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index f445cff66ab7..4114129f0794 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h | |||
| @@ -28,7 +28,7 @@ struct extent_buffer; | |||
| 28 | { BTRFS_SHARED_DATA_REF_KEY, "SHARED_DATA_REF" }) | 28 | { BTRFS_SHARED_DATA_REF_KEY, "SHARED_DATA_REF" }) |
| 29 | 29 | ||
| 30 | #define __show_root_type(obj) \ | 30 | #define __show_root_type(obj) \ |
| 31 | __print_symbolic(obj, \ | 31 | __print_symbolic_u64(obj, \ |
| 32 | { BTRFS_ROOT_TREE_OBJECTID, "ROOT_TREE" }, \ | 32 | { BTRFS_ROOT_TREE_OBJECTID, "ROOT_TREE" }, \ |
| 33 | { BTRFS_EXTENT_TREE_OBJECTID, "EXTENT_TREE" }, \ | 33 | { BTRFS_EXTENT_TREE_OBJECTID, "EXTENT_TREE" }, \ |
| 34 | { BTRFS_CHUNK_TREE_OBJECTID, "CHUNK_TREE" }, \ | 34 | { BTRFS_CHUNK_TREE_OBJECTID, "CHUNK_TREE" }, \ |
| @@ -125,7 +125,7 @@ DEFINE_EVENT(btrfs__inode, btrfs_inode_evict, | |||
| 125 | ); | 125 | ); |
| 126 | 126 | ||
| 127 | #define __show_map_type(type) \ | 127 | #define __show_map_type(type) \ |
| 128 | __print_symbolic(type, \ | 128 | __print_symbolic_u64(type, \ |
| 129 | { EXTENT_MAP_LAST_BYTE, "LAST_BYTE" }, \ | 129 | { EXTENT_MAP_LAST_BYTE, "LAST_BYTE" }, \ |
| 130 | { EXTENT_MAP_HOLE, "HOLE" }, \ | 130 | { EXTENT_MAP_HOLE, "HOLE" }, \ |
| 131 | { EXTENT_MAP_INLINE, "INLINE" }, \ | 131 | { EXTENT_MAP_INLINE, "INLINE" }, \ |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 3e68366d485a..533c49f48047 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
| @@ -205,6 +205,19 @@ | |||
| 205 | ftrace_print_symbols_seq(p, value, symbols); \ | 205 | ftrace_print_symbols_seq(p, value, symbols); \ |
| 206 | }) | 206 | }) |
| 207 | 207 | ||
| 208 | #undef __print_symbolic_u64 | ||
| 209 | #if BITS_PER_LONG == 32 | ||
| 210 | #define __print_symbolic_u64(value, symbol_array...) \ | ||
| 211 | ({ \ | ||
| 212 | static const struct trace_print_flags_u64 symbols[] = \ | ||
| 213 | { symbol_array, { -1, NULL } }; \ | ||
| 214 | ftrace_print_symbols_seq_u64(p, value, symbols); \ | ||
| 215 | }) | ||
| 216 | #else | ||
| 217 | #define __print_symbolic_u64(value, symbol_array...) \ | ||
| 218 | __print_symbolic(value, symbol_array) | ||
| 219 | #endif | ||
| 220 | |||
| 208 | #undef __print_hex | 221 | #undef __print_hex |
| 209 | #define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len) | 222 | #define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len) |
| 210 | 223 | ||
diff --git a/kernel/events/core.c b/kernel/events/core.c index c09767f7db3e..d863b3c057bb 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
| @@ -5028,6 +5028,14 @@ static int __perf_event_overflow(struct perf_event *event, int nmi, | |||
| 5028 | else | 5028 | else |
| 5029 | perf_event_output(event, nmi, data, regs); | 5029 | perf_event_output(event, nmi, data, regs); |
| 5030 | 5030 | ||
| 5031 | if (event->fasync && event->pending_kill) { | ||
| 5032 | if (nmi) { | ||
| 5033 | event->pending_wakeup = 1; | ||
| 5034 | irq_work_queue(&event->pending); | ||
| 5035 | } else | ||
| 5036 | perf_event_wakeup(event); | ||
| 5037 | } | ||
| 5038 | |||
| 5031 | return ret; | 5039 | return ret; |
| 5032 | } | 5040 | } |
| 5033 | 5041 | ||
diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 74d1c099fbd1..fa27e750dbc0 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c | |||
| @@ -105,9 +105,12 @@ static int __jump_label_text_reserved(struct jump_entry *iter_start, | |||
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | static void __jump_label_update(struct jump_label_key *key, | 107 | static void __jump_label_update(struct jump_label_key *key, |
| 108 | struct jump_entry *entry, int enable) | 108 | struct jump_entry *entry, |
| 109 | struct jump_entry *stop, int enable) | ||
| 109 | { | 110 | { |
| 110 | for (; entry->key == (jump_label_t)(unsigned long)key; entry++) { | 111 | for (; (entry < stop) && |
| 112 | (entry->key == (jump_label_t)(unsigned long)key); | ||
| 113 | entry++) { | ||
| 111 | /* | 114 | /* |
| 112 | * entry->code set to 0 invalidates module init text sections | 115 | * entry->code set to 0 invalidates module init text sections |
| 113 | * kernel_text_address() verifies we are not in core kernel | 116 | * kernel_text_address() verifies we are not in core kernel |
| @@ -181,7 +184,11 @@ static void __jump_label_mod_update(struct jump_label_key *key, int enable) | |||
| 181 | struct jump_label_mod *mod = key->next; | 184 | struct jump_label_mod *mod = key->next; |
| 182 | 185 | ||
| 183 | while (mod) { | 186 | while (mod) { |
| 184 | __jump_label_update(key, mod->entries, enable); | 187 | struct module *m = mod->mod; |
| 188 | |||
| 189 | __jump_label_update(key, mod->entries, | ||
| 190 | m->jump_entries + m->num_jump_entries, | ||
| 191 | enable); | ||
| 185 | mod = mod->next; | 192 | mod = mod->next; |
| 186 | } | 193 | } |
| 187 | } | 194 | } |
| @@ -245,7 +252,8 @@ static int jump_label_add_module(struct module *mod) | |||
| 245 | key->next = jlm; | 252 | key->next = jlm; |
| 246 | 253 | ||
| 247 | if (jump_label_enabled(key)) | 254 | if (jump_label_enabled(key)) |
| 248 | __jump_label_update(key, iter, JUMP_LABEL_ENABLE); | 255 | __jump_label_update(key, iter, iter_stop, |
| 256 | JUMP_LABEL_ENABLE); | ||
| 249 | } | 257 | } |
| 250 | 258 | ||
| 251 | return 0; | 259 | return 0; |
| @@ -371,7 +379,7 @@ static void jump_label_update(struct jump_label_key *key, int enable) | |||
| 371 | 379 | ||
| 372 | /* if there are no users, entry can be NULL */ | 380 | /* if there are no users, entry can be NULL */ |
| 373 | if (entry) | 381 | if (entry) |
| 374 | __jump_label_update(key, entry, enable); | 382 | __jump_label_update(key, entry, __stop___jump_table, enable); |
| 375 | 383 | ||
| 376 | #ifdef CONFIG_MODULES | 384 | #ifdef CONFIG_MODULES |
| 377 | __jump_label_mod_update(key, enable); | 385 | __jump_label_mod_update(key, enable); |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index d017c2c82c44..1ee417fcbfa5 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -109,12 +109,18 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip); | |||
| 109 | static void ftrace_global_list_func(unsigned long ip, | 109 | static void ftrace_global_list_func(unsigned long ip, |
| 110 | unsigned long parent_ip) | 110 | unsigned long parent_ip) |
| 111 | { | 111 | { |
| 112 | struct ftrace_ops *op = rcu_dereference_raw(ftrace_global_list); /*see above*/ | 112 | struct ftrace_ops *op; |
| 113 | |||
| 114 | if (unlikely(trace_recursion_test(TRACE_GLOBAL_BIT))) | ||
| 115 | return; | ||
| 113 | 116 | ||
| 117 | trace_recursion_set(TRACE_GLOBAL_BIT); | ||
| 118 | op = rcu_dereference_raw(ftrace_global_list); /*see above*/ | ||
| 114 | while (op != &ftrace_list_end) { | 119 | while (op != &ftrace_list_end) { |
| 115 | op->func(ip, parent_ip); | 120 | op->func(ip, parent_ip); |
| 116 | op = rcu_dereference_raw(op->next); /*see above*/ | 121 | op = rcu_dereference_raw(op->next); /*see above*/ |
| 117 | }; | 122 | }; |
| 123 | trace_recursion_clear(TRACE_GLOBAL_BIT); | ||
| 118 | } | 124 | } |
| 119 | 125 | ||
| 120 | static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip) | 126 | static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip) |
| @@ -1638,12 +1644,12 @@ static void ftrace_startup_enable(int command) | |||
| 1638 | ftrace_run_update_code(command); | 1644 | ftrace_run_update_code(command); |
| 1639 | } | 1645 | } |
| 1640 | 1646 | ||
| 1641 | static void ftrace_startup(struct ftrace_ops *ops, int command) | 1647 | static int ftrace_startup(struct ftrace_ops *ops, int command) |
| 1642 | { | 1648 | { |
| 1643 | bool hash_enable = true; | 1649 | bool hash_enable = true; |
| 1644 | 1650 | ||
| 1645 | if (unlikely(ftrace_disabled)) | 1651 | if (unlikely(ftrace_disabled)) |
| 1646 | return; | 1652 | return -ENODEV; |
| 1647 | 1653 | ||
| 1648 | ftrace_start_up++; | 1654 | ftrace_start_up++; |
| 1649 | command |= FTRACE_ENABLE_CALLS; | 1655 | command |= FTRACE_ENABLE_CALLS; |
| @@ -1662,6 +1668,8 @@ static void ftrace_startup(struct ftrace_ops *ops, int command) | |||
| 1662 | ftrace_hash_rec_enable(ops, 1); | 1668 | ftrace_hash_rec_enable(ops, 1); |
| 1663 | 1669 | ||
| 1664 | ftrace_startup_enable(command); | 1670 | ftrace_startup_enable(command); |
| 1671 | |||
| 1672 | return 0; | ||
| 1665 | } | 1673 | } |
| 1666 | 1674 | ||
| 1667 | static void ftrace_shutdown(struct ftrace_ops *ops, int command) | 1675 | static void ftrace_shutdown(struct ftrace_ops *ops, int command) |
| @@ -2501,7 +2509,7 @@ static void __enable_ftrace_function_probe(void) | |||
| 2501 | 2509 | ||
| 2502 | ret = __register_ftrace_function(&trace_probe_ops); | 2510 | ret = __register_ftrace_function(&trace_probe_ops); |
| 2503 | if (!ret) | 2511 | if (!ret) |
| 2504 | ftrace_startup(&trace_probe_ops, 0); | 2512 | ret = ftrace_startup(&trace_probe_ops, 0); |
| 2505 | 2513 | ||
| 2506 | ftrace_probe_registered = 1; | 2514 | ftrace_probe_registered = 1; |
| 2507 | } | 2515 | } |
| @@ -3466,7 +3474,11 @@ device_initcall(ftrace_nodyn_init); | |||
| 3466 | static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; } | 3474 | static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; } |
| 3467 | static inline void ftrace_startup_enable(int command) { } | 3475 | static inline void ftrace_startup_enable(int command) { } |
| 3468 | /* Keep as macros so we do not need to define the commands */ | 3476 | /* Keep as macros so we do not need to define the commands */ |
| 3469 | # define ftrace_startup(ops, command) do { } while (0) | 3477 | # define ftrace_startup(ops, command) \ |
| 3478 | ({ \ | ||
| 3479 | (ops)->flags |= FTRACE_OPS_FL_ENABLED; \ | ||
| 3480 | 0; \ | ||
| 3481 | }) | ||
| 3470 | # define ftrace_shutdown(ops, command) do { } while (0) | 3482 | # define ftrace_shutdown(ops, command) do { } while (0) |
| 3471 | # define ftrace_startup_sysctl() do { } while (0) | 3483 | # define ftrace_startup_sysctl() do { } while (0) |
| 3472 | # define ftrace_shutdown_sysctl() do { } while (0) | 3484 | # define ftrace_shutdown_sysctl() do { } while (0) |
| @@ -3484,6 +3496,10 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip) | |||
| 3484 | { | 3496 | { |
| 3485 | struct ftrace_ops *op; | 3497 | struct ftrace_ops *op; |
| 3486 | 3498 | ||
| 3499 | if (unlikely(trace_recursion_test(TRACE_INTERNAL_BIT))) | ||
| 3500 | return; | ||
| 3501 | |||
| 3502 | trace_recursion_set(TRACE_INTERNAL_BIT); | ||
| 3487 | /* | 3503 | /* |
| 3488 | * Some of the ops may be dynamically allocated, | 3504 | * Some of the ops may be dynamically allocated, |
| 3489 | * they must be freed after a synchronize_sched(). | 3505 | * they must be freed after a synchronize_sched(). |
| @@ -3496,6 +3512,7 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip) | |||
| 3496 | op = rcu_dereference_raw(op->next); | 3512 | op = rcu_dereference_raw(op->next); |
| 3497 | }; | 3513 | }; |
| 3498 | preempt_enable_notrace(); | 3514 | preempt_enable_notrace(); |
| 3515 | trace_recursion_clear(TRACE_INTERNAL_BIT); | ||
| 3499 | } | 3516 | } |
| 3500 | 3517 | ||
| 3501 | static void clear_ftrace_swapper(void) | 3518 | static void clear_ftrace_swapper(void) |
| @@ -3799,7 +3816,7 @@ int register_ftrace_function(struct ftrace_ops *ops) | |||
| 3799 | 3816 | ||
| 3800 | ret = __register_ftrace_function(ops); | 3817 | ret = __register_ftrace_function(ops); |
| 3801 | if (!ret) | 3818 | if (!ret) |
| 3802 | ftrace_startup(ops, 0); | 3819 | ret = ftrace_startup(ops, 0); |
| 3803 | 3820 | ||
| 3804 | 3821 | ||
| 3805 | out_unlock: | 3822 | out_unlock: |
| @@ -4045,7 +4062,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, | |||
| 4045 | ftrace_graph_return = retfunc; | 4062 | ftrace_graph_return = retfunc; |
| 4046 | ftrace_graph_entry = entryfunc; | 4063 | ftrace_graph_entry = entryfunc; |
| 4047 | 4064 | ||
| 4048 | ftrace_startup(&global_ops, FTRACE_START_FUNC_RET); | 4065 | ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET); |
| 4049 | 4066 | ||
| 4050 | out: | 4067 | out: |
| 4051 | mutex_unlock(&ftrace_lock); | 4068 | mutex_unlock(&ftrace_lock); |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 0ef7b4b2a1f7..b0c7aa407943 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
| @@ -2216,7 +2216,7 @@ static noinline void trace_recursive_fail(void) | |||
| 2216 | 2216 | ||
| 2217 | printk_once(KERN_WARNING "Tracing recursion: depth[%ld]:" | 2217 | printk_once(KERN_WARNING "Tracing recursion: depth[%ld]:" |
| 2218 | "HC[%lu]:SC[%lu]:NMI[%lu]\n", | 2218 | "HC[%lu]:SC[%lu]:NMI[%lu]\n", |
| 2219 | current->trace_recursion, | 2219 | trace_recursion_buffer(), |
| 2220 | hardirq_count() >> HARDIRQ_SHIFT, | 2220 | hardirq_count() >> HARDIRQ_SHIFT, |
| 2221 | softirq_count() >> SOFTIRQ_SHIFT, | 2221 | softirq_count() >> SOFTIRQ_SHIFT, |
| 2222 | in_nmi()); | 2222 | in_nmi()); |
| @@ -2226,9 +2226,9 @@ static noinline void trace_recursive_fail(void) | |||
| 2226 | 2226 | ||
| 2227 | static inline int trace_recursive_lock(void) | 2227 | static inline int trace_recursive_lock(void) |
| 2228 | { | 2228 | { |
| 2229 | current->trace_recursion++; | 2229 | trace_recursion_inc(); |
| 2230 | 2230 | ||
| 2231 | if (likely(current->trace_recursion < TRACE_RECURSIVE_DEPTH)) | 2231 | if (likely(trace_recursion_buffer() < TRACE_RECURSIVE_DEPTH)) |
| 2232 | return 0; | 2232 | return 0; |
| 2233 | 2233 | ||
| 2234 | trace_recursive_fail(); | 2234 | trace_recursive_fail(); |
| @@ -2238,9 +2238,9 @@ static inline int trace_recursive_lock(void) | |||
| 2238 | 2238 | ||
| 2239 | static inline void trace_recursive_unlock(void) | 2239 | static inline void trace_recursive_unlock(void) |
| 2240 | { | 2240 | { |
| 2241 | WARN_ON_ONCE(!current->trace_recursion); | 2241 | WARN_ON_ONCE(!trace_recursion_buffer()); |
| 2242 | 2242 | ||
| 2243 | current->trace_recursion--; | 2243 | trace_recursion_dec(); |
| 2244 | } | 2244 | } |
| 2245 | 2245 | ||
| 2246 | #else | 2246 | #else |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 6b69c4bd306f..229f8591f61d 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -784,4 +784,19 @@ extern const char *__stop___trace_bprintk_fmt[]; | |||
| 784 | FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print)) | 784 | FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print)) |
| 785 | #include "trace_entries.h" | 785 | #include "trace_entries.h" |
| 786 | 786 | ||
| 787 | /* Only current can touch trace_recursion */ | ||
| 788 | #define trace_recursion_inc() do { (current)->trace_recursion++; } while (0) | ||
| 789 | #define trace_recursion_dec() do { (current)->trace_recursion--; } while (0) | ||
| 790 | |||
| 791 | /* Ring buffer has the 10 LSB bits to count */ | ||
| 792 | #define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff) | ||
| 793 | |||
| 794 | /* for function tracing recursion */ | ||
| 795 | #define TRACE_INTERNAL_BIT (1<<11) | ||
| 796 | #define TRACE_GLOBAL_BIT (1<<12) | ||
| 797 | |||
| 798 | #define trace_recursion_set(bit) do { (current)->trace_recursion |= (bit); } while (0) | ||
| 799 | #define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(bit); } while (0) | ||
| 800 | #define trace_recursion_test(bit) ((current)->trace_recursion & (bit)) | ||
| 801 | |||
| 787 | #endif /* _LINUX_KERNEL_TRACE_H */ | 802 | #endif /* _LINUX_KERNEL_TRACE_H */ |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 2fe110341359..686ec399f2a8 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -1657,7 +1657,12 @@ static struct ftrace_ops trace_ops __initdata = | |||
| 1657 | 1657 | ||
| 1658 | static __init void event_trace_self_test_with_function(void) | 1658 | static __init void event_trace_self_test_with_function(void) |
| 1659 | { | 1659 | { |
| 1660 | register_ftrace_function(&trace_ops); | 1660 | int ret; |
| 1661 | ret = register_ftrace_function(&trace_ops); | ||
| 1662 | if (WARN_ON(ret < 0)) { | ||
| 1663 | pr_info("Failed to enable function tracer for event tests\n"); | ||
| 1664 | return; | ||
| 1665 | } | ||
| 1661 | pr_info("Running tests again, along with the function tracer\n"); | 1666 | pr_info("Running tests again, along with the function tracer\n"); |
| 1662 | event_trace_self_tests(); | 1667 | event_trace_self_tests(); |
| 1663 | unregister_ftrace_function(&trace_ops); | 1668 | unregister_ftrace_function(&trace_ops); |
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index cf535ccedc86..e37de492a9e1 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
| @@ -353,6 +353,33 @@ ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val, | |||
| 353 | } | 353 | } |
| 354 | EXPORT_SYMBOL(ftrace_print_symbols_seq); | 354 | EXPORT_SYMBOL(ftrace_print_symbols_seq); |
| 355 | 355 | ||
| 356 | #if BITS_PER_LONG == 32 | ||
| 357 | const char * | ||
| 358 | ftrace_print_symbols_seq_u64(struct trace_seq *p, unsigned long long val, | ||
| 359 | const struct trace_print_flags_u64 *symbol_array) | ||
| 360 | { | ||
| 361 | int i; | ||
| 362 | const char *ret = p->buffer + p->len; | ||
| 363 | |||
| 364 | for (i = 0; symbol_array[i].name; i++) { | ||
| 365 | |||
| 366 | if (val != symbol_array[i].mask) | ||
| 367 | continue; | ||
| 368 | |||
| 369 | trace_seq_puts(p, symbol_array[i].name); | ||
| 370 | break; | ||
| 371 | } | ||
| 372 | |||
| 373 | if (!p->len) | ||
| 374 | trace_seq_printf(p, "0x%llx", val); | ||
| 375 | |||
| 376 | trace_seq_putc(p, 0); | ||
| 377 | |||
| 378 | return ret; | ||
| 379 | } | ||
| 380 | EXPORT_SYMBOL(ftrace_print_symbols_seq_u64); | ||
| 381 | #endif | ||
| 382 | |||
| 356 | const char * | 383 | const char * |
| 357 | ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len) | 384 | ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len) |
| 358 | { | 385 | { |
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 7daa4b072e9f..3d0c56ad4792 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
| @@ -415,15 +415,13 @@ static void watchdog_nmi_disable(int cpu) { return; } | |||
| 415 | #endif /* CONFIG_HARDLOCKUP_DETECTOR */ | 415 | #endif /* CONFIG_HARDLOCKUP_DETECTOR */ |
| 416 | 416 | ||
| 417 | /* prepare/enable/disable routines */ | 417 | /* prepare/enable/disable routines */ |
| 418 | static int watchdog_prepare_cpu(int cpu) | 418 | static void watchdog_prepare_cpu(int cpu) |
| 419 | { | 419 | { |
| 420 | struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu); | 420 | struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu); |
| 421 | 421 | ||
| 422 | WARN_ON(per_cpu(softlockup_watchdog, cpu)); | 422 | WARN_ON(per_cpu(softlockup_watchdog, cpu)); |
| 423 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 423 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| 424 | hrtimer->function = watchdog_timer_fn; | 424 | hrtimer->function = watchdog_timer_fn; |
| 425 | |||
| 426 | return 0; | ||
| 427 | } | 425 | } |
| 428 | 426 | ||
| 429 | static int watchdog_enable(int cpu) | 427 | static int watchdog_enable(int cpu) |
| @@ -542,17 +540,16 @@ static int __cpuinit | |||
| 542 | cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) | 540 | cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) |
| 543 | { | 541 | { |
| 544 | int hotcpu = (unsigned long)hcpu; | 542 | int hotcpu = (unsigned long)hcpu; |
| 545 | int err = 0; | ||
| 546 | 543 | ||
| 547 | switch (action) { | 544 | switch (action) { |
| 548 | case CPU_UP_PREPARE: | 545 | case CPU_UP_PREPARE: |
| 549 | case CPU_UP_PREPARE_FROZEN: | 546 | case CPU_UP_PREPARE_FROZEN: |
| 550 | err = watchdog_prepare_cpu(hotcpu); | 547 | watchdog_prepare_cpu(hotcpu); |
| 551 | break; | 548 | break; |
| 552 | case CPU_ONLINE: | 549 | case CPU_ONLINE: |
| 553 | case CPU_ONLINE_FROZEN: | 550 | case CPU_ONLINE_FROZEN: |
| 554 | if (watchdog_enabled) | 551 | if (watchdog_enabled) |
| 555 | err = watchdog_enable(hotcpu); | 552 | watchdog_enable(hotcpu); |
| 556 | break; | 553 | break; |
| 557 | #ifdef CONFIG_HOTPLUG_CPU | 554 | #ifdef CONFIG_HOTPLUG_CPU |
| 558 | case CPU_UP_CANCELED: | 555 | case CPU_UP_CANCELED: |
diff --git a/mm/maccess.c b/mm/maccess.c index e2b6f5634e0d..4cee182ab5f3 100644 --- a/mm/maccess.c +++ b/mm/maccess.c | |||
| @@ -15,10 +15,10 @@ | |||
| 15 | * happens, handle that and return -EFAULT. | 15 | * happens, handle that and return -EFAULT. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | long __weak probe_kernel_read(void *dst, void *src, size_t size) | 18 | long __weak probe_kernel_read(void *dst, const void *src, size_t size) |
| 19 | __attribute__((alias("__probe_kernel_read"))); | 19 | __attribute__((alias("__probe_kernel_read"))); |
| 20 | 20 | ||
| 21 | long __probe_kernel_read(void *dst, void *src, size_t size) | 21 | long __probe_kernel_read(void *dst, const void *src, size_t size) |
| 22 | { | 22 | { |
| 23 | long ret; | 23 | long ret; |
| 24 | mm_segment_t old_fs = get_fs(); | 24 | mm_segment_t old_fs = get_fs(); |
| @@ -43,10 +43,10 @@ EXPORT_SYMBOL_GPL(probe_kernel_read); | |||
| 43 | * Safely write to address @dst from the buffer at @src. If a kernel fault | 43 | * Safely write to address @dst from the buffer at @src. If a kernel fault |
| 44 | * happens, handle that and return -EFAULT. | 44 | * happens, handle that and return -EFAULT. |
| 45 | */ | 45 | */ |
| 46 | long __weak probe_kernel_write(void *dst, void *src, size_t size) | 46 | long __weak probe_kernel_write(void *dst, const void *src, size_t size) |
| 47 | __attribute__((alias("__probe_kernel_write"))); | 47 | __attribute__((alias("__probe_kernel_write"))); |
| 48 | 48 | ||
| 49 | long __probe_kernel_write(void *dst, void *src, size_t size) | 49 | long __probe_kernel_write(void *dst, const void *src, size_t size) |
| 50 | { | 50 | { |
| 51 | long ret; | 51 | long ret; |
| 52 | mm_segment_t old_fs = get_fs(); | 52 | mm_segment_t old_fs = get_fs(); |
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 4be60364a405..f40a6af6bf40 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | #undef ELF_R_INFO | 43 | #undef ELF_R_INFO |
| 44 | #undef Elf_r_info | 44 | #undef Elf_r_info |
| 45 | #undef ELF_ST_BIND | 45 | #undef ELF_ST_BIND |
| 46 | #undef ELF_ST_TYPE | ||
| 46 | #undef fn_ELF_R_SYM | 47 | #undef fn_ELF_R_SYM |
| 47 | #undef fn_ELF_R_INFO | 48 | #undef fn_ELF_R_INFO |
| 48 | #undef uint_t | 49 | #undef uint_t |
| @@ -76,6 +77,7 @@ | |||
| 76 | # define ELF_R_INFO ELF64_R_INFO | 77 | # define ELF_R_INFO ELF64_R_INFO |
| 77 | # define Elf_r_info Elf64_r_info | 78 | # define Elf_r_info Elf64_r_info |
| 78 | # define ELF_ST_BIND ELF64_ST_BIND | 79 | # define ELF_ST_BIND ELF64_ST_BIND |
| 80 | # define ELF_ST_TYPE ELF64_ST_TYPE | ||
| 79 | # define fn_ELF_R_SYM fn_ELF64_R_SYM | 81 | # define fn_ELF_R_SYM fn_ELF64_R_SYM |
| 80 | # define fn_ELF_R_INFO fn_ELF64_R_INFO | 82 | # define fn_ELF_R_INFO fn_ELF64_R_INFO |
| 81 | # define uint_t uint64_t | 83 | # define uint_t uint64_t |
| @@ -108,6 +110,7 @@ | |||
| 108 | # define ELF_R_INFO ELF32_R_INFO | 110 | # define ELF_R_INFO ELF32_R_INFO |
| 109 | # define Elf_r_info Elf32_r_info | 111 | # define Elf_r_info Elf32_r_info |
| 110 | # define ELF_ST_BIND ELF32_ST_BIND | 112 | # define ELF_ST_BIND ELF32_ST_BIND |
| 113 | # define ELF_ST_TYPE ELF32_ST_TYPE | ||
| 111 | # define fn_ELF_R_SYM fn_ELF32_R_SYM | 114 | # define fn_ELF_R_SYM fn_ELF32_R_SYM |
| 112 | # define fn_ELF_R_INFO fn_ELF32_R_INFO | 115 | # define fn_ELF_R_INFO fn_ELF32_R_INFO |
| 113 | # define uint_t uint32_t | 116 | # define uint_t uint32_t |
| @@ -427,6 +430,11 @@ static unsigned find_secsym_ndx(unsigned const txtndx, | |||
| 427 | if (txtndx == w2(symp->st_shndx) | 430 | if (txtndx == w2(symp->st_shndx) |
| 428 | /* avoid STB_WEAK */ | 431 | /* avoid STB_WEAK */ |
| 429 | && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) { | 432 | && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) { |
| 433 | /* function symbols on ARM have quirks, avoid them */ | ||
| 434 | if (w2(ehdr->e_machine) == EM_ARM | ||
| 435 | && ELF_ST_TYPE(symp->st_info) == STT_FUNC) | ||
| 436 | continue; | ||
| 437 | |||
| 430 | *recvalp = _w(symp->st_value); | 438 | *recvalp = _w(symp->st_value); |
| 431 | return symp - sym0; | 439 | return symp - sym0; |
| 432 | } | 440 | } |
diff --git a/scripts/tags.sh b/scripts/tags.sh index bd6185d529cf..75c5d24f1993 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh | |||
| @@ -132,7 +132,7 @@ exuberant() | |||
| 132 | --regex-asm='/^ENTRY\(([^)]*)\).*/\1/' \ | 132 | --regex-asm='/^ENTRY\(([^)]*)\).*/\1/' \ |
| 133 | --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ | 133 | --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ |
| 134 | --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \ | 134 | --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \ |
| 135 | --regex-c++='/^DEFINE_EVENT\(([^,)]*).*/trace_\1/' | 135 | --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/' |
| 136 | 136 | ||
| 137 | all_kconfigs | xargs $1 -a \ | 137 | all_kconfigs | xargs $1 -a \ |
| 138 | --langdef=kconfig --language-force=kconfig \ | 138 | --langdef=kconfig --language-force=kconfig \ |
| @@ -152,7 +152,9 @@ emacs() | |||
| 152 | { | 152 | { |
| 153 | all_sources | xargs $1 -a \ | 153 | all_sources | xargs $1 -a \ |
| 154 | --regex='/^ENTRY(\([^)]*\)).*/\1/' \ | 154 | --regex='/^ENTRY(\([^)]*\)).*/\1/' \ |
| 155 | --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/' | 155 | --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/' \ |
| 156 | --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/' \ | ||
| 157 | --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/' | ||
| 156 | 158 | ||
| 157 | all_kconfigs | xargs $1 -a \ | 159 | all_kconfigs | xargs $1 -a \ |
| 158 | --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' | 160 | --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 1455413ec7a7..032ba6398a5c 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -215,11 +215,13 @@ LIB_FILE=$(OUTPUT)libperf.a | |||
| 215 | LIB_H += ../../include/linux/perf_event.h | 215 | LIB_H += ../../include/linux/perf_event.h |
| 216 | LIB_H += ../../include/linux/rbtree.h | 216 | LIB_H += ../../include/linux/rbtree.h |
| 217 | LIB_H += ../../include/linux/list.h | 217 | LIB_H += ../../include/linux/list.h |
| 218 | LIB_H += ../../include/linux/const.h | ||
| 218 | LIB_H += ../../include/linux/hash.h | 219 | LIB_H += ../../include/linux/hash.h |
| 219 | LIB_H += ../../include/linux/stringify.h | 220 | LIB_H += ../../include/linux/stringify.h |
| 220 | LIB_H += util/include/linux/bitmap.h | 221 | LIB_H += util/include/linux/bitmap.h |
| 221 | LIB_H += util/include/linux/bitops.h | 222 | LIB_H += util/include/linux/bitops.h |
| 222 | LIB_H += util/include/linux/compiler.h | 223 | LIB_H += util/include/linux/compiler.h |
| 224 | LIB_H += util/include/linux/const.h | ||
| 223 | LIB_H += util/include/linux/ctype.h | 225 | LIB_H += util/include/linux/ctype.h |
| 224 | LIB_H += util/include/linux/kernel.h | 226 | LIB_H += util/include/linux/kernel.h |
| 225 | LIB_H += util/include/linux/list.h | 227 | LIB_H += util/include/linux/list.h |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e18eb7ed30ae..7b139e1e7e86 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -8,8 +8,6 @@ | |||
| 8 | #include "builtin.h" | 8 | #include "builtin.h" |
| 9 | 9 | ||
| 10 | #include "util/util.h" | 10 | #include "util/util.h" |
| 11 | |||
| 12 | #include "util/util.h" | ||
| 13 | #include "util/color.h" | 11 | #include "util/color.h" |
| 14 | #include <linux/list.h> | 12 | #include <linux/list.h> |
| 15 | #include "util/cache.h" | 13 | #include "util/cache.h" |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0974f957b8fa..8e2c85798185 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -823,6 +823,16 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
| 823 | 823 | ||
| 824 | symbol__init(); | 824 | symbol__init(); |
| 825 | 825 | ||
| 826 | if (symbol_conf.kptr_restrict) | ||
| 827 | pr_warning( | ||
| 828 | "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n" | ||
| 829 | "check /proc/sys/kernel/kptr_restrict.\n\n" | ||
| 830 | "Samples in kernel functions may not be resolved if a suitable vmlinux\n" | ||
| 831 | "file is not found in the buildid cache or in the vmlinux path.\n\n" | ||
| 832 | "Samples in kernel modules won't be resolved at all.\n\n" | ||
| 833 | "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" | ||
| 834 | "even with a suitable vmlinux or kallsyms file.\n\n"); | ||
| 835 | |||
| 826 | if (no_buildid_cache || no_buildid) | 836 | if (no_buildid_cache || no_buildid) |
| 827 | disable_buildid_cache(); | 837 | disable_buildid_cache(); |
| 828 | 838 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 498c6f70a747..287a173523a7 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -116,6 +116,9 @@ static int process_sample_event(union perf_event *event, | |||
| 116 | if (al.filtered || (hide_unresolved && al.sym == NULL)) | 116 | if (al.filtered || (hide_unresolved && al.sym == NULL)) |
| 117 | return 0; | 117 | return 0; |
| 118 | 118 | ||
| 119 | if (al.map != NULL) | ||
| 120 | al.map->dso->hit = 1; | ||
| 121 | |||
| 119 | if (perf_session__add_hist_entry(session, &al, sample, evsel)) { | 122 | if (perf_session__add_hist_entry(session, &al, sample, evsel)) { |
| 120 | pr_debug("problem incrementing symbol period, skipping event\n"); | 123 | pr_debug("problem incrementing symbol period, skipping event\n"); |
| 121 | return -1; | 124 | return -1; |
| @@ -249,6 +252,8 @@ static int __cmd_report(void) | |||
| 249 | u64 nr_samples; | 252 | u64 nr_samples; |
| 250 | struct perf_session *session; | 253 | struct perf_session *session; |
| 251 | struct perf_evsel *pos; | 254 | struct perf_evsel *pos; |
| 255 | struct map *kernel_map; | ||
| 256 | struct kmap *kernel_kmap; | ||
| 252 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; | 257 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; |
| 253 | 258 | ||
| 254 | signal(SIGINT, sig_handler); | 259 | signal(SIGINT, sig_handler); |
| @@ -268,6 +273,24 @@ static int __cmd_report(void) | |||
| 268 | if (ret) | 273 | if (ret) |
| 269 | goto out_delete; | 274 | goto out_delete; |
| 270 | 275 | ||
| 276 | kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; | ||
| 277 | kernel_kmap = map__kmap(kernel_map); | ||
| 278 | if (kernel_map == NULL || | ||
| 279 | (kernel_map->dso->hit && | ||
| 280 | (kernel_kmap->ref_reloc_sym == NULL || | ||
| 281 | kernel_kmap->ref_reloc_sym->addr == 0))) { | ||
| 282 | const struct dso *kdso = kernel_map->dso; | ||
| 283 | |||
| 284 | ui__warning( | ||
| 285 | "Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n" | ||
| 286 | "Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n" | ||
| 287 | "Samples in kernel modules can't be resolved as well.\n\n", | ||
| 288 | RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION]) ? | ||
| 289 | "As no suitable kallsyms nor vmlinux was found, kernel samples\n" | ||
| 290 | "can't be resolved." : | ||
| 291 | "If some relocation was applied (e.g. kexec) symbols may be misresolved."); | ||
| 292 | } | ||
| 293 | |||
| 271 | if (dump_trace) { | 294 | if (dump_trace) { |
| 272 | perf_session__fprintf_nr_events(session, stdout); | 295 | perf_session__fprintf_nr_events(session, stdout); |
| 273 | goto out_delete; | 296 | goto out_delete; |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 974f6d3f4e53..22747de7234b 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include "util/symbol.h" | 10 | #include "util/symbol.h" |
| 11 | #include "util/thread.h" | 11 | #include "util/thread.h" |
| 12 | #include "util/trace-event.h" | 12 | #include "util/trace-event.h" |
| 13 | #include "util/parse-options.h" | ||
| 14 | #include "util/util.h" | 13 | #include "util/util.h" |
| 15 | #include "util/evlist.h" | 14 | #include "util/evlist.h" |
| 16 | #include "util/evsel.h" | 15 | #include "util/evsel.h" |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2d7934e9de38..f2f3f4937aa2 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -62,8 +62,6 @@ | |||
| 62 | #include <linux/unistd.h> | 62 | #include <linux/unistd.h> |
| 63 | #include <linux/types.h> | 63 | #include <linux/types.h> |
| 64 | 64 | ||
| 65 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | ||
| 66 | |||
| 67 | static struct perf_top top = { | 65 | static struct perf_top top = { |
| 68 | .count_filter = 5, | 66 | .count_filter = 5, |
| 69 | .delay_secs = 2, | 67 | .delay_secs = 2, |
| @@ -82,6 +80,8 @@ static bool use_tui, use_stdio; | |||
| 82 | 80 | ||
| 83 | static int default_interval = 0; | 81 | static int default_interval = 0; |
| 84 | 82 | ||
| 83 | static bool kptr_restrict_warned; | ||
| 84 | static bool vmlinux_warned; | ||
| 85 | static bool inherit = false; | 85 | static bool inherit = false; |
| 86 | static int realtime_prio = 0; | 86 | static int realtime_prio = 0; |
| 87 | static bool group = false; | 87 | static bool group = false; |
| @@ -740,7 +740,22 @@ static void perf_event__process_sample(const union perf_event *event, | |||
| 740 | al.filtered) | 740 | al.filtered) |
| 741 | return; | 741 | return; |
| 742 | 742 | ||
| 743 | if (!kptr_restrict_warned && | ||
| 744 | symbol_conf.kptr_restrict && | ||
| 745 | al.cpumode == PERF_RECORD_MISC_KERNEL) { | ||
| 746 | ui__warning( | ||
| 747 | "Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n" | ||
| 748 | "Check /proc/sys/kernel/kptr_restrict.\n\n" | ||
| 749 | "Kernel%s samples will not be resolved.\n", | ||
| 750 | !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ? | ||
| 751 | " modules" : ""); | ||
| 752 | if (use_browser <= 0) | ||
| 753 | sleep(5); | ||
| 754 | kptr_restrict_warned = true; | ||
| 755 | } | ||
| 756 | |||
| 743 | if (al.sym == NULL) { | 757 | if (al.sym == NULL) { |
| 758 | const char *msg = "Kernel samples will not be resolved.\n"; | ||
| 744 | /* | 759 | /* |
| 745 | * As we do lazy loading of symtabs we only will know if the | 760 | * As we do lazy loading of symtabs we only will know if the |
| 746 | * specified vmlinux file is invalid when we actually have a | 761 | * specified vmlinux file is invalid when we actually have a |
| @@ -752,12 +767,20 @@ static void perf_event__process_sample(const union perf_event *event, | |||
| 752 | * --hide-kernel-symbols, even if the user specifies an | 767 | * --hide-kernel-symbols, even if the user specifies an |
| 753 | * invalid --vmlinux ;-) | 768 | * invalid --vmlinux ;-) |
| 754 | */ | 769 | */ |
| 755 | if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && | 770 | if (!kptr_restrict_warned && !vmlinux_warned && |
| 771 | al.map == machine->vmlinux_maps[MAP__FUNCTION] && | ||
| 756 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { | 772 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { |
| 757 | ui__warning("The %s file can't be used\n", | 773 | if (symbol_conf.vmlinux_name) { |
| 758 | symbol_conf.vmlinux_name); | 774 | ui__warning("The %s file can't be used.\n%s", |
| 759 | exit_browser(0); | 775 | symbol_conf.vmlinux_name, msg); |
| 760 | exit(1); | 776 | } else { |
| 777 | ui__warning("A vmlinux file was not found.\n%s", | ||
| 778 | msg); | ||
| 779 | } | ||
| 780 | |||
| 781 | if (use_browser <= 0) | ||
| 782 | sleep(5); | ||
| 783 | vmlinux_warned = true; | ||
| 761 | } | 784 | } |
| 762 | 785 | ||
| 763 | return; | 786 | return; |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6635fcd11ca5..0fe9adf76379 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -553,9 +553,18 @@ static int perf_event__process_kernel_mmap(union perf_event *event, | |||
| 553 | goto out_problem; | 553 | goto out_problem; |
| 554 | 554 | ||
| 555 | perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps); | 555 | perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps); |
| 556 | perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, | 556 | |
| 557 | symbol_name, | 557 | /* |
| 558 | event->mmap.pgoff); | 558 | * Avoid using a zero address (kptr_restrict) for the ref reloc |
| 559 | * symbol. Effectively having zero here means that at record | ||
| 560 | * time /proc/sys/kernel/kptr_restrict was non zero. | ||
| 561 | */ | ||
| 562 | if (event->mmap.pgoff != 0) { | ||
| 563 | perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, | ||
| 564 | symbol_name, | ||
| 565 | event->mmap.pgoff); | ||
| 566 | } | ||
| 567 | |||
| 559 | if (machine__is_default_guest(machine)) { | 568 | if (machine__is_default_guest(machine)) { |
| 560 | /* | 569 | /* |
| 561 | * preload dso of guest kernel and modules | 570 | * preload dso of guest kernel and modules |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ee0fe0dffa71..cca29ededb5b 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -35,7 +35,17 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | |||
| 35 | 35 | ||
| 36 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 36 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
| 37 | { | 37 | { |
| 38 | int cpu, thread; | ||
| 38 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); | 39 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); |
| 40 | |||
| 41 | if (evsel->fd) { | ||
| 42 | for (cpu = 0; cpu < ncpus; cpu++) { | ||
| 43 | for (thread = 0; thread < nthreads; thread++) { | ||
| 44 | FD(evsel, cpu, thread) = -1; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 39 | return evsel->fd != NULL ? 0 : -ENOMEM; | 49 | return evsel->fd != NULL ? 0 : -ENOMEM; |
| 40 | } | 50 | } |
| 41 | 51 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 0717bebc7649..afb0849fe530 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -193,9 +193,13 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
| 193 | *linkname = malloc(size), *targetname; | 193 | *linkname = malloc(size), *targetname; |
| 194 | int len, err = -1; | 194 | int len, err = -1; |
| 195 | 195 | ||
| 196 | if (is_kallsyms) | 196 | if (is_kallsyms) { |
| 197 | if (symbol_conf.kptr_restrict) { | ||
| 198 | pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); | ||
| 199 | return 0; | ||
| 200 | } | ||
| 197 | realname = (char *)name; | 201 | realname = (char *)name; |
| 198 | else | 202 | } else |
| 199 | realname = realpath(name, NULL); | 203 | realname = realpath(name, NULL); |
| 200 | 204 | ||
| 201 | if (realname == NULL || filename == NULL || linkname == NULL) | 205 | if (realname == NULL || filename == NULL || linkname == NULL) |
diff --git a/tools/perf/util/include/linux/const.h b/tools/perf/util/include/linux/const.h new file mode 100644 index 000000000000..1b476c9ae649 --- /dev/null +++ b/tools/perf/util/include/linux/const.h | |||
| @@ -0,0 +1 @@ | |||
| #include "../../../../include/linux/const.h" | |||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 516876dfbe52..eec196329fd9 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -676,9 +676,30 @@ discard_symbol: rb_erase(&pos->rb_node, root); | |||
| 676 | return count + moved; | 676 | return count + moved; |
| 677 | } | 677 | } |
| 678 | 678 | ||
| 679 | static bool symbol__restricted_filename(const char *filename, | ||
| 680 | const char *restricted_filename) | ||
| 681 | { | ||
| 682 | bool restricted = false; | ||
| 683 | |||
| 684 | if (symbol_conf.kptr_restrict) { | ||
| 685 | char *r = realpath(filename, NULL); | ||
| 686 | |||
| 687 | if (r != NULL) { | ||
| 688 | restricted = strcmp(r, restricted_filename) == 0; | ||
| 689 | free(r); | ||
| 690 | return restricted; | ||
| 691 | } | ||
| 692 | } | ||
| 693 | |||
| 694 | return restricted; | ||
| 695 | } | ||
| 696 | |||
| 679 | int dso__load_kallsyms(struct dso *dso, const char *filename, | 697 | int dso__load_kallsyms(struct dso *dso, const char *filename, |
| 680 | struct map *map, symbol_filter_t filter) | 698 | struct map *map, symbol_filter_t filter) |
| 681 | { | 699 | { |
| 700 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | ||
| 701 | return -1; | ||
| 702 | |||
| 682 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 703 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
| 683 | return -1; | 704 | return -1; |
| 684 | 705 | ||
| @@ -1790,6 +1811,9 @@ static int machine__create_modules(struct machine *machine) | |||
| 1790 | modules = path; | 1811 | modules = path; |
| 1791 | } | 1812 | } |
| 1792 | 1813 | ||
| 1814 | if (symbol__restricted_filename(path, "/proc/modules")) | ||
| 1815 | return -1; | ||
| 1816 | |||
| 1793 | file = fopen(modules, "r"); | 1817 | file = fopen(modules, "r"); |
| 1794 | if (file == NULL) | 1818 | if (file == NULL) |
| 1795 | return -1; | 1819 | return -1; |
| @@ -2239,6 +2263,9 @@ static u64 machine__get_kernel_start_addr(struct machine *machine) | |||
| 2239 | } | 2263 | } |
| 2240 | } | 2264 | } |
| 2241 | 2265 | ||
| 2266 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | ||
| 2267 | return 0; | ||
| 2268 | |||
| 2242 | if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) | 2269 | if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) |
| 2243 | return 0; | 2270 | return 0; |
| 2244 | 2271 | ||
| @@ -2410,6 +2437,25 @@ static int setup_list(struct strlist **list, const char *list_str, | |||
| 2410 | return 0; | 2437 | return 0; |
| 2411 | } | 2438 | } |
| 2412 | 2439 | ||
| 2440 | static bool symbol__read_kptr_restrict(void) | ||
| 2441 | { | ||
| 2442 | bool value = false; | ||
| 2443 | |||
| 2444 | if (geteuid() != 0) { | ||
| 2445 | FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); | ||
| 2446 | if (fp != NULL) { | ||
| 2447 | char line[8]; | ||
| 2448 | |||
| 2449 | if (fgets(line, sizeof(line), fp) != NULL) | ||
| 2450 | value = atoi(line) != 0; | ||
| 2451 | |||
| 2452 | fclose(fp); | ||
| 2453 | } | ||
| 2454 | } | ||
| 2455 | |||
| 2456 | return value; | ||
| 2457 | } | ||
| 2458 | |||
| 2413 | int symbol__init(void) | 2459 | int symbol__init(void) |
| 2414 | { | 2460 | { |
| 2415 | const char *symfs; | 2461 | const char *symfs; |
| @@ -2456,6 +2502,8 @@ int symbol__init(void) | |||
| 2456 | if (symfs != symbol_conf.symfs) | 2502 | if (symfs != symbol_conf.symfs) |
| 2457 | free((void *)symfs); | 2503 | free((void *)symfs); |
| 2458 | 2504 | ||
| 2505 | symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); | ||
| 2506 | |||
| 2459 | symbol_conf.initialized = true; | 2507 | symbol_conf.initialized = true; |
| 2460 | return 0; | 2508 | return 0; |
| 2461 | 2509 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 242de0101a86..325ee36a9d29 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -75,7 +75,8 @@ struct symbol_conf { | |||
| 75 | use_callchain, | 75 | use_callchain, |
| 76 | exclude_other, | 76 | exclude_other, |
| 77 | show_cpu_utilization, | 77 | show_cpu_utilization, |
| 78 | initialized; | 78 | initialized, |
| 79 | kptr_restrict; | ||
| 79 | const char *vmlinux_name, | 80 | const char *vmlinux_name, |
| 80 | *kallsyms_name, | 81 | *kallsyms_name, |
| 81 | *source_prefix, | 82 | *source_prefix, |
