diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-07 16:17:37 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-07 16:17:37 -0400 |
| commit | 8b061610dac3a3b89770c85ad63b481a47b0c38e (patch) | |
| tree | 3ab93ad7f8f3e8bd612cff4e59d55d5a36c0c1fa | |
| parent | c2bf807eb347325988b1c7f9139e934ed9b1d795 (diff) | |
| parent | 174a7b1f9692acad7f0ca2b02f696894201a6d94 (diff) | |
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
perf tools: Makefile: Use gcc to determine ARCH
perf events, x86: Fix Intel Nehalem and Westmere last level cache event definitions
hw_breakpoints, powerpc: Fix CONFIG_HAVE_HW_BREAKPOINT off-case in ptrace_set_debugreg()
sh, hw_breakpoints: Fix racy access to ptrace breakpoints
arm, hw_breakpoints: Fix racy access to ptrace breakpoints
powerpc, hw_breakpoints: Fix racy access to ptrace breakpoints
x86, hw_breakpoints: Fix racy access to ptrace breakpoints
ptrace: Prepare to fix racy accesses on task breakpoints
| -rw-r--r-- | arch/arm/kernel/ptrace.c | 8 | ||||
| -rw-r--r-- | arch/powerpc/kernel/ptrace.c | 12 | ||||
| -rw-r--r-- | arch/sh/kernel/ptrace_32.c | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 87 | ||||
| -rw-r--r-- | arch/x86/kernel/ptrace.c | 36 | ||||
| -rw-r--r-- | include/linux/ptrace.h | 13 | ||||
| -rw-r--r-- | include/linux/sched.h | 3 | ||||
| -rw-r--r-- | kernel/exit.c | 2 | ||||
| -rw-r--r-- | kernel/ptrace.c | 17 | ||||
| -rw-r--r-- | tools/perf/Makefile | 16 |
10 files changed, 144 insertions, 54 deletions
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 2bf27f364d09..8182f45ca493 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
| @@ -767,12 +767,20 @@ long arch_ptrace(struct task_struct *child, long request, | |||
| 767 | 767 | ||
| 768 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 768 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
| 769 | case PTRACE_GETHBPREGS: | 769 | case PTRACE_GETHBPREGS: |
| 770 | if (ptrace_get_breakpoints(child) < 0) | ||
| 771 | return -ESRCH; | ||
| 772 | |||
| 770 | ret = ptrace_gethbpregs(child, addr, | 773 | ret = ptrace_gethbpregs(child, addr, |
| 771 | (unsigned long __user *)data); | 774 | (unsigned long __user *)data); |
| 775 | ptrace_put_breakpoints(child); | ||
| 772 | break; | 776 | break; |
| 773 | case PTRACE_SETHBPREGS: | 777 | case PTRACE_SETHBPREGS: |
| 778 | if (ptrace_get_breakpoints(child) < 0) | ||
| 779 | return -ESRCH; | ||
| 780 | |||
| 774 | ret = ptrace_sethbpregs(child, addr, | 781 | ret = ptrace_sethbpregs(child, addr, |
| 775 | (unsigned long __user *)data); | 782 | (unsigned long __user *)data); |
| 783 | ptrace_put_breakpoints(child); | ||
| 776 | break; | 784 | break; |
| 777 | #endif | 785 | #endif |
| 778 | 786 | ||
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 55613e33e263..a6ae1cfad86c 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
| @@ -933,12 +933,16 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
| 933 | if (data && !(data & DABR_TRANSLATION)) | 933 | if (data && !(data & DABR_TRANSLATION)) |
| 934 | return -EIO; | 934 | return -EIO; |
| 935 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 935 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
| 936 | if (ptrace_get_breakpoints(task) < 0) | ||
| 937 | return -ESRCH; | ||
| 938 | |||
| 936 | bp = thread->ptrace_bps[0]; | 939 | bp = thread->ptrace_bps[0]; |
| 937 | if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) { | 940 | if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) { |
| 938 | if (bp) { | 941 | if (bp) { |
| 939 | unregister_hw_breakpoint(bp); | 942 | unregister_hw_breakpoint(bp); |
| 940 | thread->ptrace_bps[0] = NULL; | 943 | thread->ptrace_bps[0] = NULL; |
| 941 | } | 944 | } |
| 945 | ptrace_put_breakpoints(task); | ||
| 942 | return 0; | 946 | return 0; |
| 943 | } | 947 | } |
| 944 | if (bp) { | 948 | if (bp) { |
| @@ -948,9 +952,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
| 948 | (DABR_DATA_WRITE | DABR_DATA_READ), | 952 | (DABR_DATA_WRITE | DABR_DATA_READ), |
| 949 | &attr.bp_type); | 953 | &attr.bp_type); |
| 950 | ret = modify_user_hw_breakpoint(bp, &attr); | 954 | ret = modify_user_hw_breakpoint(bp, &attr); |
| 951 | if (ret) | 955 | if (ret) { |
| 956 | ptrace_put_breakpoints(task); | ||
| 952 | return ret; | 957 | return ret; |
| 958 | } | ||
| 953 | thread->ptrace_bps[0] = bp; | 959 | thread->ptrace_bps[0] = bp; |
| 960 | ptrace_put_breakpoints(task); | ||
| 954 | thread->dabr = data; | 961 | thread->dabr = data; |
| 955 | return 0; | 962 | return 0; |
| 956 | } | 963 | } |
| @@ -965,9 +972,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
| 965 | ptrace_triggered, task); | 972 | ptrace_triggered, task); |
| 966 | if (IS_ERR(bp)) { | 973 | if (IS_ERR(bp)) { |
| 967 | thread->ptrace_bps[0] = NULL; | 974 | thread->ptrace_bps[0] = NULL; |
| 975 | ptrace_put_breakpoints(task); | ||
| 968 | return PTR_ERR(bp); | 976 | return PTR_ERR(bp); |
| 969 | } | 977 | } |
| 970 | 978 | ||
| 979 | ptrace_put_breakpoints(task); | ||
| 980 | |||
| 971 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 981 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
| 972 | 982 | ||
| 973 | /* Move contents to the DABR register */ | 983 | /* Move contents to the DABR register */ |
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 2130ca674e9b..3d7b209b2178 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c | |||
| @@ -117,7 +117,11 @@ void user_enable_single_step(struct task_struct *child) | |||
| 117 | 117 | ||
| 118 | set_tsk_thread_flag(child, TIF_SINGLESTEP); | 118 | set_tsk_thread_flag(child, TIF_SINGLESTEP); |
| 119 | 119 | ||
| 120 | if (ptrace_get_breakpoints(child) < 0) | ||
| 121 | return; | ||
| 122 | |||
| 120 | set_single_step(child, pc); | 123 | set_single_step(child, pc); |
| 124 | ptrace_put_breakpoints(child); | ||
| 121 | } | 125 | } |
| 122 | 126 | ||
| 123 | void user_disable_single_step(struct task_struct *child) | 127 | void user_disable_single_step(struct task_struct *child) |
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index e61539b07d2c..447a28de6f09 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
| @@ -184,26 +184,23 @@ static __initconst const u64 snb_hw_cache_event_ids | |||
| 184 | }, | 184 | }, |
| 185 | }, | 185 | }, |
| 186 | [ C(LL ) ] = { | 186 | [ C(LL ) ] = { |
| 187 | /* | ||
| 188 | * TBD: Need Off-core Response Performance Monitoring support | ||
| 189 | */ | ||
| 190 | [ C(OP_READ) ] = { | 187 | [ C(OP_READ) ] = { |
| 191 | /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */ | 188 | /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */ |
| 192 | [ C(RESULT_ACCESS) ] = 0x01b7, | 189 | [ C(RESULT_ACCESS) ] = 0x01b7, |
| 193 | /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */ | 190 | /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */ |
| 194 | [ C(RESULT_MISS) ] = 0x01bb, | 191 | [ C(RESULT_MISS) ] = 0x01b7, |
| 195 | }, | 192 | }, |
| 196 | [ C(OP_WRITE) ] = { | 193 | [ C(OP_WRITE) ] = { |
| 197 | /* OFFCORE_RESPONSE_0.ANY_RFO.LOCAL_CACHE */ | 194 | /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */ |
| 198 | [ C(RESULT_ACCESS) ] = 0x01b7, | 195 | [ C(RESULT_ACCESS) ] = 0x01b7, |
| 199 | /* OFFCORE_RESPONSE_1.ANY_RFO.ANY_LLC_MISS */ | 196 | /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */ |
| 200 | [ C(RESULT_MISS) ] = 0x01bb, | 197 | [ C(RESULT_MISS) ] = 0x01b7, |
| 201 | }, | 198 | }, |
| 202 | [ C(OP_PREFETCH) ] = { | 199 | [ C(OP_PREFETCH) ] = { |
| 203 | /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */ | 200 | /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */ |
| 204 | [ C(RESULT_ACCESS) ] = 0x01b7, | 201 | [ C(RESULT_ACCESS) ] = 0x01b7, |
| 205 | /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */ | 202 | /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */ |
| 206 | [ C(RESULT_MISS) ] = 0x01bb, | 203 | [ C(RESULT_MISS) ] = 0x01b7, |
| 207 | }, | 204 | }, |
| 208 | }, | 205 | }, |
| 209 | [ C(DTLB) ] = { | 206 | [ C(DTLB) ] = { |
| @@ -285,26 +282,26 @@ static __initconst const u64 westmere_hw_cache_event_ids | |||
| 285 | }, | 282 | }, |
| 286 | [ C(LL ) ] = { | 283 | [ C(LL ) ] = { |
| 287 | [ C(OP_READ) ] = { | 284 | [ C(OP_READ) ] = { |
| 288 | /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */ | 285 | /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */ |
| 289 | [ C(RESULT_ACCESS) ] = 0x01b7, | 286 | [ C(RESULT_ACCESS) ] = 0x01b7, |
| 290 | /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */ | 287 | /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */ |
| 291 | [ C(RESULT_MISS) ] = 0x01bb, | 288 | [ C(RESULT_MISS) ] = 0x01b7, |
| 292 | }, | 289 | }, |
| 293 | /* | 290 | /* |
| 294 | * Use RFO, not WRITEBACK, because a write miss would typically occur | 291 | * Use RFO, not WRITEBACK, because a write miss would typically occur |
| 295 | * on RFO. | 292 | * on RFO. |
| 296 | */ | 293 | */ |
| 297 | [ C(OP_WRITE) ] = { | 294 | [ C(OP_WRITE) ] = { |
| 298 | /* OFFCORE_RESPONSE_1.ANY_RFO.LOCAL_CACHE */ | 295 | /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */ |
| 299 | [ C(RESULT_ACCESS) ] = 0x01bb, | 296 | [ C(RESULT_ACCESS) ] = 0x01b7, |
| 300 | /* OFFCORE_RESPONSE_0.ANY_RFO.ANY_LLC_MISS */ | 297 | /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */ |
| 301 | [ C(RESULT_MISS) ] = 0x01b7, | 298 | [ C(RESULT_MISS) ] = 0x01b7, |
| 302 | }, | 299 | }, |
| 303 | [ C(OP_PREFETCH) ] = { | 300 | [ C(OP_PREFETCH) ] = { |
| 304 | /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */ | 301 | /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */ |
| 305 | [ C(RESULT_ACCESS) ] = 0x01b7, | 302 | [ C(RESULT_ACCESS) ] = 0x01b7, |
| 306 | /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */ | 303 | /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */ |
| 307 | [ C(RESULT_MISS) ] = 0x01bb, | 304 | [ C(RESULT_MISS) ] = 0x01b7, |
| 308 | }, | 305 | }, |
| 309 | }, | 306 | }, |
| 310 | [ C(DTLB) ] = { | 307 | [ C(DTLB) ] = { |
| @@ -352,16 +349,36 @@ static __initconst const u64 westmere_hw_cache_event_ids | |||
| 352 | }; | 349 | }; |
| 353 | 350 | ||
| 354 | /* | 351 | /* |
| 355 | * OFFCORE_RESPONSE MSR bits (subset), See IA32 SDM Vol 3 30.6.1.3 | 352 | * Nehalem/Westmere MSR_OFFCORE_RESPONSE bits; |
| 353 | * See IA32 SDM Vol 3B 30.6.1.3 | ||
| 356 | */ | 354 | */ |
| 357 | 355 | ||
| 358 | #define DMND_DATA_RD (1 << 0) | 356 | #define NHM_DMND_DATA_RD (1 << 0) |
| 359 | #define DMND_RFO (1 << 1) | 357 | #define NHM_DMND_RFO (1 << 1) |
| 360 | #define DMND_WB (1 << 3) | 358 | #define NHM_DMND_IFETCH (1 << 2) |
| 361 | #define PF_DATA_RD (1 << 4) | 359 | #define NHM_DMND_WB (1 << 3) |
| 362 | #define PF_DATA_RFO (1 << 5) | 360 | #define NHM_PF_DATA_RD (1 << 4) |
| 363 | #define RESP_UNCORE_HIT (1 << 8) | 361 | #define NHM_PF_DATA_RFO (1 << 5) |
| 364 | #define RESP_MISS (0xf600) /* non uncore hit */ | 362 | #define NHM_PF_IFETCH (1 << 6) |
| 363 | #define NHM_OFFCORE_OTHER (1 << 7) | ||
| 364 | #define NHM_UNCORE_HIT (1 << 8) | ||
| 365 | #define NHM_OTHER_CORE_HIT_SNP (1 << 9) | ||
| 366 | #define NHM_OTHER_CORE_HITM (1 << 10) | ||
| 367 | /* reserved */ | ||
| 368 | #define NHM_REMOTE_CACHE_FWD (1 << 12) | ||
| 369 | #define NHM_REMOTE_DRAM (1 << 13) | ||
| 370 | #define NHM_LOCAL_DRAM (1 << 14) | ||
| 371 | #define NHM_NON_DRAM (1 << 15) | ||
| 372 | |||
| 373 | #define NHM_ALL_DRAM (NHM_REMOTE_DRAM|NHM_LOCAL_DRAM) | ||
| 374 | |||
| 375 | #define NHM_DMND_READ (NHM_DMND_DATA_RD) | ||
| 376 | #define NHM_DMND_WRITE (NHM_DMND_RFO|NHM_DMND_WB) | ||
| 377 | #define NHM_DMND_PREFETCH (NHM_PF_DATA_RD|NHM_PF_DATA_RFO) | ||
| 378 | |||
| 379 | #define NHM_L3_HIT (NHM_UNCORE_HIT|NHM_OTHER_CORE_HIT_SNP|NHM_OTHER_CORE_HITM) | ||
| 380 | #define NHM_L3_MISS (NHM_NON_DRAM|NHM_ALL_DRAM|NHM_REMOTE_CACHE_FWD) | ||
| 381 | #define NHM_L3_ACCESS (NHM_L3_HIT|NHM_L3_MISS) | ||
| 365 | 382 | ||
| 366 | static __initconst const u64 nehalem_hw_cache_extra_regs | 383 | static __initconst const u64 nehalem_hw_cache_extra_regs |
| 367 | [PERF_COUNT_HW_CACHE_MAX] | 384 | [PERF_COUNT_HW_CACHE_MAX] |
| @@ -370,16 +387,16 @@ static __initconst const u64 nehalem_hw_cache_extra_regs | |||
| 370 | { | 387 | { |
| 371 | [ C(LL ) ] = { | 388 | [ C(LL ) ] = { |
| 372 | [ C(OP_READ) ] = { | 389 | [ C(OP_READ) ] = { |
| 373 | [ C(RESULT_ACCESS) ] = DMND_DATA_RD|RESP_UNCORE_HIT, | 390 | [ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_L3_ACCESS, |
| 374 | [ C(RESULT_MISS) ] = DMND_DATA_RD|RESP_MISS, | 391 | [ C(RESULT_MISS) ] = NHM_DMND_READ|NHM_L3_MISS, |
| 375 | }, | 392 | }, |
| 376 | [ C(OP_WRITE) ] = { | 393 | [ C(OP_WRITE) ] = { |
| 377 | [ C(RESULT_ACCESS) ] = DMND_RFO|DMND_WB|RESP_UNCORE_HIT, | 394 | [ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_L3_ACCESS, |
| 378 | [ C(RESULT_MISS) ] = DMND_RFO|DMND_WB|RESP_MISS, | 395 | [ C(RESULT_MISS) ] = NHM_DMND_WRITE|NHM_L3_MISS, |
| 379 | }, | 396 | }, |
| 380 | [ C(OP_PREFETCH) ] = { | 397 | [ C(OP_PREFETCH) ] = { |
| 381 | [ C(RESULT_ACCESS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_UNCORE_HIT, | 398 | [ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_L3_ACCESS, |
| 382 | [ C(RESULT_MISS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_MISS, | 399 | [ C(RESULT_MISS) ] = NHM_DMND_PREFETCH|NHM_L3_MISS, |
| 383 | }, | 400 | }, |
| 384 | } | 401 | } |
| 385 | }; | 402 | }; |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 45892dc4b72a..f65e5b521dbd 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
| @@ -608,6 +608,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) | |||
| 608 | unsigned len, type; | 608 | unsigned len, type; |
| 609 | struct perf_event *bp; | 609 | struct perf_event *bp; |
| 610 | 610 | ||
| 611 | if (ptrace_get_breakpoints(tsk) < 0) | ||
| 612 | return -ESRCH; | ||
| 613 | |||
| 611 | data &= ~DR_CONTROL_RESERVED; | 614 | data &= ~DR_CONTROL_RESERVED; |
| 612 | old_dr7 = ptrace_get_dr7(thread->ptrace_bps); | 615 | old_dr7 = ptrace_get_dr7(thread->ptrace_bps); |
| 613 | restore: | 616 | restore: |
| @@ -655,6 +658,9 @@ restore: | |||
| 655 | } | 658 | } |
| 656 | goto restore; | 659 | goto restore; |
| 657 | } | 660 | } |
| 661 | |||
| 662 | ptrace_put_breakpoints(tsk); | ||
| 663 | |||
| 658 | return ((orig_ret < 0) ? orig_ret : rc); | 664 | return ((orig_ret < 0) ? orig_ret : rc); |
| 659 | } | 665 | } |
| 660 | 666 | ||
| @@ -668,10 +674,17 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n) | |||
| 668 | 674 | ||
| 669 | if (n < HBP_NUM) { | 675 | if (n < HBP_NUM) { |
| 670 | struct perf_event *bp; | 676 | struct perf_event *bp; |
| 677 | |||
| 678 | if (ptrace_get_breakpoints(tsk) < 0) | ||
| 679 | return -ESRCH; | ||
| 680 | |||
| 671 | bp = thread->ptrace_bps[n]; | 681 | bp = thread->ptrace_bps[n]; |
| 672 | if (!bp) | 682 | if (!bp) |
| 673 | return 0; | 683 | val = 0; |
| 674 | val = bp->hw.info.address; | 684 | else |
| 685 | val = bp->hw.info.address; | ||
| 686 | |||
| 687 | ptrace_put_breakpoints(tsk); | ||
| 675 | } else if (n == 6) { | 688 | } else if (n == 6) { |
| 676 | val = thread->debugreg6; | 689 | val = thread->debugreg6; |
| 677 | } else if (n == 7) { | 690 | } else if (n == 7) { |
| @@ -686,6 +699,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, | |||
| 686 | struct perf_event *bp; | 699 | struct perf_event *bp; |
| 687 | struct thread_struct *t = &tsk->thread; | 700 | struct thread_struct *t = &tsk->thread; |
| 688 | struct perf_event_attr attr; | 701 | struct perf_event_attr attr; |
| 702 | int err = 0; | ||
| 703 | |||
| 704 | if (ptrace_get_breakpoints(tsk) < 0) | ||
| 705 | return -ESRCH; | ||
| 689 | 706 | ||
| 690 | if (!t->ptrace_bps[nr]) { | 707 | if (!t->ptrace_bps[nr]) { |
| 691 | ptrace_breakpoint_init(&attr); | 708 | ptrace_breakpoint_init(&attr); |
| @@ -709,24 +726,23 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, | |||
| 709 | * writing for the user. And anyway this is the previous | 726 | * writing for the user. And anyway this is the previous |
| 710 | * behaviour. | 727 | * behaviour. |
| 711 | */ | 728 | */ |
| 712 | if (IS_ERR(bp)) | 729 | if (IS_ERR(bp)) { |
| 713 | return PTR_ERR(bp); | 730 | err = PTR_ERR(bp); |
| 731 | goto put; | ||
| 732 | } | ||
| 714 | 733 | ||
| 715 | t->ptrace_bps[nr] = bp; | 734 | t->ptrace_bps[nr] = bp; |
| 716 | } else { | 735 | } else { |
| 717 | int err; | ||
| 718 | |||
| 719 | bp = t->ptrace_bps[nr]; | 736 | bp = t->ptrace_bps[nr]; |
| 720 | 737 | ||
| 721 | attr = bp->attr; | 738 | attr = bp->attr; |
| 722 | attr.bp_addr = addr; | 739 | attr.bp_addr = addr; |
| 723 | err = modify_user_hw_breakpoint(bp, &attr); | 740 | err = modify_user_hw_breakpoint(bp, &attr); |
| 724 | if (err) | ||
| 725 | return err; | ||
| 726 | } | 741 | } |
| 727 | 742 | ||
| 728 | 743 | put: | |
| 729 | return 0; | 744 | ptrace_put_breakpoints(tsk); |
| 745 | return err; | ||
| 730 | } | 746 | } |
| 731 | 747 | ||
| 732 | /* | 748 | /* |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index a1147e5dd245..9178d5cc0b01 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
| @@ -189,6 +189,10 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) | |||
| 189 | child->ptrace = current->ptrace; | 189 | child->ptrace = current->ptrace; |
| 190 | __ptrace_link(child, current->parent); | 190 | __ptrace_link(child, current->parent); |
| 191 | } | 191 | } |
| 192 | |||
| 193 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 194 | atomic_set(&child->ptrace_bp_refcnt, 1); | ||
| 195 | #endif | ||
| 192 | } | 196 | } |
| 193 | 197 | ||
| 194 | /** | 198 | /** |
| @@ -350,6 +354,13 @@ extern int task_current_syscall(struct task_struct *target, long *callno, | |||
| 350 | unsigned long args[6], unsigned int maxargs, | 354 | unsigned long args[6], unsigned int maxargs, |
| 351 | unsigned long *sp, unsigned long *pc); | 355 | unsigned long *sp, unsigned long *pc); |
| 352 | 356 | ||
| 353 | #endif | 357 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
| 358 | extern int ptrace_get_breakpoints(struct task_struct *tsk); | ||
| 359 | extern void ptrace_put_breakpoints(struct task_struct *tsk); | ||
| 360 | #else | ||
| 361 | static inline void ptrace_put_breakpoints(struct task_struct *tsk) { } | ||
| 362 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||
| 363 | |||
| 364 | #endif /* __KERNEL */ | ||
| 354 | 365 | ||
| 355 | #endif | 366 | #endif |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 18d63cea2848..781abd137673 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1537,6 +1537,9 @@ struct task_struct { | |||
| 1537 | unsigned long memsw_nr_pages; /* uncharged mem+swap usage */ | 1537 | unsigned long memsw_nr_pages; /* uncharged mem+swap usage */ |
| 1538 | } memcg_batch; | 1538 | } memcg_batch; |
| 1539 | #endif | 1539 | #endif |
| 1540 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 1541 | atomic_t ptrace_bp_refcnt; | ||
| 1542 | #endif | ||
| 1540 | }; | 1543 | }; |
| 1541 | 1544 | ||
| 1542 | /* Future-safe accessor for struct task_struct's cpus_allowed. */ | 1545 | /* Future-safe accessor for struct task_struct's cpus_allowed. */ |
diff --git a/kernel/exit.c b/kernel/exit.c index f5d2f63bae0b..8dd874181542 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -1016,7 +1016,7 @@ NORET_TYPE void do_exit(long code) | |||
| 1016 | /* | 1016 | /* |
| 1017 | * FIXME: do that only when needed, using sched_exit tracepoint | 1017 | * FIXME: do that only when needed, using sched_exit tracepoint |
| 1018 | */ | 1018 | */ |
| 1019 | flush_ptrace_hw_breakpoint(tsk); | 1019 | ptrace_put_breakpoints(tsk); |
| 1020 | 1020 | ||
| 1021 | exit_notify(tsk, group_dead); | 1021 | exit_notify(tsk, group_dead); |
| 1022 | #ifdef CONFIG_NUMA | 1022 | #ifdef CONFIG_NUMA |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 0fc1eed28d27..dc7ab65f3b36 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/syscalls.h> | 22 | #include <linux/syscalls.h> |
| 23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
| 24 | #include <linux/regset.h> | 24 | #include <linux/regset.h> |
| 25 | #include <linux/hw_breakpoint.h> | ||
| 25 | 26 | ||
| 26 | 27 | ||
| 27 | /* | 28 | /* |
| @@ -879,3 +880,19 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, | |||
| 879 | return ret; | 880 | return ret; |
| 880 | } | 881 | } |
| 881 | #endif /* CONFIG_COMPAT */ | 882 | #endif /* CONFIG_COMPAT */ |
| 883 | |||
| 884 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 885 | int ptrace_get_breakpoints(struct task_struct *tsk) | ||
| 886 | { | ||
| 887 | if (atomic_inc_not_zero(&tsk->ptrace_bp_refcnt)) | ||
| 888 | return 0; | ||
| 889 | |||
| 890 | return -1; | ||
| 891 | } | ||
| 892 | |||
| 893 | void ptrace_put_breakpoints(struct task_struct *tsk) | ||
| 894 | { | ||
| 895 | if (atomic_dec_and_test(&tsk->ptrace_bp_refcnt)) | ||
| 896 | flush_ptrace_hw_breakpoint(tsk); | ||
| 897 | } | ||
| 898 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 207dee5c5b16..0c542563ea6c 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -35,15 +35,21 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | |||
| 35 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | 35 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ |
| 36 | -e s/sh[234].*/sh/ ) | 36 | -e s/sh[234].*/sh/ ) |
| 37 | 37 | ||
| 38 | CC = $(CROSS_COMPILE)gcc | ||
| 39 | AR = $(CROSS_COMPILE)ar | ||
| 40 | |||
| 38 | # Additional ARCH settings for x86 | 41 | # Additional ARCH settings for x86 |
| 39 | ifeq ($(ARCH),i386) | 42 | ifeq ($(ARCH),i386) |
| 40 | ARCH := x86 | 43 | ARCH := x86 |
| 41 | endif | 44 | endif |
| 42 | ifeq ($(ARCH),x86_64) | 45 | ifeq ($(ARCH),x86_64) |
| 43 | RAW_ARCH := x86_64 | 46 | ARCH := x86 |
| 44 | ARCH := x86 | 47 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1) |
| 45 | ARCH_CFLAGS := -DARCH_X86_64 | 48 | ifeq (${IS_X86_64}, 1) |
| 46 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S | 49 | RAW_ARCH := x86_64 |
| 50 | ARCH_CFLAGS := -DARCH_X86_64 | ||
| 51 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S | ||
| 52 | endif | ||
| 47 | endif | 53 | endif |
| 48 | 54 | ||
| 49 | # | 55 | # |
| @@ -119,8 +125,6 @@ lib = lib | |||
| 119 | 125 | ||
| 120 | export prefix bindir sharedir sysconfdir | 126 | export prefix bindir sharedir sysconfdir |
| 121 | 127 | ||
| 122 | CC = $(CROSS_COMPILE)gcc | ||
| 123 | AR = $(CROSS_COMPILE)ar | ||
| 124 | RM = rm -f | 128 | RM = rm -f |
| 125 | MKDIR = mkdir | 129 | MKDIR = mkdir |
| 126 | FIND = find | 130 | FIND = find |
