Skip to contentSkip to conversation

compress the stack layout of do_page_fault(), x86

PATCH In review Ingo Molnar 3 participants 5 messages Jul 9, 2005 – Jul 10, 2005

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 compress the stack layout of do_page_fault(), x86

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.)

build and boot tested.

Ingo

arch/i386/mm/fault.c +18 -15
Index: linux/arch/i386/mm/fault.c
===================================================================
@@ -201,6 +201,18 @@ static inline int is_prefetch(struct pt_
 	return 0;
 } 
 
+static void force_sig_info_fault(int si_signo, int si_code,
+				 unsigned long address, struct task_struct *tsk)
+{
+	siginfo_t info;
+
+	info.si_signo = SIGSEGV;
+	info.si_errno = 0;
+	info.si_code = si_code;
+	info.si_addr = (void __user *)address;
+	force_sig_info(SIGSEGV, &info, tsk);
+}
+
 fastcall void do_invalid_op(struct pt_regs *, unsigned long);
 
 /*
@@ -220,9 +232,8 @@ fastcall notrace void do_page_fault(stru
 	struct vm_area_struct * vma;
 	unsigned long address;
 	unsigned long page;
-	int write;
-	siginfo_t info;
-
+	int write, si_code;
+	
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 	trace_special(regs->eip, error_code, address);
@@ -236,7 +247,7 @@ fastcall notrace void do_page_fault(stru
 
 	tsk = current;
 
-	info.si_code = SEGV_MAPERR;
+	si_code = SEGV_MAPERR;
 
 	/*
 	 * We fault-in kernel-space virtual memory on-demand. The
@@ -316,7 +327,7 @@ fastcall notrace void do_page_fault(stru
  * we can handle it..
  */
 good_area:
-	info.si_code = SEGV_ACCERR;
+	si_code = SEGV_ACCERR;
 	write = 0;
 	switch (error_code & 3) {
 		default:	/* 3: write, present */
@@ -390,11 +401,7 @@ bad_area_nosemaphore:
 		/* Kernel addresses are always protection faults */
 		tsk->thread.error_code = error_code | (address >= TASK_SIZE);
 		tsk->thread.trap_no = 14;
-		info.si_signo = SIGSEGV;
-		info.si_errno = 0;
-		/* info.si_code has been set above */
-		info.si_addr = (void __user *)address;
-		force_sig_info(SIGSEGV, &info, tsk);
+		force_sig_info_fault(SIGSEGV, si_code, address, tsk);
 		return;
 	}
 
@@ -500,11 +507,7 @@ do_sigbus:
 	tsk->thread.cr2 = address;
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = 14;
-	info.si_signo = SIGBUS;
-	info.si_errno = 0;
-	info.si_code = BUS_ADRERR;
-	info.si_addr = (void __user *)address;
-	force_sig_info(SIGBUS, &info, tsk);
+	force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
 	return;
 
 vmalloc_fault:
#1 lore raw

Guillaume noticed a bug in the patch, si_signo should be used instead of SIGSEGV. (doh) New patch below.

Ingo

-----

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.)

build and boot tested.

argument bugfix from "Guillaume C." <[email protected]>

arch/i386/mm/fault.c +18 -15
Index: linux/arch/i386/mm/fault.c
===================================================================
@@ -201,6 +201,18 @@ static inline int is_prefetch(struct pt_
 	return 0;
 } 
 
+static 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);
 
 /*
@@ -220,9 +232,8 @@ fastcall notrace void do_page_fault(stru
 	struct vm_area_struct * vma;
 	unsigned long address;
 	unsigned long page;
-	int write;
-	siginfo_t info;
-
+	int write, si_code;
+	
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 	trace_special(regs->eip, error_code, address);
@@ -236,7 +247,7 @@ fastcall notrace void do_page_fault(stru
 
 	tsk = current;
 
-	info.si_code = SEGV_MAPERR;
+	si_code = SEGV_MAPERR;
 
 	/*
 	 * We fault-in kernel-space virtual memory on-demand. The
@@ -316,7 +327,7 @@ fastcall notrace void do_page_fault(stru
  * we can handle it..
  */
 good_area:
-	info.si_code = SEGV_ACCERR;
+	si_code = SEGV_ACCERR;
 	write = 0;
 	switch (error_code & 3) {
 		default:	/* 3: write, present */
@@ -390,11 +401,7 @@ bad_area_nosemaphore:
 		/* Kernel addresses are always protection faults */
 		tsk->thread.error_code = error_code | (address >= TASK_SIZE);
 		tsk->thread.trap_no = 14;
-		info.si_signo = SIGSEGV;
-		info.si_errno = 0;
-		/* info.si_code has been set above */
-		info.si_addr = (void __user *)address;
-		force_sig_info(SIGSEGV, &info, tsk);
+		force_sig_info_fault(SIGSEGV, si_code, address, tsk);
 		return;
 	}
 
@@ -500,11 +507,7 @@ do_sigbus:
 	tsk->thread.cr2 = address;
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = 14;
-	info.si_signo = SIGBUS;
-	info.si_errno = 0;
-	info.si_code = BUS_ADRERR;
-	info.si_addr = (void __user *)address;
-	force_sig_info(SIGBUS, &info, tsk);
+	force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
 	return;
 
 vmalloc_fault:
#2 lore raw

On Sat, 9 Jul 2005 17:29:24 +0200 Ingo Molnar wrote:

| 
| Guillaume noticed a bug in the patch, si_signo should be used instead of 
| SIGSEGV. (doh) New patch below.
| 
| 	Ingo
| 
| -----
| 
| 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.)
| 
| build and boot tested.

Hi Ingo-

Just to clarify this, "boot tested" does not mean that this changed code was tested, right?
or do you have a test case that was tested?

Thanks,
---
~Randy

#3 lore raw
Quoted 2 lines · randy_dunlap

Just to clarify this, "boot tested" does not mean that this changed code was tested, right? or do you have a test case that was tested?

i tested segfaults, but not bus-faults. The bug would have resulted in sigsegv being delivered not a sigbus.

Ingo

#4 lore raw
In reply to Ingo Molnar
Quoted 5 lines · Ingo Molnar

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.

does the benefit actually show up anywhere?