Commit 869f96a0 authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[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: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7e06066b
...@@ -199,6 +199,18 @@ static inline int is_prefetch(struct pt_regs *regs, unsigned long addr, ...@@ -199,6 +199,18 @@ static inline int is_prefetch(struct pt_regs *regs, unsigned long addr,
return 0; return 0;
} }
static noinline void force_sig_info_fault(int si_signo, int si_code,
unsigned long address, struct task_struct *tsk)
{
siginfo_t info;
info.si_signo = si_signo;
info.si_errno = 0;
info.si_code = si_code;
info.si_addr = (void __user *)address;
force_sig_info(si_signo, &info, tsk);
}
fastcall void do_invalid_op(struct pt_regs *, unsigned long); fastcall void do_invalid_op(struct pt_regs *, unsigned long);
/* /*
...@@ -218,8 +230,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -218,8 +230,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
struct vm_area_struct * vma; struct vm_area_struct * vma;
unsigned long address; unsigned long address;
unsigned long page; unsigned long page;
int write; int write, si_code;
siginfo_t info;
/* get the address */ /* get the address */
__asm__("movl %%cr2,%0":"=r" (address)); __asm__("movl %%cr2,%0":"=r" (address));
...@@ -233,7 +244,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -233,7 +244,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
tsk = current; tsk = current;
info.si_code = SEGV_MAPERR; si_code = SEGV_MAPERR;
/* /*
* We fault-in kernel-space virtual memory on-demand. The * 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,7 +324,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
* we can handle it.. * we can handle it..
*/ */
good_area: good_area:
info.si_code = SEGV_ACCERR; si_code = SEGV_ACCERR;
write = 0; write = 0;
switch (error_code & 3) { switch (error_code & 3) {
default: /* 3: write, present */ default: /* 3: write, present */
...@@ -387,11 +398,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -387,11 +398,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
/* Kernel addresses are always protection faults */ /* Kernel addresses are always protection faults */
tsk->thread.error_code = error_code | (address >= TASK_SIZE); tsk->thread.error_code = error_code | (address >= TASK_SIZE);
tsk->thread.trap_no = 14; tsk->thread.trap_no = 14;
info.si_signo = SIGSEGV; force_sig_info_fault(SIGSEGV, si_code, address, tsk);
info.si_errno = 0;
/* info.si_code has been set above */
info.si_addr = (void __user *)address;
force_sig_info(SIGSEGV, &info, tsk);
return; return;
} }
...@@ -500,11 +507,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -500,11 +507,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
tsk->thread.cr2 = address; tsk->thread.cr2 = address;
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
tsk->thread.trap_no = 14; tsk->thread.trap_no = 14;
info.si_signo = SIGBUS; force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
info.si_errno = 0;
info.si_code = BUS_ADRERR;
info.si_addr = (void __user *)address;
force_sig_info(SIGBUS, &info, tsk);
return; return;
vmalloc_fault: vmalloc_fault:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment