aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStuart Menefy <stuart.menefy@st.com>2008-07-02 04:51:23 -0400
committerPaul Mundt <lethal@linux-sh.org>2008-07-28 05:10:33 -0400
commitf2fb4e4f647dabf1177d3ce164988e73482d76b1 (patch)
tree5288184d2d8535c826c8b3c33d79b2529c83542b
parent068f59143d821553e7a55cdbd69142b05e245d47 (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>
-rw-r--r--arch/sh/kernel/signal_32.c3
-rw-r--r--arch/sh/mm/fault_32.c12
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
405give_sigsegv: 404give_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..