diff options
author | Stuart Menefy <stuart.menefy@st.com> | 2008-07-02 04:51:23 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-07-28 05:10:33 -0400 |
commit | f2fb4e4f647dabf1177d3ce164988e73482d76b1 (patch) | |
tree | 5288184d2d8535c826c8b3c33d79b2529c83542b /arch | |
parent | 068f59143d821553e7a55cdbd69142b05e245d47 (diff) |
sh: Conditionally re-enable IRQs in fault path.
The current kernel behaviour is to reenable interrupts unconditionally
when taking a page fault. This patch changes this to only enable them
if interrupts were previously enabled.
It also fixes a problem seen with this fix in place: the kernel previously
flushed the vsyscall page when handling a signal, which is not only
unncessary, but caused a possible sleep with interrupts disabled.
Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sh/kernel/signal_32.c | 3 | ||||
-rw-r--r-- | arch/sh/mm/fault_32.c | 12 |
2 files changed, 9 insertions, 6 deletions
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index eee29257a8ae..4bbbde895a53 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
@@ -373,6 +373,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
373 | err |= __put_user(OR_R0_R0, &frame->retcode[6]); | 373 | err |= __put_user(OR_R0_R0, &frame->retcode[6]); |
374 | err |= __put_user((__NR_sigreturn), &frame->retcode[7]); | 374 | err |= __put_user((__NR_sigreturn), &frame->retcode[7]); |
375 | regs->pr = (unsigned long) frame->retcode; | 375 | regs->pr = (unsigned long) frame->retcode; |
376 | flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode)); | ||
376 | } | 377 | } |
377 | 378 | ||
378 | if (err) | 379 | if (err) |
@@ -398,8 +399,6 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
398 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 399 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
399 | current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); | 400 | current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); |
400 | 401 | ||
401 | flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode)); | ||
402 | |||
403 | return 0; | 402 | return 0; |
404 | 403 | ||
405 | give_sigsegv: | 404 | give_sigsegv: |
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index d1fa27594c6e..0c776fdfbdda 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c | |||
@@ -37,16 +37,12 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, | |||
37 | int fault; | 37 | int fault; |
38 | siginfo_t info; | 38 | siginfo_t info; |
39 | 39 | ||
40 | trace_hardirqs_on(); | ||
41 | local_irq_enable(); | ||
42 | |||
43 | #ifdef CONFIG_SH_KGDB | 40 | #ifdef CONFIG_SH_KGDB |
44 | if (kgdb_nofault && kgdb_bus_err_hook) | 41 | if (kgdb_nofault && kgdb_bus_err_hook) |
45 | kgdb_bus_err_hook(); | 42 | kgdb_bus_err_hook(); |
46 | #endif | 43 | #endif |
47 | 44 | ||
48 | tsk = current; | 45 | tsk = current; |
49 | mm = tsk->mm; | ||
50 | si_code = SEGV_MAPERR; | 46 | si_code = SEGV_MAPERR; |
51 | 47 | ||
52 | if (unlikely(address >= TASK_SIZE)) { | 48 | if (unlikely(address >= TASK_SIZE)) { |
@@ -88,6 +84,14 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, | |||
88 | return; | 84 | return; |
89 | } | 85 | } |
90 | 86 | ||
87 | /* Only enable interrupts if they were on before the fault */ | ||
88 | if ((regs->sr & SR_IMASK) != SR_IMASK) { | ||
89 | trace_hardirqs_on(); | ||
90 | local_irq_enable(); | ||
91 | } | ||
92 | |||
93 | mm = tsk->mm; | ||
94 | |||
91 | /* | 95 | /* |
92 | * If we're in an interrupt or have no user | 96 | * If we're in an interrupt or have no user |
93 | * context, we must not take the fault.. | 97 | * context, we must not take the fault.. |