Commit 21f585073d6347651f2262da187606fa1c4ee16d
Committed by
Benjamin Herrenschmidt
1 parent
04c32a5168
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
powerpc: Fix smp_processor_id() in preemptible splat in set_breakpoint
Currently, on 8641D, which doesn't set CONFIG_HAVE_HW_BREAKPOINT we get the following splat: BUG: using smp_processor_id() in preemptible [00000000] code: login/1382 caller is set_breakpoint+0x1c/0xa0 CPU: 0 PID: 1382 Comm: login Not tainted 3.15.0-rc3-00041-g2aafe1a4d451 #1 Call Trace: [decd5d80] [c0008dc4] show_stack+0x50/0x158 (unreliable) [decd5dc0] [c03c6fa0] dump_stack+0x7c/0xdc [decd5de0] [c01f8818] check_preemption_disabled+0xf4/0x104 [decd5e00] [c00086b8] set_breakpoint+0x1c/0xa0 [decd5e10] [c00d4530] flush_old_exec+0x2bc/0x588 [decd5e40] [c011c468] load_elf_binary+0x2ac/0x1164 [decd5ec0] [c00d35f8] search_binary_handler+0xc4/0x1f8 [decd5ef0] [c00d4ee8] do_execve+0x3d8/0x4b8 [decd5f40] [c001185c] ret_from_syscall+0x0/0x38 --- Exception: c01 at 0xfeee554 LR = 0xfeee7d4 The call path in this case is: flush_thread --> set_debug_reg_defaults --> set_breakpoint --> __get_cpu_var Since preemption is enabled in the cleanup of flush thread, and there is no need to disable it, introduce the distinction between set_breakpoint and __set_breakpoint, leaving only the flush_thread instance as the current user of set_breakpoint. Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Showing 6 changed files with 17 additions and 9 deletions Side-by-side Diff
arch/powerpc/include/asm/debug.h
... | ... | @@ -47,6 +47,7 @@ |
47 | 47 | #endif |
48 | 48 | |
49 | 49 | void set_breakpoint(struct arch_hw_breakpoint *brk); |
50 | +void __set_breakpoint(struct arch_hw_breakpoint *brk); | |
50 | 51 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
51 | 52 | extern void do_send_trap(struct pt_regs *regs, unsigned long address, |
52 | 53 | unsigned long error_code, int signal_code, int brkpt); |
arch/powerpc/include/asm/hw_breakpoint.h
arch/powerpc/kernel/hw_breakpoint.c
... | ... | @@ -72,7 +72,7 @@ |
72 | 72 | * If so, DABR will be populated in single_step_dabr_instruction(). |
73 | 73 | */ |
74 | 74 | if (current->thread.last_hit_ubp != bp) |
75 | - set_breakpoint(info); | |
75 | + __set_breakpoint(info); | |
76 | 76 | |
77 | 77 | return 0; |
78 | 78 | } |
... | ... | @@ -198,7 +198,7 @@ |
198 | 198 | |
199 | 199 | info = counter_arch_bp(tsk->thread.last_hit_ubp); |
200 | 200 | regs->msr &= ~MSR_SE; |
201 | - set_breakpoint(info); | |
201 | + __set_breakpoint(info); | |
202 | 202 | tsk->thread.last_hit_ubp = NULL; |
203 | 203 | } |
204 | 204 | |
... | ... | @@ -284,7 +284,7 @@ |
284 | 284 | if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ)) |
285 | 285 | perf_bp_event(bp, regs); |
286 | 286 | |
287 | - set_breakpoint(info); | |
287 | + __set_breakpoint(info); | |
288 | 288 | out: |
289 | 289 | rcu_read_unlock(); |
290 | 290 | return rc; |
... | ... | @@ -316,7 +316,7 @@ |
316 | 316 | if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ)) |
317 | 317 | perf_bp_event(bp, regs); |
318 | 318 | |
319 | - set_breakpoint(info); | |
319 | + __set_breakpoint(info); | |
320 | 320 | current->thread.last_hit_ubp = NULL; |
321 | 321 | |
322 | 322 | /* |
arch/powerpc/kernel/process.c
... | ... | @@ -496,7 +496,7 @@ |
496 | 496 | return 0; |
497 | 497 | } |
498 | 498 | |
499 | -void set_breakpoint(struct arch_hw_breakpoint *brk) | |
499 | +void __set_breakpoint(struct arch_hw_breakpoint *brk) | |
500 | 500 | { |
501 | 501 | __get_cpu_var(current_brk) = *brk; |
502 | 502 | |
... | ... | @@ -506,6 +506,13 @@ |
506 | 506 | set_dabr(brk); |
507 | 507 | } |
508 | 508 | |
509 | +void set_breakpoint(struct arch_hw_breakpoint *brk) | |
510 | +{ | |
511 | + preempt_disable(); | |
512 | + __set_breakpoint(brk); | |
513 | + preempt_enable(); | |
514 | +} | |
515 | + | |
509 | 516 | #ifdef CONFIG_PPC64 |
510 | 517 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); |
511 | 518 | #endif |
... | ... | @@ -835,7 +842,7 @@ |
835 | 842 | */ |
836 | 843 | #ifndef CONFIG_HAVE_HW_BREAKPOINT |
837 | 844 | if (unlikely(!hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk))) |
838 | - set_breakpoint(&new->thread.hw_brk); | |
845 | + __set_breakpoint(&new->thread.hw_brk); | |
839 | 846 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
840 | 847 | #endif |
841 | 848 |
arch/powerpc/kernel/signal.c
... | ... | @@ -134,7 +134,7 @@ |
134 | 134 | */ |
135 | 135 | if (current->thread.hw_brk.address && |
136 | 136 | current->thread.hw_brk.type) |
137 | - set_breakpoint(¤t->thread.hw_brk); | |
137 | + __set_breakpoint(¤t->thread.hw_brk); | |
138 | 138 | #endif |
139 | 139 | /* Re-enable the breakpoints for the signal stack */ |
140 | 140 | thread_change_pc(current, regs); |
arch/powerpc/xmon/xmon.c
... | ... | @@ -759,7 +759,7 @@ |
759 | 759 | brk.address = dabr.address; |
760 | 760 | brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL; |
761 | 761 | brk.len = 8; |
762 | - set_breakpoint(&brk); | |
762 | + __set_breakpoint(&brk); | |
763 | 763 | } |
764 | 764 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) |
765 | 765 | mtspr(SPRN_IABR, iabr->address |