diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h index 405442c204c7..4611b2eee144 100644 --- a/sys/vm/vm_extern.h +++ b/sys/vm/vm_extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: vm_extern.h,v 1.28 1997/12/31 07:47:41 thorpej Exp $ */ +/* $NetBSD: vm_extern.h,v 1.29 1998/01/03 02:53:00 thorpej Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -119,7 +119,7 @@ void vm_fault_copy_entry __P((vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t)); void vm_fault_unwire __P((vm_map_t, vm_offset_t, vm_offset_t)); int vm_fault_wire __P((vm_map_t, vm_offset_t, vm_offset_t)); -void vm_fork __P((struct proc *, struct proc *)); +void vm_fork __P((struct proc *, struct proc *, boolean_t)); int vm_inherit __P((vm_map_t, vm_offset_t, vm_size_t, vm_inherit_t)); void vm_init_limits __P((struct proc *)); @@ -134,6 +134,8 @@ struct vmspace *vmspace_alloc __P((vm_offset_t, vm_offset_t, int)); struct vmspace *vmspace_fork __P((struct vmspace *)); void vmspace_exec __P((struct proc *)); void vmspace_free __P((struct vmspace *)); +void vmspace_share __P((struct proc *, struct proc *)); +void vmspace_unshare __P((struct proc *)); void vmtotal __P((struct vmtotal *)); void vnode_pager_setsize __P((struct vnode *, u_quad_t)); void vnode_pager_sync __P((struct mount *)); diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index 1b2543d20adc..14276e358d53 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -1,4 +1,4 @@ -/* $NetBSD: vm_glue.c,v 1.68 1997/06/19 20:54:48 pk Exp $ */ +/* $NetBSD: vm_glue.c,v 1.69 1998/01/03 02:53:02 thorpej Exp $ */ /* * Copyright (c) 1991, 1993 @@ -202,26 +202,20 @@ vsunlock(addr, len) * after cpu_fork returns. */ void -vm_fork(p1, p2) +vm_fork(p1, p2, shared) register struct proc *p1, *p2; + boolean_t shared; { register struct user *up; vm_offset_t addr; -#if defined(i386) || defined(pc532) /* - * avoid copying any of the parent's pagetables or other per-process - * objects that reside in the map by marking all of them non-inheritable + * Share the address space if we've been directed to. */ - (void)vm_map_inherit(&p1->p_vmspace->vm_map, - VM_MAXUSER_ADDRESS, VM_MAX_ADDRESS, VM_INHERIT_NONE); -#endif - p2->p_vmspace = vmspace_fork(p1->p_vmspace); - -#ifdef SYSVSHM - if (p1->p_vmspace->vm_shm) - shmfork(p1, p2); -#endif + if (shared == TRUE) + vmspace_share(p1, p2); + else + p2->p_vmspace = vmspace_fork(p1->p_vmspace); #if !defined(vax) /* @@ -260,17 +254,6 @@ vm_fork(p1, p2) ((caddr_t)&up->u_stats.pstat_endcopy - (caddr_t)&up->u_stats.pstat_startcopy)); -#if defined(i386) || defined(pc532) - { vm_offset_t addr = VM_MAXUSER_ADDRESS; struct vm_map *vp; - - /* ream out old pagetables and kernel stack */ - vp = &p2->p_vmspace->vm_map; - (void)vm_deallocate(vp, addr, VM_MAX_ADDRESS - addr); - (void)vm_allocate(vp, &addr, VM_MAX_ADDRESS - addr, FALSE); - (void)vm_map_inherit(vp, addr, VM_MAX_ADDRESS, VM_INHERIT_NONE); - } -#endif - /* * cpu_fork will copy and update the kernel stack and pcb, * and make the child ready to run. The child will exit diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 0ad48cf64d0d..45be68fe5e5a 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -1,4 +1,4 @@ -/* $NetBSD: vm_map.c,v 1.30 1997/12/31 07:47:42 thorpej Exp $ */ +/* $NetBSD: vm_map.c,v 1.31 1998/01/03 02:53:04 thorpej Exp $ */ /* * Copyright (c) 1991, 1993 @@ -71,6 +71,7 @@ #include #include #include +#include #ifdef SYSVSHM #include @@ -205,6 +206,36 @@ vmspace_alloc(min, max, pageable) return (vm); } +/* + * Make p1 and p2 share address space. + */ +void +vmspace_share(p1, p2) + struct proc *p1, *p2; +{ + + p2->p_vmspace = p1->p_vmspace; + p1->p_vmspace->vm_refcnt++; +} + +/* + * Make p not share its address space. + */ +void +vmspace_unshare(p) + struct proc *p; +{ + struct vmspace *nvm, *ovm = p->p_vmspace; + + if (ovm->vm_refcnt == 1) + return; + + nvm = vmspace_fork(ovm); + p->p_vmspace = nvm; + pmap_activate(p); + vmspace_free(ovm); +} + /* * Perform operations on VM space that need to happen during exec. */ @@ -212,20 +243,49 @@ void vmspace_exec(p) struct proc *p; { - struct vmspace *ovm = p->p_vmspace; + struct vmspace *nvm, *ovm = p->p_vmspace; vm_map_t map = &ovm->vm_map; #ifdef sparc /* XXX cgd 960926: the sparc #ifdef should be a MD hook */ kill_user_windows(p); /* before stack addresses go away */ #endif - /* Kill shared memory and unmap old program. */ + + if (ovm->vm_refcnt == 1) { + /* + * Destroy this process's VM space. + */ #ifdef SYSVSHM - if (ovm->vm_shm) - shmexit(p); + /* Kill shared memory. */ + if (ovm->vm_shm) + shmexit(ovm); #endif - vm_deallocate(map, VM_MIN_ADDRESS, - VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS); + /* Unmap old program. */ + vm_deallocate(map, VM_MIN_ADDRESS, + VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS); + } else { + /* + * This address space is being shared. We must + * create a new one to avoid disrupting other + * processes that are using it. Since we would + * immediately unmap the entire address space, + * we do minimal work here. + */ + nvm = vmspace_alloc(map->min_offset, map->max_offset, + map->entries_pageable); +#if defined(i386) || defined(pc532) /* XXX XXX XXX */ + /* Allocate page table space. */ + { vm_offset_t addr = VM_MAXUSER_ADDRESS; + (void) vm_allocate(&nvm->vm_map, &addr, VM_MAX_ADDRESS - addr, + FALSE); + (void) vm_map_inherit(&nvm->vm_map, addr, VM_MAX_ADDRESS, + VM_INHERIT_NONE); + } +#endif + p->p_vmspace = nvm; + pmap_activate(p); + vmspace_free(ovm); + } } void @@ -2165,6 +2225,17 @@ vmspace_fork(vm1) vm_map_entry_t new_entry; pmap_t new_pmap; +#if defined(i386) || defined(pc532) /* XXX XXX XXX */ + /* + * Avoid copying any of the parent's page tables or other + * per-process objects that reside in the map by marking + * all of them non-inheritable. + */ + + (void) vm_map_inherit(old_map, VM_MAXUSER_ADDRESS, VM_MAX_ADDRESS, + VM_INHERIT_NONE); +#endif + vm_map_lock(old_map); vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset, @@ -2297,6 +2368,20 @@ vmspace_fork(vm1) new_map->size = old_map->size; vm_map_unlock(old_map); +#if defined(i386) || defined(pc532) /* XXX XXX XXX */ + /* Allocate page table space. */ + { vm_offset_t addr = VM_MAXUSER_ADDRESS; + (void) vm_allocate(new_map, &addr, VM_MAX_ADDRESS - addr, FALSE); + (void) vm_map_inherit(new_map, addr, VM_MAX_ADDRESS, + VM_INHERIT_NONE); + } +#endif + +#ifdef SYSVSHM + if (vm1->vm_shm) + shmfork(vm1, vm2); +#endif + return(vm2); }