[PATCH] uml: stack usage reduction

The KSTK_* macros used an inordinate amount of stack. In order to overcome
an impedance mismatch between their interface, which just returns a single
register value, and the interface of get_thread_regs, which took a full
pt_regs, the implementation created an on-stack pt_regs, filled it in, and
returned one field. do_task_stat calls KSTK_* twice, resulting in two
local pt_regs, blowing out the stack.

This patch changes the interface (and name) of get_thread_regs to just
return a single register from a jmp_buf.

The include of archsetjmp.h" in registers.h to get the definition of
jmp_buf exposed a bogus include of <setjmp.h> in start_up.c. <setjmp.h>
shouldn't be used anywhere any more since UML uses the klibc
setjmp/longjmp.

Signed-off-by: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Jeff Dike and committed by
Linus Torvalds
75e29b18 bf61f50d

+21 -17
+2 -1
arch/um/include/registers.h
··· 7 7 #define __REGISTERS_H 8 8 9 9 #include "sysdep/ptrace.h" 10 + #include "sysdep/archsetjmp.h" 10 11 11 12 extern void init_thread_registers(union uml_pt_regs *to); 12 13 extern int save_fp_registers(int pid, unsigned long *fp_regs); ··· 16 15 extern void restore_registers(int pid, union uml_pt_regs *regs); 17 16 extern void init_registers(int pid); 18 17 extern void get_safe_registers(unsigned long * regs, unsigned long * fp_regs); 19 - extern void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer); 18 + extern unsigned long get_thread_reg(int reg, jmp_buf *buf); 20 19 21 20 #endif
-1
arch/um/os-Linux/start_up.c
··· 14 14 #include <sched.h> 15 15 #include <fcntl.h> 16 16 #include <errno.h> 17 - #include <setjmp.h> 18 17 #include <sys/time.h> 19 18 #include <sys/wait.h> 20 19 #include <sys/mman.h>
+9 -6
arch/um/os-Linux/sys-i386/registers.c
··· 130 130 HOST_FP_SIZE * sizeof(unsigned long)); 131 131 } 132 132 133 - void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) 133 + unsigned long get_thread_reg(int reg, jmp_buf *buf) 134 134 { 135 - struct __jmp_buf *jmpbuf = buffer; 136 - 137 - UPT_SET(uml_regs, EIP, jmpbuf->__eip); 138 - UPT_SET(uml_regs, UESP, jmpbuf->__esp); 139 - UPT_SET(uml_regs, EBP, jmpbuf->__ebp); 135 + switch(reg){ 136 + case EIP: return buf[0]->__eip; 137 + case UESP: return buf[0]->__esp; 138 + case EBP: return buf[0]->__ebp; 139 + default: 140 + printk("get_thread_regs - unknown register %d\n", reg); 141 + return 0; 142 + } 140 143 }
+9 -6
arch/um/os-Linux/sys-x86_64/registers.c
··· 78 78 HOST_FP_SIZE * sizeof(unsigned long)); 79 79 } 80 80 81 - void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) 81 + unsigned long get_thread_reg(int reg, jmp_buf *buf) 82 82 { 83 - struct __jmp_buf *jmpbuf = buffer; 84 - 85 - UPT_SET(uml_regs, RIP, jmpbuf->__rip); 86 - UPT_SET(uml_regs, RSP, jmpbuf->__rsp); 87 - UPT_SET(uml_regs, RBP, jmpbuf->__rbp); 83 + switch(reg){ 84 + case RIP: return buf[0]->__rip; 85 + case RSP: return buf[0]->__rsp; 86 + case RBP: return buf[0]->__rbp; 87 + default: 88 + printk("get_thread_regs - unknown register %d\n", reg); 89 + return 0; 90 + } 88 91 }
+1 -3
include/asm-um/processor-generic.h
··· 138 138 139 139 #ifdef CONFIG_MODE_SKAS 140 140 #define KSTK_REG(tsk, reg) \ 141 - ({ union uml_pt_regs regs; \ 142 - get_thread_regs(&regs, tsk->thread.mode.skas.switch_buf); \ 143 - UPT_REG(&regs, reg); }) 141 + get_thread_reg(reg, tsk->thread.mode.skas.switch_buf) 144 142 #else 145 143 #define KSTK_REG(tsk, reg) (0xbadbabe) 146 144 #endif