Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Ingo Molnar and committed by
Linus Torvalds
869f96a0 7e06066b

+17 -14
+17 -14
arch/i386/mm/fault.c
··· 199 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 214 fastcall void do_invalid_op(struct pt_regs *, unsigned long); 203 215 204 216 /* ··· 230 218 struct vm_area_struct * vma; 231 219 unsigned long address; 232 220 unsigned long page; 233 - int write; 234 - siginfo_t info; 221 + int write, si_code; 235 222 236 223 /* get the address */ 237 224 __asm__("movl %%cr2,%0":"=r" (address)); ··· 244 233 245 234 tsk = current; 246 235 247 - info.si_code = SEGV_MAPERR; 236 + si_code = SEGV_MAPERR; 248 237 249 238 /* 250 239 * We fault-in kernel-space virtual memory on-demand. The ··· 324 313 * we can handle it.. 325 314 */ 326 315 good_area: 327 - info.si_code = SEGV_ACCERR; 316 + si_code = SEGV_ACCERR; 328 317 write = 0; 329 318 switch (error_code & 3) { 330 319 default: /* 3: write, present */ ··· 398 387 /* Kernel addresses are always protection faults */ 399 388 tsk->thread.error_code = error_code | (address >= TASK_SIZE); 400 389 tsk->thread.trap_no = 14; 401 - info.si_signo = SIGSEGV; 402 - info.si_errno = 0; 403 - /* info.si_code has been set above */ 404 - info.si_addr = (void __user *)address; 405 - force_sig_info(SIGSEGV, &info, tsk); 390 + force_sig_info_fault(SIGSEGV, si_code, address, tsk); 406 391 return; 407 392 } 408 393 ··· 507 500 tsk->thread.cr2 = address; 508 501 tsk->thread.error_code = error_code; 509 502 tsk->thread.trap_no = 14; 510 - info.si_signo = SIGBUS; 511 - info.si_errno = 0; 512 - info.si_code = BUS_ADRERR; 513 - info.si_addr = (void __user *)address; 514 - force_sig_info(SIGBUS, &info, tsk); 503 + force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); 515 504 return; 516 505 517 506 vmalloc_fault: