1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 6df8bae1dSRodney W. Grimes * The Mach Operating System project at Carnegie-Mellon University. 7df8bae1dSRodney W. Grimes * 8df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 9df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 10df8bae1dSRodney W. Grimes * are met: 11df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 12df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 13df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 15df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 16df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 175929bcfaSPhilippe Charnier * must display the following acknowledgement: 18df8bae1dSRodney W. Grimes * This product includes software developed by the University of 19df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 20df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 21df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 22df8bae1dSRodney W. Grimes * without specific prior written permission. 23df8bae1dSRodney W. Grimes * 24df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df8bae1dSRodney W. Grimes * SUCH DAMAGE. 35df8bae1dSRodney W. Grimes * 363c4dd356SDavid Greenman * from: @(#)vm_glue.c 8.6 (Berkeley) 1/5/94 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * 39df8bae1dSRodney W. Grimes * Copyright (c) 1987, 1990 Carnegie-Mellon University. 40df8bae1dSRodney W. Grimes * All rights reserved. 41df8bae1dSRodney W. Grimes * 42df8bae1dSRodney W. Grimes * Permission to use, copy, modify and distribute this software and 43df8bae1dSRodney W. Grimes * its documentation is hereby granted, provided that both the copyright 44df8bae1dSRodney W. Grimes * notice and this permission notice appear in all copies of the 45df8bae1dSRodney W. Grimes * software, derivative works or modified versions, and any portions 46df8bae1dSRodney W. Grimes * thereof, and that both notices appear in supporting documentation. 47df8bae1dSRodney W. Grimes * 48df8bae1dSRodney W. Grimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 49df8bae1dSRodney W. Grimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 50df8bae1dSRodney W. Grimes * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 51df8bae1dSRodney W. Grimes * 52df8bae1dSRodney W. Grimes * Carnegie Mellon requests users of this software to return to 53df8bae1dSRodney W. Grimes * 54df8bae1dSRodney W. Grimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 55df8bae1dSRodney W. Grimes * School of Computer Science 56df8bae1dSRodney W. Grimes * Carnegie Mellon University 57df8bae1dSRodney W. Grimes * Pittsburgh PA 15213-3890 58df8bae1dSRodney W. Grimes * 59df8bae1dSRodney W. Grimes * any improvements or extensions that they make and grant Carnegie the 60df8bae1dSRodney W. Grimes * rights to redistribute these changes. 613c4dd356SDavid Greenman * 62c3aac50fSPeter Wemm * $FreeBSD$ 63df8bae1dSRodney W. Grimes */ 64df8bae1dSRodney W. Grimes 65faa5f8d8SAndrzej Bialecki #include "opt_vm.h" 66e9822d92SJoerg Wunsch 67df8bae1dSRodney W. Grimes #include <sys/param.h> 68df8bae1dSRodney W. Grimes #include <sys/systm.h> 69fb919e4dSMark Murray #include <sys/lock.h> 70fb919e4dSMark Murray #include <sys/mutex.h> 71df8bae1dSRodney W. Grimes #include <sys/proc.h> 72df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 733aa12267SBruce Evans #include <sys/shm.h> 74efeaf95aSDavid Greenman #include <sys/vmmeter.h> 751005a129SJohn Baldwin #include <sys/sx.h> 76ceb0cf87SJohn Dyson #include <sys/sysctl.h> 77df8bae1dSRodney W. Grimes 7826f9a767SRodney W. Grimes #include <sys/kernel.h> 790384fff8SJason Evans #include <sys/ktr.h> 80a2a1c95cSPeter Wemm #include <sys/unistd.h> 8126f9a767SRodney W. Grimes 82b1037dcdSBruce Evans #include <machine/limits.h> 83b1037dcdSBruce Evans 84df8bae1dSRodney W. Grimes #include <vm/vm.h> 85efeaf95aSDavid Greenman #include <vm/vm_param.h> 86efeaf95aSDavid Greenman #include <vm/pmap.h> 87efeaf95aSDavid Greenman #include <vm/vm_map.h> 88df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 8926f9a767SRodney W. Grimes #include <vm/vm_pageout.h> 90a136efe9SPeter Wemm #include <vm/vm_object.h> 91df8bae1dSRodney W. Grimes #include <vm/vm_kern.h> 92efeaf95aSDavid Greenman #include <vm/vm_extern.h> 93a136efe9SPeter Wemm #include <vm/vm_pager.h> 94efeaf95aSDavid Greenman 95efeaf95aSDavid Greenman #include <sys/user.h> 96df8bae1dSRodney W. Grimes 97ea754954SJohn Baldwin extern int maxslp; 98ea754954SJohn Baldwin 992b14f991SJulian Elischer /* 1002b14f991SJulian Elischer * System initialization 1012b14f991SJulian Elischer * 1022b14f991SJulian Elischer * Note: proc0 from proc.h 1032b14f991SJulian Elischer */ 10411caded3SAlfred Perlstein static void vm_init_limits(void *); 1054590fd3aSDavid Greenman SYSINIT(vm_limits, SI_SUB_VM_CONF, SI_ORDER_FIRST, vm_init_limits, &proc0) 1062b14f991SJulian Elischer 1072b14f991SJulian Elischer /* 1082b14f991SJulian Elischer * THIS MUST BE THE LAST INITIALIZATION ITEM!!! 1092b14f991SJulian Elischer * 1102b14f991SJulian Elischer * Note: run scheduling should be divorced from the vm system. 1112b14f991SJulian Elischer */ 11211caded3SAlfred Perlstein static void scheduler(void *); 1132b14f991SJulian Elischer SYSINIT(scheduler, SI_SUB_RUN_SCHEDULER, SI_ORDER_FIRST, scheduler, NULL) 1142b14f991SJulian Elischer 115e50f5c2eSBruce Evans #ifndef NO_SWAPPING 11611caded3SAlfred Perlstein static void swapout(struct proc *); 117a136efe9SPeter Wemm static void vm_proc_swapin(struct proc *p); 118a136efe9SPeter Wemm static void vm_proc_swapout(struct proc *p); 119e50f5c2eSBruce Evans #endif 120f708ef1bSPoul-Henning Kamp 12143a90f3aSAlan Cox /* 12243a90f3aSAlan Cox * MPSAFE 12343a90f3aSAlan Cox */ 124df8bae1dSRodney W. Grimes int 125df8bae1dSRodney W. Grimes kernacc(addr, len, rw) 126df8bae1dSRodney W. Grimes caddr_t addr; 127df8bae1dSRodney W. Grimes int len, rw; 128df8bae1dSRodney W. Grimes { 129df8bae1dSRodney W. Grimes boolean_t rv; 130df8bae1dSRodney W. Grimes vm_offset_t saddr, eaddr; 13102c58685SPoul-Henning Kamp vm_prot_t prot; 132df8bae1dSRodney W. Grimes 133e50f5c2eSBruce Evans KASSERT((rw & ~VM_PROT_ALL) == 0, 13402c58685SPoul-Henning Kamp ("illegal ``rw'' argument to kernacc (%x)\n", rw)); 13502c58685SPoul-Henning Kamp prot = rw; 1366cde7a16SDavid Greenman saddr = trunc_page((vm_offset_t)addr); 1376cde7a16SDavid Greenman eaddr = round_page((vm_offset_t)addr + len); 138df8bae1dSRodney W. Grimes rv = vm_map_check_protection(kernel_map, saddr, eaddr, prot); 139df8bae1dSRodney W. Grimes return (rv == TRUE); 140df8bae1dSRodney W. Grimes } 141df8bae1dSRodney W. Grimes 14243a90f3aSAlan Cox /* 14343a90f3aSAlan Cox * MPSAFE 14443a90f3aSAlan Cox */ 145df8bae1dSRodney W. Grimes int 146df8bae1dSRodney W. Grimes useracc(addr, len, rw) 147df8bae1dSRodney W. Grimes caddr_t addr; 148df8bae1dSRodney W. Grimes int len, rw; 149df8bae1dSRodney W. Grimes { 150df8bae1dSRodney W. Grimes boolean_t rv; 15102c58685SPoul-Henning Kamp vm_prot_t prot; 152df8bae1dSRodney W. Grimes 153e50f5c2eSBruce Evans KASSERT((rw & ~VM_PROT_ALL) == 0, 15402c58685SPoul-Henning Kamp ("illegal ``rw'' argument to useracc (%x)\n", rw)); 15502c58685SPoul-Henning Kamp prot = rw; 15626f9a767SRodney W. Grimes /* 157bbc0ec52SDavid Greenman * XXX - check separately to disallow access to user area and user 158bbc0ec52SDavid Greenman * page tables - they are in the map. 15926f9a767SRodney W. Grimes * 1600d94caffSDavid Greenman * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. It was once 1610d94caffSDavid Greenman * only used (as an end address) in trap.c. Use it as an end address 1620d94caffSDavid Greenman * here too. This bogusness has spread. I just fixed where it was 1630d94caffSDavid Greenman * used as a max in vm_mmap.c. 16426f9a767SRodney W. Grimes */ 165bbc0ec52SDavid Greenman if ((vm_offset_t) addr + len > /* XXX */ VM_MAXUSER_ADDRESS 166bbc0ec52SDavid Greenman || (vm_offset_t) addr + len < (vm_offset_t) addr) { 16726f9a767SRodney W. Grimes return (FALSE); 16826f9a767SRodney W. Grimes } 1695ee9fe6bSAlan Cox rv = vm_map_check_protection(&curproc->p_vmspace->vm_map, 1705ee9fe6bSAlan Cox trunc_page((vm_offset_t)addr), round_page((vm_offset_t)addr + len), 1715ee9fe6bSAlan Cox prot); 172df8bae1dSRodney W. Grimes return (rv == TRUE); 173df8bae1dSRodney W. Grimes } 174df8bae1dSRodney W. Grimes 17543a90f3aSAlan Cox /* 17643a90f3aSAlan Cox * MPSAFE 17743a90f3aSAlan Cox */ 178df8bae1dSRodney W. Grimes void 179df8bae1dSRodney W. Grimes vslock(addr, len) 180df8bae1dSRodney W. Grimes caddr_t addr; 181df8bae1dSRodney W. Grimes u_int len; 182df8bae1dSRodney W. Grimes { 18343a90f3aSAlan Cox 1841d7cf06cSAlan Cox vm_map_wire(&curproc->p_vmspace->vm_map, trunc_page((vm_offset_t)addr), 1856cde7a16SDavid Greenman round_page((vm_offset_t)addr + len), FALSE); 186df8bae1dSRodney W. Grimes } 187df8bae1dSRodney W. Grimes 188319490fbSAlan Cox /* 189319490fbSAlan Cox * MPSAFE 190319490fbSAlan Cox */ 191df8bae1dSRodney W. Grimes void 1927de47255SPoul-Henning Kamp vsunlock(addr, len) 193df8bae1dSRodney W. Grimes caddr_t addr; 194df8bae1dSRodney W. Grimes u_int len; 195df8bae1dSRodney W. Grimes { 196319490fbSAlan Cox 1971d7cf06cSAlan Cox vm_map_unwire(&curproc->p_vmspace->vm_map, 19823955314SAlfred Perlstein trunc_page((vm_offset_t)addr), 1991d7cf06cSAlan Cox round_page((vm_offset_t)addr + len), FALSE); 200df8bae1dSRodney W. Grimes } 201df8bae1dSRodney W. Grimes 202df8bae1dSRodney W. Grimes /* 203a136efe9SPeter Wemm * Create the U area for a new process. 204a136efe9SPeter Wemm * This routine directly affects the fork perf for a process. 205a136efe9SPeter Wemm */ 206a136efe9SPeter Wemm void 207a136efe9SPeter Wemm vm_proc_new(struct proc *p) 208a136efe9SPeter Wemm { 209a136efe9SPeter Wemm vm_page_t ma[UAREA_PAGES]; 210a136efe9SPeter Wemm vm_object_t upobj; 211a136efe9SPeter Wemm vm_offset_t up; 212a136efe9SPeter Wemm vm_page_t m; 213a136efe9SPeter Wemm u_int i; 214a136efe9SPeter Wemm 215a136efe9SPeter Wemm /* 216a136efe9SPeter Wemm * Allocate object for the upage. 217a136efe9SPeter Wemm */ 218a136efe9SPeter Wemm upobj = vm_object_allocate(OBJT_DEFAULT, UAREA_PAGES); 219a136efe9SPeter Wemm p->p_upages_obj = upobj; 220a136efe9SPeter Wemm 221a136efe9SPeter Wemm /* 222a136efe9SPeter Wemm * Get a kernel virtual address for the U area for this process. 223a136efe9SPeter Wemm */ 224a136efe9SPeter Wemm up = kmem_alloc_nofault(kernel_map, UAREA_PAGES * PAGE_SIZE); 225a136efe9SPeter Wemm if (up == 0) 226a136efe9SPeter Wemm panic("vm_proc_new: upage allocation failed"); 227a136efe9SPeter Wemm p->p_uarea = (struct user *)up; 228a136efe9SPeter Wemm 229a136efe9SPeter Wemm for (i = 0; i < UAREA_PAGES; i++) { 230a136efe9SPeter Wemm /* 231a136efe9SPeter Wemm * Get a uarea page. 232a136efe9SPeter Wemm */ 233a136efe9SPeter Wemm m = vm_page_grab(upobj, i, VM_ALLOC_NORMAL | VM_ALLOC_RETRY); 234a136efe9SPeter Wemm ma[i] = m; 235a136efe9SPeter Wemm 236a136efe9SPeter Wemm /* 237a136efe9SPeter Wemm * Wire the page. 238a136efe9SPeter Wemm */ 239a136efe9SPeter Wemm m->wire_count++; 240a136efe9SPeter Wemm cnt.v_wire_count++; 241a136efe9SPeter Wemm 242a136efe9SPeter Wemm vm_page_wakeup(m); 243a136efe9SPeter Wemm vm_page_flag_clear(m, PG_ZERO); 244a136efe9SPeter Wemm vm_page_flag_set(m, PG_MAPPED | PG_WRITEABLE); 245a136efe9SPeter Wemm m->valid = VM_PAGE_BITS_ALL; 246a136efe9SPeter Wemm } 247a136efe9SPeter Wemm 248a136efe9SPeter Wemm /* 249a136efe9SPeter Wemm * Enter the pages into the kernel address space. 250a136efe9SPeter Wemm */ 251a136efe9SPeter Wemm pmap_qenter(up, ma, UAREA_PAGES); 252a136efe9SPeter Wemm } 253a136efe9SPeter Wemm 254a136efe9SPeter Wemm /* 255a136efe9SPeter Wemm * Dispose the U area for a process that has exited. 256a136efe9SPeter Wemm * This routine directly impacts the exit perf of a process. 257a136efe9SPeter Wemm * XXX proc_zone is marked UMA_ZONE_NOFREE, so this should never be called. 258a136efe9SPeter Wemm */ 259a136efe9SPeter Wemm void 260a136efe9SPeter Wemm vm_proc_dispose(struct proc *p) 261a136efe9SPeter Wemm { 262a136efe9SPeter Wemm vm_object_t upobj; 263a136efe9SPeter Wemm vm_offset_t up; 264a136efe9SPeter Wemm vm_page_t m; 265a136efe9SPeter Wemm int i; 266a136efe9SPeter Wemm 267a136efe9SPeter Wemm upobj = p->p_upages_obj; 268a136efe9SPeter Wemm up = (vm_offset_t)p->p_uarea; 269a136efe9SPeter Wemm for (i = 0; i < UAREA_PAGES; i++) { 270a136efe9SPeter Wemm m = vm_page_lookup(upobj, i); 271a136efe9SPeter Wemm if (m == NULL) 272a136efe9SPeter Wemm panic("vm_proc_dispose: upage already missing?"); 273a136efe9SPeter Wemm vm_page_busy(m); 274a136efe9SPeter Wemm vm_page_unwire(m, 0); 275a136efe9SPeter Wemm vm_page_free(m); 276a136efe9SPeter Wemm } 277a136efe9SPeter Wemm pmap_qremove(up, UAREA_PAGES); 278a136efe9SPeter Wemm kmem_free(kernel_map, up, UAREA_PAGES * PAGE_SIZE); 279a136efe9SPeter Wemm p->p_upages_obj = NULL; 280a136efe9SPeter Wemm vm_object_deallocate(upobj); 281a136efe9SPeter Wemm } 282a136efe9SPeter Wemm 283a136efe9SPeter Wemm #ifndef NO_SWAPPING 284a136efe9SPeter Wemm /* 285a136efe9SPeter Wemm * Allow the U area for a process to be prejudicially paged out. 286a136efe9SPeter Wemm */ 287a136efe9SPeter Wemm void 288a136efe9SPeter Wemm vm_proc_swapout(struct proc *p) 289a136efe9SPeter Wemm { 290a136efe9SPeter Wemm vm_object_t upobj; 291a136efe9SPeter Wemm vm_offset_t up; 292a136efe9SPeter Wemm vm_page_t m; 293a136efe9SPeter Wemm int i; 294a136efe9SPeter Wemm 295a136efe9SPeter Wemm upobj = p->p_upages_obj; 296a136efe9SPeter Wemm up = (vm_offset_t)p->p_uarea; 297a136efe9SPeter Wemm for (i = 0; i < UAREA_PAGES; i++) { 298a136efe9SPeter Wemm m = vm_page_lookup(upobj, i); 299a136efe9SPeter Wemm if (m == NULL) 300a136efe9SPeter Wemm panic("vm_proc_swapout: upage already missing?"); 301a136efe9SPeter Wemm vm_page_dirty(m); 302a136efe9SPeter Wemm vm_page_unwire(m, 0); 303a136efe9SPeter Wemm } 304a136efe9SPeter Wemm pmap_qremove(up, UAREA_PAGES); 305a136efe9SPeter Wemm } 306a136efe9SPeter Wemm 307a136efe9SPeter Wemm /* 308a136efe9SPeter Wemm * Bring the U area for a specified process back in. 309a136efe9SPeter Wemm */ 310a136efe9SPeter Wemm void 311a136efe9SPeter Wemm vm_proc_swapin(struct proc *p) 312a136efe9SPeter Wemm { 313a136efe9SPeter Wemm vm_page_t ma[UAREA_PAGES]; 314a136efe9SPeter Wemm vm_object_t upobj; 315a136efe9SPeter Wemm vm_offset_t up; 316a136efe9SPeter Wemm vm_page_t m; 317a136efe9SPeter Wemm int rv; 318a136efe9SPeter Wemm int i; 319a136efe9SPeter Wemm 320a136efe9SPeter Wemm upobj = p->p_upages_obj; 321a136efe9SPeter Wemm up = (vm_offset_t)p->p_uarea; 322a136efe9SPeter Wemm for (i = 0; i < UAREA_PAGES; i++) { 323a136efe9SPeter Wemm m = vm_page_grab(upobj, i, VM_ALLOC_NORMAL | VM_ALLOC_RETRY); 324a136efe9SPeter Wemm if (m->valid != VM_PAGE_BITS_ALL) { 325a136efe9SPeter Wemm rv = vm_pager_get_pages(upobj, &m, 1, 0); 326a136efe9SPeter Wemm if (rv != VM_PAGER_OK) 327a136efe9SPeter Wemm panic("vm_proc_swapin: cannot get upage"); 328a136efe9SPeter Wemm m = vm_page_lookup(upobj, i); 329a136efe9SPeter Wemm m->valid = VM_PAGE_BITS_ALL; 330a136efe9SPeter Wemm } 331a136efe9SPeter Wemm ma[i] = m; 332a136efe9SPeter Wemm vm_page_wire(m); 333a136efe9SPeter Wemm vm_page_wakeup(m); 334a136efe9SPeter Wemm vm_page_flag_set(m, PG_MAPPED | PG_WRITEABLE); 335a136efe9SPeter Wemm } 336a136efe9SPeter Wemm pmap_qenter(up, ma, UAREA_PAGES); 337a136efe9SPeter Wemm } 338a136efe9SPeter Wemm #endif 339a136efe9SPeter Wemm 340a136efe9SPeter Wemm /* 341df8bae1dSRodney W. Grimes * Implement fork's actions on an address space. 342df8bae1dSRodney W. Grimes * Here we arrange for the address space to be copied or referenced, 343df8bae1dSRodney W. Grimes * allocate a user struct (pcb and kernel stack), then call the 344df8bae1dSRodney W. Grimes * machine-dependent layer to fill those in and make the new process 345a2a1c95cSPeter Wemm * ready to run. The new process is set up so that it returns directly 346a2a1c95cSPeter Wemm * to user mode to avoid stack copying and relocation problems. 347df8bae1dSRodney W. Grimes */ 348a2a1c95cSPeter Wemm void 349079b7badSJulian Elischer vm_forkproc(td, p2, td2, flags) 350b40ce416SJulian Elischer struct thread *td; 351b40ce416SJulian Elischer struct proc *p2; 352079b7badSJulian Elischer struct thread *td2; 353a2a1c95cSPeter Wemm int flags; 354df8bae1dSRodney W. Grimes { 355b40ce416SJulian Elischer struct proc *p1 = td->td_proc; 35654d92145SMatthew Dillon struct user *up; 357df8bae1dSRodney W. Grimes 3580cddd8f0SMatthew Dillon GIANT_REQUIRED; 3590cddd8f0SMatthew Dillon 36091c28bfdSLuoqi Chen if ((flags & RFPROC) == 0) { 36191c28bfdSLuoqi Chen /* 36291c28bfdSLuoqi Chen * Divorce the memory, if it is shared, essentially 36391c28bfdSLuoqi Chen * this changes shared memory amongst threads, into 36491c28bfdSLuoqi Chen * COW locally. 36591c28bfdSLuoqi Chen */ 36691c28bfdSLuoqi Chen if ((flags & RFMEM) == 0) { 36791c28bfdSLuoqi Chen if (p1->p_vmspace->vm_refcnt > 1) { 36891c28bfdSLuoqi Chen vmspace_unshare(p1); 36991c28bfdSLuoqi Chen } 37091c28bfdSLuoqi Chen } 371079b7badSJulian Elischer cpu_fork(td, p2, td2, flags); 37291c28bfdSLuoqi Chen return; 37391c28bfdSLuoqi Chen } 37491c28bfdSLuoqi Chen 3755856e12eSJohn Dyson if (flags & RFMEM) { 3765856e12eSJohn Dyson p2->p_vmspace = p1->p_vmspace; 3775856e12eSJohn Dyson p1->p_vmspace->vm_refcnt++; 3785856e12eSJohn Dyson } 3795856e12eSJohn Dyson 38090ecac61SMatthew Dillon while (vm_page_count_severe()) { 38126f9a767SRodney W. Grimes VM_WAIT; 3820d94caffSDavid Greenman } 38326f9a767SRodney W. Grimes 3845856e12eSJohn Dyson if ((flags & RFMEM) == 0) { 385df8bae1dSRodney W. Grimes p2->p_vmspace = vmspace_fork(p1->p_vmspace); 386df8bae1dSRodney W. Grimes 387d4da2dbaSAlan Cox pmap_pinit2(vmspace_pmap(p2->p_vmspace)); 388d4da2dbaSAlan Cox 389df8bae1dSRodney W. Grimes if (p1->p_vmspace->vm_shm) 390dabee6feSPeter Wemm shmfork(p1, p2); 391a2a1c95cSPeter Wemm } 392df8bae1dSRodney W. Grimes 393b40ce416SJulian Elischer /* XXXKSE this is unsatisfactory but should be adequate */ 394b40ce416SJulian Elischer up = p2->p_uarea; 395df8bae1dSRodney W. Grimes 39639fb8e6bSJulian Elischer /* 39739fb8e6bSJulian Elischer * p_stats currently points at fields in the user struct 39839fb8e6bSJulian Elischer * but not at &u, instead at p_addr. Copy parts of 39939fb8e6bSJulian Elischer * p_stats; zero the rest of p_stats (statistics). 400dc9c271aSJulian Elischer * 401dc9c271aSJulian Elischer * If procsig->ps_refcnt is 1 and p2->p_sigacts is NULL we dont' need 402dc9c271aSJulian Elischer * to share sigacts, so we use the up->u_sigacts. 40339fb8e6bSJulian Elischer */ 40439fb8e6bSJulian Elischer p2->p_stats = &up->u_stats; 405dc9c271aSJulian Elischer if (p2->p_sigacts == NULL) { 406dc9c271aSJulian Elischer if (p2->p_procsig->ps_refcnt != 1) 407dc9c271aSJulian Elischer printf ("PID:%d NULL sigacts with refcnt not 1!\n",p2->p_pid); 408dc9c271aSJulian Elischer p2->p_sigacts = &up->u_sigacts; 409dc9c271aSJulian Elischer up->u_sigacts = *p1->p_sigacts; 410dc9c271aSJulian Elischer } 41188c5ea45SJulian Elischer 412df8bae1dSRodney W. Grimes bzero(&up->u_stats.pstat_startzero, 413df8bae1dSRodney W. Grimes (unsigned) ((caddr_t) &up->u_stats.pstat_endzero - 414df8bae1dSRodney W. Grimes (caddr_t) &up->u_stats.pstat_startzero)); 415df8bae1dSRodney W. Grimes bcopy(&p1->p_stats->pstat_startcopy, &up->u_stats.pstat_startcopy, 416df8bae1dSRodney W. Grimes ((caddr_t) &up->u_stats.pstat_endcopy - 417df8bae1dSRodney W. Grimes (caddr_t) &up->u_stats.pstat_startcopy)); 418df8bae1dSRodney W. Grimes 419df8bae1dSRodney W. Grimes 420df8bae1dSRodney W. Grimes /* 421a2a1c95cSPeter Wemm * cpu_fork will copy and update the pcb, set up the kernel stack, 422a2a1c95cSPeter Wemm * and make the child ready to run. 423df8bae1dSRodney W. Grimes */ 424079b7badSJulian Elischer cpu_fork(td, p2, td2, flags); 425df8bae1dSRodney W. Grimes } 426df8bae1dSRodney W. Grimes 427df8bae1dSRodney W. Grimes /* 428eb30c1c0SPeter Wemm * Called after process has been wait(2)'ed apon and is being reaped. 429eb30c1c0SPeter Wemm * The idea is to reclaim resources that we could not reclaim while 430eb30c1c0SPeter Wemm * the process was still executing. 431eb30c1c0SPeter Wemm */ 432eb30c1c0SPeter Wemm void 433eb30c1c0SPeter Wemm vm_waitproc(p) 434eb30c1c0SPeter Wemm struct proc *p; 435eb30c1c0SPeter Wemm { 436b40ce416SJulian Elischer struct thread *td; 437eb30c1c0SPeter Wemm 438eb30c1c0SPeter Wemm GIANT_REQUIRED; 439eb30c1c0SPeter Wemm cpu_wait(p); 440e602ba25SJulian Elischer /* XXXKSE by here there should not be any threads left! */ 441e602ba25SJulian Elischer FOREACH_THREAD_IN_PROC(p, td) { 442e602ba25SJulian Elischer panic("vm_waitproc: Survivor thread!"); 443e602ba25SJulian Elischer } 444582ec34cSAlfred Perlstein vmspace_exitfree(p); /* and clean-out the vmspace */ 445eb30c1c0SPeter Wemm } 446eb30c1c0SPeter Wemm 447eb30c1c0SPeter Wemm /* 448df8bae1dSRodney W. Grimes * Set default limits for VM system. 449df8bae1dSRodney W. Grimes * Called for proc 0, and then inherited by all others. 4502b14f991SJulian Elischer * 4512b14f991SJulian Elischer * XXX should probably act directly on proc0. 452df8bae1dSRodney W. Grimes */ 4532b14f991SJulian Elischer static void 4542b14f991SJulian Elischer vm_init_limits(udata) 4554590fd3aSDavid Greenman void *udata; 456df8bae1dSRodney W. Grimes { 45754d92145SMatthew Dillon struct proc *p = udata; 458bbc0ec52SDavid Greenman int rss_limit; 459df8bae1dSRodney W. Grimes 460df8bae1dSRodney W. Grimes /* 4610d94caffSDavid Greenman * Set up the initial limits on process VM. Set the maximum resident 4620d94caffSDavid Greenman * set size to be half of (reasonably) available memory. Since this 4630d94caffSDavid Greenman * is a soft limit, it comes into effect only when the system is out 4640d94caffSDavid Greenman * of memory - half of main memory helps to favor smaller processes, 465bbc0ec52SDavid Greenman * and reduces thrashing of the object cache. 466df8bae1dSRodney W. Grimes */ 467cbc89bfbSPaul Saab p->p_rlimit[RLIMIT_STACK].rlim_cur = dflssiz; 468cbc89bfbSPaul Saab p->p_rlimit[RLIMIT_STACK].rlim_max = maxssiz; 469cbc89bfbSPaul Saab p->p_rlimit[RLIMIT_DATA].rlim_cur = dfldsiz; 470cbc89bfbSPaul Saab p->p_rlimit[RLIMIT_DATA].rlim_max = maxdsiz; 471dd0bd066SDavid Greenman /* limit the limit to no less than 2MB */ 472f2daac0cSDavid Greenman rss_limit = max(cnt.v_free_count, 512); 473bbc0ec52SDavid Greenman p->p_rlimit[RLIMIT_RSS].rlim_cur = ptoa(rss_limit); 47426f9a767SRodney W. Grimes p->p_rlimit[RLIMIT_RSS].rlim_max = RLIM_INFINITY; 475df8bae1dSRodney W. Grimes } 476df8bae1dSRodney W. Grimes 47726f9a767SRodney W. Grimes void 47826f9a767SRodney W. Grimes faultin(p) 47926f9a767SRodney W. Grimes struct proc *p; 48026f9a767SRodney W. Grimes { 48126f9a767SRodney W. Grimes 482a136efe9SPeter Wemm GIANT_REQUIRED; 483c96d52a9SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 4849ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 485a136efe9SPeter Wemm #ifdef NO_SWAPPING 486a136efe9SPeter Wemm if ((p->p_sflag & PS_INMEM) == 0) 487a136efe9SPeter Wemm panic("faultin: proc swapped out with NO_SWAPPING!"); 488a136efe9SPeter Wemm #else 4895074aecdSJohn Baldwin if ((p->p_sflag & PS_INMEM) == 0) { 490a136efe9SPeter Wemm struct thread *td; 491a136efe9SPeter Wemm 49226f9a767SRodney W. Grimes ++p->p_lock; 4939ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 49445ece682SJohn Baldwin PROC_UNLOCK(p); 49526f9a767SRodney W. Grimes 496a136efe9SPeter Wemm vm_proc_swapin(p); 497b40ce416SJulian Elischer FOREACH_THREAD_IN_PROC (p, td) 498b40ce416SJulian Elischer pmap_swapin_thread(td); 49926f9a767SRodney W. Grimes 50045ece682SJohn Baldwin PROC_LOCK(p); 5019ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 502b40ce416SJulian Elischer FOREACH_THREAD_IN_PROC (p, td) 503e602ba25SJulian Elischer if (td->td_state == TDS_RUNQ) /* XXXKSE */ 504b40ce416SJulian Elischer setrunqueue(td); 50526f9a767SRodney W. Grimes 5065074aecdSJohn Baldwin p->p_sflag |= PS_INMEM; 50726f9a767SRodney W. Grimes 50826f9a767SRodney W. Grimes /* undo the effect of setting SLOCK above */ 50926f9a767SRodney W. Grimes --p->p_lock; 51026f9a767SRodney W. Grimes } 511a136efe9SPeter Wemm #endif 5129ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 51326f9a767SRodney W. Grimes } 51426f9a767SRodney W. Grimes 515df8bae1dSRodney W. Grimes /* 51626f9a767SRodney W. Grimes * This swapin algorithm attempts to swap-in processes only if there 51726f9a767SRodney W. Grimes * is enough space for them. Of course, if a process waits for a long 51826f9a767SRodney W. Grimes * time, it will be swapped in anyway. 5190384fff8SJason Evans * 520e602ba25SJulian Elischer * XXXKSE - process with the thread with highest priority counts.. 521b40ce416SJulian Elischer * 5220384fff8SJason Evans * Giant is still held at this point, to be released in tsleep. 523df8bae1dSRodney W. Grimes */ 5242b14f991SJulian Elischer /* ARGSUSED*/ 5252b14f991SJulian Elischer static void 526d841aaa7SBruce Evans scheduler(dummy) 527d841aaa7SBruce Evans void *dummy; 528df8bae1dSRodney W. Grimes { 52954d92145SMatthew Dillon struct proc *p; 530e602ba25SJulian Elischer struct thread *td; 53154d92145SMatthew Dillon int pri; 532df8bae1dSRodney W. Grimes struct proc *pp; 533df8bae1dSRodney W. Grimes int ppri; 534df8bae1dSRodney W. Grimes 535c96d52a9SJohn Baldwin mtx_assert(&Giant, MA_OWNED | MA_NOTRECURSED); 5360cddd8f0SMatthew Dillon /* GIANT_REQUIRED */ 5370384fff8SJason Evans 538df8bae1dSRodney W. Grimes loop: 53990ecac61SMatthew Dillon if (vm_page_count_min()) { 5400d94caffSDavid Greenman VM_WAIT; 54190ecac61SMatthew Dillon goto loop; 5420d94caffSDavid Greenman } 54326f9a767SRodney W. Grimes 544df8bae1dSRodney W. Grimes pp = NULL; 545df8bae1dSRodney W. Grimes ppri = INT_MIN; 5461005a129SJohn Baldwin sx_slock(&allproc_lock); 547b40ce416SJulian Elischer FOREACH_PROC_IN_SYSTEM(p) { 548b40ce416SJulian Elischer struct ksegrp *kg; 549e602ba25SJulian Elischer if (p->p_sflag & (PS_INMEM | PS_SWAPPING)) { 550e602ba25SJulian Elischer continue; 551e602ba25SJulian Elischer } 5529ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 553e602ba25SJulian Elischer FOREACH_THREAD_IN_PROC(p, td) { 554e602ba25SJulian Elischer /* Only consider runnable threads */ 555e602ba25SJulian Elischer if (td->td_state == TDS_RUNQ) { 556e602ba25SJulian Elischer kg = td->td_ksegrp; 557b40ce416SJulian Elischer pri = p->p_swtime + kg->kg_slptime; 5585074aecdSJohn Baldwin if ((p->p_sflag & PS_SWAPINREQ) == 0) { 559b40ce416SJulian Elischer pri -= kg->kg_nice * 8; 560a669a6e9SJohn Dyson } 56195461b45SJohn Dyson 56226f9a767SRodney W. Grimes /* 563b40ce416SJulian Elischer * if this ksegrp is higher priority 564b40ce416SJulian Elischer * and there is enough space, then select 565b40ce416SJulian Elischer * this process instead of the previous 566b40ce416SJulian Elischer * selection. 56726f9a767SRodney W. Grimes */ 5680d94caffSDavid Greenman if (pri > ppri) { 569df8bae1dSRodney W. Grimes pp = p; 570df8bae1dSRodney W. Grimes ppri = pri; 571df8bae1dSRodney W. Grimes } 572df8bae1dSRodney W. Grimes } 573b40ce416SJulian Elischer } 5749ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 575df8bae1dSRodney W. Grimes } 5761005a129SJohn Baldwin sx_sunlock(&allproc_lock); 57726f9a767SRodney W. Grimes 578df8bae1dSRodney W. Grimes /* 579a669a6e9SJohn Dyson * Nothing to do, back to sleep. 580df8bae1dSRodney W. Grimes */ 581df8bae1dSRodney W. Grimes if ((p = pp) == NULL) { 582ea754954SJohn Baldwin tsleep(&proc0, PVM, "sched", maxslp * hz / 2); 583df8bae1dSRodney W. Grimes goto loop; 584df8bae1dSRodney W. Grimes } 5859ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 5865074aecdSJohn Baldwin p->p_sflag &= ~PS_SWAPINREQ; 5879ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 588a669a6e9SJohn Dyson 589df8bae1dSRodney W. Grimes /* 59026f9a767SRodney W. Grimes * We would like to bring someone in. (only if there is space). 591e602ba25SJulian Elischer * [What checks the space? ] 592df8bae1dSRodney W. Grimes */ 59345ece682SJohn Baldwin PROC_LOCK(p); 59426f9a767SRodney W. Grimes faultin(p); 59545ece682SJohn Baldwin PROC_UNLOCK(p); 5969ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 597df8bae1dSRodney W. Grimes p->p_swtime = 0; 5989ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 599df8bae1dSRodney W. Grimes goto loop; 600df8bae1dSRodney W. Grimes } 601df8bae1dSRodney W. Grimes 6025afce282SDavid Greenman #ifndef NO_SWAPPING 6035afce282SDavid Greenman 604ceb0cf87SJohn Dyson /* 605ceb0cf87SJohn Dyson * Swap_idle_threshold1 is the guaranteed swapped in time for a process 606ceb0cf87SJohn Dyson */ 607303b270bSEivind Eklund static int swap_idle_threshold1 = 2; 608ceb0cf87SJohn Dyson SYSCTL_INT(_vm, OID_AUTO, swap_idle_threshold1, 609ceb0cf87SJohn Dyson CTLFLAG_RW, &swap_idle_threshold1, 0, ""); 610ceb0cf87SJohn Dyson 611ceb0cf87SJohn Dyson /* 612ceb0cf87SJohn Dyson * Swap_idle_threshold2 is the time that a process can be idle before 613ceb0cf87SJohn Dyson * it will be swapped out, if idle swapping is enabled. 614ceb0cf87SJohn Dyson */ 615303b270bSEivind Eklund static int swap_idle_threshold2 = 10; 616ceb0cf87SJohn Dyson SYSCTL_INT(_vm, OID_AUTO, swap_idle_threshold2, 617ceb0cf87SJohn Dyson CTLFLAG_RW, &swap_idle_threshold2, 0, ""); 618ceb0cf87SJohn Dyson 619df8bae1dSRodney W. Grimes /* 620df8bae1dSRodney W. Grimes * Swapout is driven by the pageout daemon. Very simple, we find eligible 621df8bae1dSRodney W. Grimes * procs and unwire their u-areas. We try to always "swap" at least one 622df8bae1dSRodney W. Grimes * process in case we need the room for a swapin. 623df8bae1dSRodney W. Grimes * If any procs have been sleeping/stopped for at least maxslp seconds, 624df8bae1dSRodney W. Grimes * they are swapped. Else, we swap the longest-sleeping or stopped process, 625df8bae1dSRodney W. Grimes * if any, otherwise the longest-resident process. 626df8bae1dSRodney W. Grimes */ 627df8bae1dSRodney W. Grimes void 6283a2dc656SJohn Dyson swapout_procs(action) 6293a2dc656SJohn Dyson int action; 630df8bae1dSRodney W. Grimes { 63154d92145SMatthew Dillon struct proc *p; 632e602ba25SJulian Elischer struct thread *td; 633b40ce416SJulian Elischer struct ksegrp *kg; 634df8bae1dSRodney W. Grimes struct proc *outp, *outp2; 635df8bae1dSRodney W. Grimes int outpri, outpri2; 636df8bae1dSRodney W. Grimes int didswap = 0; 637df8bae1dSRodney W. Grimes 6380cddd8f0SMatthew Dillon GIANT_REQUIRED; 6390cddd8f0SMatthew Dillon 640df8bae1dSRodney W. Grimes outp = outp2 = NULL; 64126f9a767SRodney W. Grimes outpri = outpri2 = INT_MIN; 6420d94caffSDavid Greenman retry: 6433a2189d4SJohn Baldwin sx_slock(&allproc_lock); 644e602ba25SJulian Elischer FOREACH_PROC_IN_SYSTEM(p) { 645b18bfc3dSJohn Dyson struct vmspace *vm; 646b40ce416SJulian Elischer int minslptime = 100000; 647b18bfc3dSJohn Dyson 6485074aecdSJohn Baldwin PROC_LOCK(p); 64969b40456SJohn Baldwin if (p->p_lock != 0 || 650e602ba25SJulian Elischer (p->p_flag & (P_STOPPED_SNGL|P_TRACED|P_SYSTEM|P_WEXIT)) != 0) { 6515074aecdSJohn Baldwin PROC_UNLOCK(p); 6525074aecdSJohn Baldwin continue; 6535074aecdSJohn Baldwin } 65423955314SAlfred Perlstein /* 65523955314SAlfred Perlstein * only aiod changes vmspace, however it will be 65623955314SAlfred Perlstein * skipped because of the if statement above checking 65723955314SAlfred Perlstein * for P_SYSTEM 65823955314SAlfred Perlstein */ 659b18bfc3dSJohn Dyson vm = p->p_vmspace; 6609ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 66169b40456SJohn Baldwin if ((p->p_sflag & (PS_INMEM|PS_SWAPPING)) != PS_INMEM) { 6629ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 663ea754954SJohn Baldwin PROC_UNLOCK(p); 66469b40456SJohn Baldwin continue; 66569b40456SJohn Baldwin } 66669b40456SJohn Baldwin 667e602ba25SJulian Elischer switch (p->p_state) { 6680d94caffSDavid Greenman default: 669e602ba25SJulian Elischer /* Don't swap out processes in any sort 670e602ba25SJulian Elischer * of 'special' state. */ 6719ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 672ea754954SJohn Baldwin PROC_UNLOCK(p); 673df8bae1dSRodney W. Grimes continue; 674df8bae1dSRodney W. Grimes 675e602ba25SJulian Elischer case PRS_NORMAL: 67626f9a767SRodney W. Grimes /* 677bfbfac11SDavid Greenman * do not swapout a realtime process 678b40ce416SJulian Elischer * Check all the thread groups.. 679bfbfac11SDavid Greenman */ 680b40ce416SJulian Elischer FOREACH_KSEGRP_IN_PROC(p, kg) { 6812c100766SJulian Elischer if (PRI_IS_REALTIME(kg->kg_pri_class)) { 6829ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 683ea754954SJohn Baldwin PROC_UNLOCK(p); 684b40ce416SJulian Elischer goto nextproc; 685c8a6b001SJohn Baldwin } 686bfbfac11SDavid Greenman 687bfbfac11SDavid Greenman /* 688b40ce416SJulian Elischer * Do not swapout a process waiting 689b40ce416SJulian Elischer * on a critical event of some kind. 690b40ce416SJulian Elischer * Also guarantee swap_idle_threshold1 691ceb0cf87SJohn Dyson * time in memory. 6920d94caffSDavid Greenman */ 693e602ba25SJulian Elischer if (kg->kg_slptime < swap_idle_threshold1) { 6949ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 695ea754954SJohn Baldwin PROC_UNLOCK(p); 696b40ce416SJulian Elischer goto nextproc; 697c8a6b001SJohn Baldwin } 698e602ba25SJulian Elischer FOREACH_THREAD_IN_PROC(p, td) { 699e602ba25SJulian Elischer if ((td->td_priority) < PSOCK) { 700e602ba25SJulian Elischer mtx_unlock_spin(&sched_lock); 701e602ba25SJulian Elischer PROC_UNLOCK(p); 702e602ba25SJulian Elischer goto nextproc; 703e602ba25SJulian Elischer } 704e602ba25SJulian Elischer } 705ceb0cf87SJohn Dyson /* 706b40ce416SJulian Elischer * If the system is under memory stress, 707b40ce416SJulian Elischer * or if we are swapping 708b40ce416SJulian Elischer * idle processes >= swap_idle_threshold2, 709b40ce416SJulian Elischer * then swap the process out. 710ceb0cf87SJohn Dyson */ 711ceb0cf87SJohn Dyson if (((action & VM_SWAP_NORMAL) == 0) && 712ceb0cf87SJohn Dyson (((action & VM_SWAP_IDLE) == 0) || 713b40ce416SJulian Elischer (kg->kg_slptime < swap_idle_threshold2))) { 7149ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 715ea754954SJohn Baldwin PROC_UNLOCK(p); 716b40ce416SJulian Elischer goto nextproc; 7175074aecdSJohn Baldwin } 718b40ce416SJulian Elischer if (minslptime > kg->kg_slptime) 719b40ce416SJulian Elischer minslptime = kg->kg_slptime; 720b40ce416SJulian Elischer } 7210d94caffSDavid Greenman 722b40ce416SJulian Elischer mtx_unlock_spin(&sched_lock); 723b18bfc3dSJohn Dyson ++vm->vm_refcnt; 724d3a34985SJohn Dyson /* 725b40ce416SJulian Elischer * do not swapout a process that 726b40ce416SJulian Elischer * is waiting for VM 727b40ce416SJulian Elischer * data structures there is a 728b40ce416SJulian Elischer * possible deadlock. 729d3a34985SJohn Dyson */ 730d974f03cSAlan Cox if (!vm_map_trylock(&vm->vm_map)) { 731b18bfc3dSJohn Dyson vmspace_free(vm); 732ea754954SJohn Baldwin PROC_UNLOCK(p); 733b40ce416SJulian Elischer goto nextproc; 734d3a34985SJohn Dyson } 735b18bfc3dSJohn Dyson vm_map_unlock(&vm->vm_map); 73611b224dcSDavid Greenman /* 7370d94caffSDavid Greenman * If the process has been asleep for awhile and had 7380d94caffSDavid Greenman * most of its pages taken away already, swap it out. 73911b224dcSDavid Greenman */ 740ceb0cf87SJohn Dyson if ((action & VM_SWAP_NORMAL) || 741ceb0cf87SJohn Dyson ((action & VM_SWAP_IDLE) && 742b40ce416SJulian Elischer (minslptime > swap_idle_threshold2))) { 7433a2189d4SJohn Baldwin sx_sunlock(&allproc_lock); 744df8bae1dSRodney W. Grimes swapout(p); 745b18bfc3dSJohn Dyson vmspace_free(vm); 746df8bae1dSRodney W. Grimes didswap++; 7470d94caffSDavid Greenman goto retry; 748c96d52a9SJohn Baldwin } 749ea754954SJohn Baldwin PROC_UNLOCK(p); 7503a2189d4SJohn Baldwin vmspace_free(vm); 75126f9a767SRodney W. Grimes } 752b40ce416SJulian Elischer nextproc: 75330171114SPeter Wemm continue; 754ceb0cf87SJohn Dyson } 7551005a129SJohn Baldwin sx_sunlock(&allproc_lock); 75626f9a767SRodney W. Grimes /* 75726f9a767SRodney W. Grimes * If we swapped something out, and another process needed memory, 75826f9a767SRodney W. Grimes * then wakeup the sched process. 75926f9a767SRodney W. Grimes */ 7600d94caffSDavid Greenman if (didswap) 76124a1cce3SDavid Greenman wakeup(&proc0); 762df8bae1dSRodney W. Grimes } 763df8bae1dSRodney W. Grimes 764f708ef1bSPoul-Henning Kamp static void 765df8bae1dSRodney W. Grimes swapout(p) 76654d92145SMatthew Dillon struct proc *p; 767df8bae1dSRodney W. Grimes { 768b40ce416SJulian Elischer struct thread *td; 769df8bae1dSRodney W. Grimes 770ea754954SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 771d3a34985SJohn Dyson #if defined(SWAP_DEBUG) 772d3a34985SJohn Dyson printf("swapping out %d\n", p->p_pid); 773d3a34985SJohn Dyson #endif 77426f9a767SRodney W. Grimes ++p->p_stats->p_ru.ru_nswap; 775df8bae1dSRodney W. Grimes /* 77626f9a767SRodney W. Grimes * remember the process resident count 777df8bae1dSRodney W. Grimes */ 778b1028ad1SLuoqi Chen p->p_vmspace->vm_swrss = vmspace_resident_count(p->p_vmspace); 779df8bae1dSRodney W. Grimes 7809ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 7815074aecdSJohn Baldwin p->p_sflag &= ~PS_INMEM; 7825074aecdSJohn Baldwin p->p_sflag |= PS_SWAPPING; 783c86b6ff5SJohn Baldwin PROC_UNLOCK(p); 784b40ce416SJulian Elischer FOREACH_THREAD_IN_PROC (p, td) 785e602ba25SJulian Elischer if (td->td_state == TDS_RUNQ) /* XXXKSE */ 786b40ce416SJulian Elischer remrunqueue(td); /* XXXKSE */ 7879ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 78826f9a767SRodney W. Grimes 789a136efe9SPeter Wemm vm_proc_swapout(p); 790b40ce416SJulian Elischer FOREACH_THREAD_IN_PROC(p, td) 791b40ce416SJulian Elischer pmap_swapout_thread(td); 7929ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 7935074aecdSJohn Baldwin p->p_sflag &= ~PS_SWAPPING; 794df8bae1dSRodney W. Grimes p->p_swtime = 0; 7959ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 796df8bae1dSRodney W. Grimes } 7975afce282SDavid Greenman #endif /* !NO_SWAPPING */ 798