diff options
author | Ingo Molnar <mingo@elte.hu> | 2005-09-03 18:56:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-05 03:06:09 -0400 |
commit | 869f96a00e8f53c7db8470ca9cf72e2e3fa40119 (patch) | |
tree | e28e526eb0e9d304d79dab3a20c944959a6ee38e /arch/i386/mm/fault.c | |
parent | 7e06066b87ffd2c7a7f4c3f1c612293307270976 (diff) |
[PATCH] x86: compress the stack layout of do_page_fault()
This patch pushes the creation of a rare signal frame (SIGBUS or SIGSEGV)
into a separate function, thus saving stackspace in the main
do_page_fault() stackframe. The effect is 132 bytes less of stack used by
the typical do_page_fault() invocation - resulting in a denser
cache-layout.
(Another minor effect is that in case of kernel crashes that come from a
pagefault, we add less space to the already existing frame, giving the
crash functions a slightly higher chance to do their stuff without
overflowing the stack.)
(The changes also result in slightly cleaner code.)
argument bugfix from "Guillaume C." <guichaz@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/mm/fault.c')
-rw-r--r-- | arch/i386/mm/fault.c | 31 |
1 files changed, 17 insertions, 14 deletions
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 8e90339d6eaa..61d9e34af5a6 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c | |||
@@ -199,6 +199,18 @@ static inline int is_prefetch(struct pt_regs *regs, unsigned long addr, | |||
199 | return 0; | 199 | return 0; |
200 | } | 200 | } |
201 | 201 | ||
202 | static noinline void force_sig_info_fault(int si_signo, int si_code, | ||
203 | unsigned long address, struct task_struct *tsk) | ||
204 | { | ||
205 | siginfo_t info; | ||
206 | |||
207 | info.si_signo = si_signo; | ||
208 | info.si_errno = 0; | ||
209 | info.si_code = si_code; | ||
210 | info.si_addr = (void __user *)address; | ||
211 | force_sig_info(si_signo, &info, tsk); | ||
212 | } | ||
213 | |||
202 | fastcall void do_invalid_op(struct pt_regs *, unsigned long); | 214 | fastcall void do_invalid_op(struct pt_regs *, unsigned long); |
203 | 215 | ||
204 | /* | 216 | /* |
@@ -218,8 +230,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
218 | struct vm_area_struct * vma; | 230 | struct vm_area_struct * vma; |
219 | unsigned long address; | 231 | unsigned long address; |
220 | unsigned long page; | 232 | unsigned long page; |
221 | int write; | 233 | int write, si_code; |
222 | siginfo_t info; | ||
223 | 234 | ||
224 | /* get the address */ | 235 | /* get the address */ |
225 | __asm__("movl %%cr2,%0":"=r" (address)); | 236 | __asm__("movl %%cr2,%0":"=r" (address)); |
@@ -233,7 +244,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
233 | 244 | ||
234 | tsk = current; | 245 | tsk = current; |
235 | 246 | ||
236 | info.si_code = SEGV_MAPERR; | 247 | si_code = SEGV_MAPERR; |
237 | 248 | ||
238 | /* | 249 | /* |
239 | * We fault-in kernel-space virtual memory on-demand. The | 250 | * We fault-in kernel-space virtual memory on-demand. The |
@@ -313,7 +324,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
313 | * we can handle it.. | 324 | * we can handle it.. |
314 | */ | 325 | */ |
315 | good_area: | 326 | good_area: |
316 | info.si_code = SEGV_ACCERR; | 327 | si_code = SEGV_ACCERR; |
317 | write = 0; | 328 | write = 0; |
318 | switch (error_code & 3) { | 329 | switch (error_code & 3) { |
319 | default: /* 3: write, present */ | 330 | default: /* 3: write, present */ |
@@ -387,11 +398,7 @@ bad_area_nosemaphore: | |||
387 | /* Kernel addresses are always protection faults */ | 398 | /* Kernel addresses are always protection faults */ |
388 | tsk->thread.error_code = error_code | (address >= TASK_SIZE); | 399 | tsk->thread.error_code = error_code | (address >= TASK_SIZE); |
389 | tsk->thread.trap_no = 14; | 400 | tsk->thread.trap_no = 14; |
390 | info.si_signo = SIGSEGV; | 401 | force_sig_info_fault(SIGSEGV, si_code, address, tsk); |
391 | info.si_errno = 0; | ||
392 | /* info.si_code has been set above */ | ||
393 | info.si_addr = (void __user *)address; | ||
394 | force_sig_info(SIGSEGV, &info, tsk); | ||
395 | return; | 402 | return; |
396 | } | 403 | } |
397 | 404 | ||
@@ -500,11 +507,7 @@ do_sigbus: | |||
500 | tsk->thread.cr2 = address; | 507 | tsk->thread.cr2 = address; |
501 | tsk->thread.error_code = error_code; | 508 | tsk->thread.error_code = error_code; |
502 | tsk->thread.trap_no = 14; | 509 | tsk->thread.trap_no = 14; |
503 | info.si_signo = SIGBUS; | 510 | force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); |
504 | info.si_errno = 0; | ||
505 | info.si_code = BUS_ADRERR; | ||
506 | info.si_addr = (void __user *)address; | ||
507 | force_sig_info(SIGBUS, &info, tsk); | ||
508 | return; | 511 | return; |
509 | 512 | ||
510 | vmalloc_fault: | 513 | vmalloc_fault: |