kernel - Move grow_stack code in fault path to improve fault performance
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 2 Mar 2010 00:09:41 +0000 (16:09 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 2 Mar 2010 00:09:41 +0000 (16:09 -0800)
* grow_stack() calls were being performed unconditionally during a
  page fault.  Shift the code over to vm_fault() and only run it if
  the vm_map_lookup() call fails.

* Also take this opportunity to remove trapwrite() (added by Matt).

Submitted-by: Venkatesh Srinivas <me@endeavour.zapto.org>
sys/emulation/linux/i386/linux_sysvec.c
sys/platform/pc32/i386/trap.c
sys/platform/pc32/i386/vm_machdep.c
sys/platform/pc64/x86_64/trap.c
sys/platform/pc64/x86_64/vm_machdep.c
sys/platform/vkernel/i386/trap.c
sys/platform/vkernel/i386/vm_machdep.c
sys/vm/vm_extern.h
sys/vm/vm_fault.c

index c136b4c..41a5a1a 100644 (file)
@@ -279,7 +279,7 @@ linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
         *      and the stack can not be grown. useracc will return FALSE
         *      if access is denied.
         */
-       if ((grow_stack (p, (int)fp) == FALSE) ||
+       if ((vm_map_growstack(p, (vm_offset_t)fp) != KERN_SUCCESS) ||
            !useracc((caddr_t)fp, sizeof (struct l_rt_sigframe), 
            VM_PROT_WRITE)) {
                /*
@@ -442,7 +442,7 @@ linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
         *      and the stack can not be grown. useracc will return FALSE
         *      if access is denied.
         */
-       if ((grow_stack (p, (int)fp) == FALSE) ||
+       if ((vm_map_growstack(p, (vm_offset_t)fp) != KERN_SUCCESS) ||
            !useracc((caddr_t)fp, sizeof (struct l_sigframe), 
            VM_PROT_WRITE)) {
                /*
index 194c627..bd6c3f5 100644 (file)
 int (*pmath_emulate) (struct trapframe *);
 
 extern void trap (struct trapframe *frame);
-extern int trapwrite (unsigned addr);
 extern void syscall2 (struct trapframe *frame);
 
 static int trap_pfault (struct trapframe *, int, vm_offset_t);
@@ -988,21 +987,6 @@ trap_pfault(struct trapframe *frame, int usermode, vm_offset_t eva)
                 */
                PHOLD(lp->lwp_proc);
 
-               /*
-                * Grow the stack if necessary
-                */
-               /* grow_stack returns false only if va falls into
-                * a growable stack region and the stack growth
-                * fails.  It returns true if va was not within
-                * a growable stack region, or if the stack 
-                * growth succeeded.
-                */
-               if (!grow_stack(lp->lwp_proc, va)) {
-                       rv = KERN_FAILURE;
-                       PRELE(lp->lwp_proc);
-                       goto nogo;
-               }
-
                /*
                 * Issue fault
                 */
@@ -1166,50 +1150,6 @@ dblfault_handler(void)
        panic("double fault");
 }
 
-/*
- * Compensate for 386 brain damage (missing URKR).
- * This is a little simpler than the pagefault handler in trap() because
- * it the page tables have already been faulted in and high addresses
- * are thrown out early for other reasons.
- */
-int
-trapwrite(unsigned addr)
-{
-       struct lwp *lp;
-       vm_offset_t va;
-       struct vmspace *vm;
-       int rv;
-
-       va = trunc_page((vm_offset_t)addr);
-       /*
-        * XXX - MAX is END.  Changed > to >= for temp. fix.
-        */
-       if (va >= VM_MAX_USER_ADDRESS)
-               return (1);
-
-       lp = curthread->td_lwp;
-       vm = lp->lwp_vmspace;
-
-       PHOLD(lp->lwp_proc);
-
-       if (!grow_stack(lp->lwp_proc, va)) {
-               PRELE(lp->lwp_proc);
-               return (1);
-       }
-
-       /*
-        * fault the data page
-        */
-       rv = vm_fault(&vm->vm_map, va, VM_PROT_WRITE, VM_FAULT_DIRTY);
-
-       PRELE(lp->lwp_proc);
-
-       if (rv != KERN_SUCCESS)
-               return 1;
-
-       return (0);
-}
-
 /*
  * syscall2 -  MP aware system call request C handler
  *
index a59a2a0..80d5d14 100644 (file)
@@ -472,18 +472,6 @@ cpu_reset_real(void)
        while(1);
 }
 
-int
-grow_stack(struct proc *p, vm_offset_t sp)
-{
-       int rv;
-
-       rv = vm_map_growstack (p, sp);
-       if (rv != KERN_SUCCESS)
-               return (0);
-
-       return (1);
-}
-
 SYSCTL_DECL(_vm_stats_misc);
 
 static int cnt_prezero;
index 0e02a10..08afdee 100644 (file)
@@ -856,21 +856,6 @@ trap_pfault(struct trapframe *frame, int usermode)
                 */
                PHOLD(lp->lwp_proc);
 
-               /*
-                * Grow the stack if necessary
-                */
-               /* grow_stack returns false only if va falls into
-                * a growable stack region and the stack growth
-                * fails.  It returns true if va was not within
-                * a growable stack region, or if the stack 
-                * growth succeeded.
-                */
-               if (!grow_stack(lp->lwp_proc, va)) {
-                       rv = KERN_FAILURE;
-                       PRELE(lp->lwp_proc);
-                       goto nogo;
-               }
-
                /*
                 * Issue fault
                 */
index 278d06d..c02cb2d 100644 (file)
@@ -347,18 +347,6 @@ kvtop(void *addr)
        return (pa);
 }
 
-int
-grow_stack(struct proc *p, vm_offset_t sp)
-{
-       int rv;
-
-       rv = vm_map_growstack (p, sp);
-       if (rv != KERN_SUCCESS)
-               return (0);
-
-       return (1);
-}
-
 /*
  * Tell whether this address is in some physical memory region.
  * Currently used by the kernel coredump code in order to avoid
index 377e5a8..49fbd83 100644 (file)
 
 int (*pmath_emulate) (struct trapframe *);
 
-extern int trapwrite (unsigned addr);
-
 static int trap_pfault (struct trapframe *, int, vm_offset_t);
 static void trap_fatal (struct trapframe *, int, vm_offset_t);
 void dblfault_handler (void);
@@ -924,21 +922,6 @@ trap_pfault(struct trapframe *frame, int usermode, vm_offset_t eva)
                 */
                PHOLD(lp->lwp_proc);
 
-               /*
-                * Grow the stack if necessary
-                */
-               /* grow_stack returns false only if va falls into
-                * a growable stack region and the stack growth
-                * fails.  It returns true if va was not within
-                * a growable stack region, or if the stack 
-                * growth succeeded.
-                */
-               if (!grow_stack (lp->lwp_proc, va)) {
-                       rv = KERN_FAILURE;
-                       PRELE(lp->lwp_proc);
-                       goto nogo;
-               }
-
                /*
                 * Issue fault
                 */
@@ -1090,50 +1073,6 @@ dblfault_handler(void)
        panic("double fault");
 }
 
-/*
- * Compensate for 386 brain damage (missing URKR).
- * This is a little simpler than the pagefault handler in trap() because
- * it the page tables have already been faulted in and high addresses
- * are thrown out early for other reasons.
- */
-int
-trapwrite(unsigned addr)
-{
-       struct lwp *lp;
-       vm_offset_t va;
-       struct vmspace *vm;
-       int rv;
-
-       va = trunc_page((vm_offset_t)addr);
-       /*
-        * XXX - MAX is END.  Changed > to >= for temp. fix.
-        */
-       if (va >= VM_MAX_USER_ADDRESS)
-               return (1);
-
-       lp = curthread->td_lwp;
-       vm = lp->lwp_vmspace;
-
-       PHOLD(lp->lwp_proc);
-
-       if (!grow_stack (lp->lwp_proc, va)) {
-               PRELE(lp->lwp_proc);
-               return (1);
-       }
-
-       /*
-        * fault the data page
-        */
-       rv = vm_fault(&vm->vm_map, va, VM_PROT_WRITE, VM_FAULT_DIRTY);
-
-       PRELE(lp->lwp_proc);
-
-       if (rv != KERN_SUCCESS)
-               return 1;
-
-       return (0);
-}
-
 /*
  * syscall2 -  MP aware system call request C handler
  *
index 266c765..54df1b5 100644 (file)
@@ -367,18 +367,6 @@ kvtop(void *addr)
        return (pa);
 }
 
-int
-grow_stack(struct proc *p, vm_offset_t sp)
-{
-       int rv;
-
-       rv = vm_map_growstack (p, sp);
-       if (rv != KERN_SUCCESS)
-               return (0);
-
-       return (1);
-}
-
 SYSCTL_DECL(_vm_stats_misc);
 
 static int cnt_prezero;
index 0c452e3..5bcb989 100644 (file)
@@ -74,7 +74,6 @@ int swapon (struct proc *, void *, int *);
 #endif
 
 int grow (struct proc *, size_t);
-int grow_stack (struct proc *, vm_offset_t);
 int kernacc(c_caddr_t, int, int);
 vm_offset_t kmem_alloc3 (vm_map_t, vm_size_t, int flags);
 vm_offset_t kmem_alloc_nofault (vm_map_t, vm_size_t);
index 02f3da0..b55b0da 100644 (file)
@@ -225,12 +225,14 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, int fault_flags)
        int result;
        vm_pindex_t first_pindex;
        struct faultstate fs;
+       int growstack;
 
        mycpu->gd_cnt.v_vm_faults++;
 
        fs.didlimit = 0;
        fs.hardfault = 0;
        fs.fault_flags = fault_flags;
+       growstack = 1;
 
 RetryFault:
        /*
@@ -258,10 +260,19 @@ RetryFault:
         * to do a user wiring we have more work to do.
         */
        if (result != KERN_SUCCESS) {
-               if (result != KERN_PROTECTION_FAILURE)
-                       return result;
-               if ((fs.fault_flags & VM_FAULT_WIRE_MASK) != VM_FAULT_USER_WIRE)
-                       return result;
+               if (result != KERN_PROTECTION_FAILURE ||
+                   (fs.fault_flags & VM_FAULT_WIRE_MASK) != VM_FAULT_USER_WIRE)
+               {
+                       if (result == KERN_INVALID_ADDRESS && growstack &&
+                           map != &kernel_map && curproc != NULL) {
+                               result = vm_map_growstack(curproc, vaddr);
+                               if (result != KERN_SUCCESS)
+                                       return (KERN_FAILURE);
+                               growstack = 0;
+                               goto RetryFault;
+                       }
+                       return (result);
+               }
 
                /*
                 * If we are user-wiring a r/w segment, and it is COW, then