diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-03-07 00:48:45 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-03-08 18:55:08 -0500 |
commit | a546498f3bf9aac311c66f965186373aee2ca0b0 (patch) | |
tree | 86fb9a778aba26df3810acd8e52a921a2d84489b /arch/powerpc/mm/fault.c | |
parent | 1b70117924a4f254840ed70fbe3020d4519a1a9a (diff) |
powerpc: Call do_page_fault() with interrupts off
We currently turn interrupts back to their previous state before
calling do_page_fault(). This can be annoying when debugging as
a bad fault will potentially have lost some processor state before
getting into the debugger.
We also end up calling some generic code with interrupts enabled
such as notify_page_fault() with interrupts enabled, which could
be unexpected.
This changes our code to behave more like other architectures,
and make the assembly entry code call into do_page_faults() with
interrupts disabled. They are conditionally re-enabled from
within do_page_fault() in the same spot x86 does it.
While there, add the might_sleep() test in the case of a successful
trylock of the mmap semaphore, again like x86.
Also fix a bug in the existing assembly where r12 (_MSR) could get
clobbered by C calls (the DTL accounting in the exception common
macro and DISABLE_INTS) in some cases.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
v2. Add the r12 clobber fix
Diffstat (limited to 'arch/powerpc/mm/fault.c')
-rw-r--r-- | arch/powerpc/mm/fault.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 2f0d1b032a89..7e890065cf39 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -179,6 +179,10 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
179 | } | 179 | } |
180 | #endif | 180 | #endif |
181 | 181 | ||
182 | /* We restore the interrupt state now */ | ||
183 | if (!arch_irq_disabled_regs(regs)) | ||
184 | local_irq_enable(); | ||
185 | |||
182 | if (in_atomic() || mm == NULL) { | 186 | if (in_atomic() || mm == NULL) { |
183 | if (!user_mode(regs)) | 187 | if (!user_mode(regs)) |
184 | return SIGSEGV; | 188 | return SIGSEGV; |
@@ -213,6 +217,13 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
213 | goto bad_area_nosemaphore; | 217 | goto bad_area_nosemaphore; |
214 | 218 | ||
215 | down_read(&mm->mmap_sem); | 219 | down_read(&mm->mmap_sem); |
220 | } else { | ||
221 | /* | ||
222 | * The above down_read_trylock() might have succeeded in | ||
223 | * which case we'll have missed the might_sleep() from | ||
224 | * down_read(): | ||
225 | */ | ||
226 | might_sleep(); | ||
216 | } | 227 | } |
217 | 228 | ||
218 | vma = find_vma(mm, address); | 229 | vma = find_vma(mm, address); |