1df8bae1dSRodney W. Grimes /* 226f9a767SRodney W. Grimes * Copyright (c) 1991 Regents of the University of California. 326f9a767SRodney W. Grimes * All rights reserved. 426f9a767SRodney W. Grimes * Copyright (c) 1994 John S. Dyson 526f9a767SRodney W. Grimes * All rights reserved. 626f9a767SRodney W. Grimes * Copyright (c) 1994 David Greenman 726f9a767SRodney W. Grimes * All rights reserved. 8df8bae1dSRodney W. Grimes * 9df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 10df8bae1dSRodney W. Grimes * The Mach Operating System project at Carnegie-Mellon University. 11df8bae1dSRodney W. Grimes * 12df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 13df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 14df8bae1dSRodney W. Grimes * are met: 15df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 17df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 18df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 19df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 20df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 21df8bae1dSRodney W. Grimes * must display the following acknowledgement: 22df8bae1dSRodney W. Grimes * This product includes software developed by the University of 23df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 24df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 25df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 26df8bae1dSRodney W. Grimes * without specific prior written permission. 27df8bae1dSRodney W. Grimes * 28df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38df8bae1dSRodney W. Grimes * SUCH DAMAGE. 39df8bae1dSRodney W. Grimes * 4026f9a767SRodney W. Grimes * @(#)vm_pageout.c 7.4 (Berkeley) 5/7/91 41df8bae1dSRodney W. Grimes * 42df8bae1dSRodney W. Grimes * 43df8bae1dSRodney W. Grimes * Copyright (c) 1987, 1990 Carnegie-Mellon University. 44df8bae1dSRodney W. Grimes * All rights reserved. 45df8bae1dSRodney W. Grimes * 46df8bae1dSRodney W. Grimes * Authors: Avadis Tevanian, Jr., Michael Wayne Young 47df8bae1dSRodney W. Grimes * 48df8bae1dSRodney W. Grimes * Permission to use, copy, modify and distribute this software and 49df8bae1dSRodney W. Grimes * its documentation is hereby granted, provided that both the copyright 50df8bae1dSRodney W. Grimes * notice and this permission notice appear in all copies of the 51df8bae1dSRodney W. Grimes * software, derivative works or modified versions, and any portions 52df8bae1dSRodney W. Grimes * thereof, and that both notices appear in supporting documentation. 53df8bae1dSRodney W. Grimes * 54df8bae1dSRodney W. Grimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 55df8bae1dSRodney W. Grimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 56df8bae1dSRodney W. Grimes * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 57df8bae1dSRodney W. Grimes * 58df8bae1dSRodney W. Grimes * Carnegie Mellon requests users of this software to return to 59df8bae1dSRodney W. Grimes * 60df8bae1dSRodney W. Grimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 61df8bae1dSRodney W. Grimes * School of Computer Science 62df8bae1dSRodney W. Grimes * Carnegie Mellon University 63df8bae1dSRodney W. Grimes * Pittsburgh PA 15213-3890 64df8bae1dSRodney W. Grimes * 65df8bae1dSRodney W. Grimes * any improvements or extensions that they make and grant Carnegie the 66df8bae1dSRodney W. Grimes * rights to redistribute these changes. 6726f9a767SRodney W. Grimes * 6826f9a767SRodney W. Grimes * $Id: vm_pageout.c,v 1.20 1994/04/20 07:07:15 davidg Exp $ 69df8bae1dSRodney W. Grimes */ 70df8bae1dSRodney W. Grimes 71df8bae1dSRodney W. Grimes /* 72df8bae1dSRodney W. Grimes * The proverbial page-out daemon. 73df8bae1dSRodney W. Grimes */ 74df8bae1dSRodney W. Grimes 75df8bae1dSRodney W. Grimes #include <sys/param.h> 7626f9a767SRodney W. Grimes #include <sys/systm.h> 7726f9a767SRodney W. Grimes #include <sys/proc.h> 7826f9a767SRodney W. Grimes #include <sys/resourcevar.h> 7926f9a767SRodney W. Grimes #include <sys/malloc.h> 80df8bae1dSRodney W. Grimes 81df8bae1dSRodney W. Grimes #include <vm/vm.h> 82df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 83df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h> 84df8bae1dSRodney W. Grimes 8526f9a767SRodney W. Grimes extern vm_map_t kmem_map; 86df8bae1dSRodney W. Grimes int vm_pages_needed; /* Event on which pageout daemon sleeps */ 8726f9a767SRodney W. Grimes int vm_pagescanner; /* Event on which pagescanner sleeps */ 8826f9a767SRodney W. Grimes int vm_pageout_free_min = 0; /* Stop pageout to wait for pagers at this free level */ 8926f9a767SRodney W. Grimes 9026f9a767SRodney W. Grimes int vm_pageout_pages_needed = 0; /* flag saying that the pageout daemon needs pages */ 9126f9a767SRodney W. Grimes int vm_page_pagesfreed; 9226f9a767SRodney W. Grimes 9326f9a767SRodney W. Grimes extern int npendingio; 9426f9a767SRodney W. Grimes extern int hz; 9526f9a767SRodney W. Grimes int vm_pageout_proc_limit; 9626f9a767SRodney W. Grimes extern int nswiodone; 9726f9a767SRodney W. Grimes extern int swap_pager_full; 9826f9a767SRodney W. Grimes extern int swap_pager_ready(); 9926f9a767SRodney W. Grimes 10026f9a767SRodney W. Grimes #define MAXREF 32767 10126f9a767SRodney W. Grimes 10226f9a767SRodney W. Grimes #define MAXSCAN 512 /* maximum number of pages to scan in active queue */ 10326f9a767SRodney W. Grimes /* set the "clock" hands to be (MAXSCAN * 4096) Bytes */ 10426f9a767SRodney W. Grimes #define ACT_DECLINE 1 10526f9a767SRodney W. Grimes #define ACT_ADVANCE 6 10626f9a767SRodney W. Grimes #define ACT_MAX 300 10726f9a767SRodney W. Grimes 10826f9a767SRodney W. Grimes #define LOWATER ((2048*1024)/NBPG) 10926f9a767SRodney W. Grimes 11026f9a767SRodney W. Grimes #define VM_PAGEOUT_PAGE_COUNT 8 11126f9a767SRodney W. Grimes static vm_offset_t vm_space_needed; 11226f9a767SRodney W. Grimes int vm_pageout_req_do_stats; 113df8bae1dSRodney W. Grimes 114df8bae1dSRodney W. Grimes int vm_page_max_wired = 0; /* XXX max # of wired pages system-wide */ 115df8bae1dSRodney W. Grimes 11626f9a767SRodney W. Grimes 11726f9a767SRodney W. Grimes /* 11826f9a767SRodney W. Grimes * vm_pageout_clean: 11926f9a767SRodney W. Grimes * cleans a vm_page 12026f9a767SRodney W. Grimes */ 12126f9a767SRodney W. Grimes int 12226f9a767SRodney W. Grimes vm_pageout_clean(m, sync) 12326f9a767SRodney W. Grimes register vm_page_t m; 12426f9a767SRodney W. Grimes int sync; 12526f9a767SRodney W. Grimes { 12626f9a767SRodney W. Grimes /* 12726f9a767SRodney W. Grimes * Clean the page and remove it from the 12826f9a767SRodney W. Grimes * laundry. 12926f9a767SRodney W. Grimes * 13026f9a767SRodney W. Grimes * We set the busy bit to cause 13126f9a767SRodney W. Grimes * potential page faults on this page to 13226f9a767SRodney W. Grimes * block. 13326f9a767SRodney W. Grimes * 13426f9a767SRodney W. Grimes * And we set pageout-in-progress to keep 13526f9a767SRodney W. Grimes * the object from disappearing during 13626f9a767SRodney W. Grimes * pageout. This guarantees that the 13726f9a767SRodney W. Grimes * page won't move from the inactive 13826f9a767SRodney W. Grimes * queue. (However, any other page on 13926f9a767SRodney W. Grimes * the inactive queue may move!) 14026f9a767SRodney W. Grimes */ 14126f9a767SRodney W. Grimes 14226f9a767SRodney W. Grimes register vm_object_t object; 14326f9a767SRodney W. Grimes register vm_pager_t pager; 14426f9a767SRodney W. Grimes int pageout_status[VM_PAGEOUT_PAGE_COUNT]; 14526f9a767SRodney W. Grimes vm_page_t ms[VM_PAGEOUT_PAGE_COUNT]; 14626f9a767SRodney W. Grimes int pageout_count; 14726f9a767SRodney W. Grimes int anyok=0; 14826f9a767SRodney W. Grimes int i; 14926f9a767SRodney W. Grimes vm_offset_t offset = m->offset; 15026f9a767SRodney W. Grimes 15126f9a767SRodney W. Grimes object = m->object; 15226f9a767SRodney W. Grimes if (!object) { 15326f9a767SRodney W. Grimes printf("pager: object missing\n"); 15426f9a767SRodney W. Grimes return 0; 15526f9a767SRodney W. Grimes } 15626f9a767SRodney W. Grimes 15726f9a767SRodney W. Grimes /* 15826f9a767SRodney W. Grimes * Try to collapse the object before 15926f9a767SRodney W. Grimes * making a pager for it. We must 16026f9a767SRodney W. Grimes * unlock the page queues first. 16126f9a767SRodney W. Grimes * We try to defer the creation of a pager 16226f9a767SRodney W. Grimes * until all shadows are not paging. This 16326f9a767SRodney W. Grimes * allows vm_object_collapse to work better and 16426f9a767SRodney W. Grimes * helps control swap space size. 16526f9a767SRodney W. Grimes * (J. Dyson 11 Nov 93) 16626f9a767SRodney W. Grimes */ 16726f9a767SRodney W. Grimes 16826f9a767SRodney W. Grimes if (!object->pager && 16926f9a767SRodney W. Grimes cnt.v_free_count < vm_pageout_free_min) 17026f9a767SRodney W. Grimes return 0; 17126f9a767SRodney W. Grimes 17226f9a767SRodney W. Grimes if (!object->pager && 17326f9a767SRodney W. Grimes object->shadow && 17426f9a767SRodney W. Grimes object->shadow->paging_in_progress) 17526f9a767SRodney W. Grimes return 0; 17626f9a767SRodney W. Grimes 17726f9a767SRodney W. Grimes if( !sync) { 17826f9a767SRodney W. Grimes if (object->shadow) { 17926f9a767SRodney W. Grimes vm_object_collapse(object); 18026f9a767SRodney W. Grimes if (!vm_page_lookup(object, offset)) 18126f9a767SRodney W. Grimes return 0; 18226f9a767SRodney W. Grimes } 18326f9a767SRodney W. Grimes 18426f9a767SRodney W. Grimes if ((m->flags & PG_BUSY) || (m->hold_count != 0)) { 18526f9a767SRodney W. Grimes return 0; 18626f9a767SRodney W. Grimes } 18726f9a767SRodney W. Grimes } 18826f9a767SRodney W. Grimes 18926f9a767SRodney W. Grimes pageout_count = 1; 19026f9a767SRodney W. Grimes ms[0] = m; 19126f9a767SRodney W. Grimes 19226f9a767SRodney W. Grimes if( pager = object->pager) { 19326f9a767SRodney W. Grimes for(i=1;i<VM_PAGEOUT_PAGE_COUNT;i++) { 19426f9a767SRodney W. Grimes if( ms[i] = vm_page_lookup( object, offset+i*NBPG)) { 19526f9a767SRodney W. Grimes if((((ms[i]->flags & (PG_CLEAN|PG_INACTIVE|PG_BUSY)) == PG_INACTIVE) 19626f9a767SRodney W. Grimes || (( ms[i]->flags & PG_CLEAN) == 0 && sync == VM_PAGEOUT_FORCE)) 19726f9a767SRodney W. Grimes && (ms[i]->wire_count == 0) 19826f9a767SRodney W. Grimes && (ms[i]->hold_count == 0)) 19926f9a767SRodney W. Grimes pageout_count++; 20026f9a767SRodney W. Grimes else 20126f9a767SRodney W. Grimes break; 20226f9a767SRodney W. Grimes } else 20326f9a767SRodney W. Grimes break; 20426f9a767SRodney W. Grimes } 20526f9a767SRodney W. Grimes for(i=0;i<pageout_count;i++) { 20626f9a767SRodney W. Grimes ms[i]->flags |= PG_BUSY; 20726f9a767SRodney W. Grimes pmap_page_protect(VM_PAGE_TO_PHYS(ms[i]), VM_PROT_READ); 20826f9a767SRodney W. Grimes } 20926f9a767SRodney W. Grimes object->paging_in_progress += pageout_count; 21026f9a767SRodney W. Grimes cnt.v_pageouts += pageout_count; 21126f9a767SRodney W. Grimes } else { 21226f9a767SRodney W. Grimes 21326f9a767SRodney W. Grimes m->flags |= PG_BUSY; 21426f9a767SRodney W. Grimes 21526f9a767SRodney W. Grimes pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_READ); 21626f9a767SRodney W. Grimes 21726f9a767SRodney W. Grimes cnt.v_pageouts++; 21826f9a767SRodney W. Grimes 21926f9a767SRodney W. Grimes object->paging_in_progress++; 22026f9a767SRodney W. Grimes 22126f9a767SRodney W. Grimes pager = vm_pager_allocate(PG_DFLT, (caddr_t)0, 22226f9a767SRodney W. Grimes object->size, VM_PROT_ALL, 0); 22326f9a767SRodney W. Grimes if (pager != NULL) { 22426f9a767SRodney W. Grimes vm_object_setpager(object, pager, 0, FALSE); 22526f9a767SRodney W. Grimes } 22626f9a767SRodney W. Grimes } 22726f9a767SRodney W. Grimes 22826f9a767SRodney W. Grimes /* 22926f9a767SRodney W. Grimes * If there is no pager for the page, 23026f9a767SRodney W. Grimes * use the default pager. If there's 23126f9a767SRodney W. Grimes * no place to put the page at the 23226f9a767SRodney W. Grimes * moment, leave it in the laundry and 23326f9a767SRodney W. Grimes * hope that there will be paging space 23426f9a767SRodney W. Grimes * later. 23526f9a767SRodney W. Grimes */ 23626f9a767SRodney W. Grimes 23726f9a767SRodney W. Grimes if ((pager && pager->pg_type == PG_SWAP) || 23826f9a767SRodney W. Grimes cnt.v_free_count >= vm_pageout_free_min) { 23926f9a767SRodney W. Grimes if( pageout_count == 1) { 24026f9a767SRodney W. Grimes pageout_status[0] = pager ? 24126f9a767SRodney W. Grimes vm_pager_put(pager, m, 24226f9a767SRodney W. Grimes ((sync || (object == kernel_object)) ? TRUE: FALSE)) : 24326f9a767SRodney W. Grimes VM_PAGER_FAIL; 24426f9a767SRodney W. Grimes } else { 24526f9a767SRodney W. Grimes if( !pager) { 24626f9a767SRodney W. Grimes for(i=0;i<pageout_count;i++) 24726f9a767SRodney W. Grimes pageout_status[i] = VM_PAGER_FAIL; 24826f9a767SRodney W. Grimes } else { 24926f9a767SRodney W. Grimes vm_pager_put_pages(pager, ms, pageout_count, 25026f9a767SRodney W. Grimes ((sync || (object == kernel_object)) ? TRUE : FALSE), 25126f9a767SRodney W. Grimes pageout_status); 25226f9a767SRodney W. Grimes } 25326f9a767SRodney W. Grimes } 25426f9a767SRodney W. Grimes 25526f9a767SRodney W. Grimes } else { 25626f9a767SRodney W. Grimes for(i=0;i<pageout_count;i++) 25726f9a767SRodney W. Grimes pageout_status[i] = VM_PAGER_FAIL; 25826f9a767SRodney W. Grimes } 25926f9a767SRodney W. Grimes 26026f9a767SRodney W. Grimes for(i=0;i<pageout_count;i++) { 26126f9a767SRodney W. Grimes switch (pageout_status[i]) { 26226f9a767SRodney W. Grimes case VM_PAGER_OK: 26326f9a767SRodney W. Grimes ms[i]->flags &= ~PG_LAUNDRY; 26426f9a767SRodney W. Grimes ++anyok; 26526f9a767SRodney W. Grimes break; 26626f9a767SRodney W. Grimes case VM_PAGER_PEND: 26726f9a767SRodney W. Grimes ms[i]->flags &= ~PG_LAUNDRY; 26826f9a767SRodney W. Grimes ++anyok; 26926f9a767SRodney W. Grimes break; 27026f9a767SRodney W. Grimes case VM_PAGER_BAD: 27126f9a767SRodney W. Grimes /* 27226f9a767SRodney W. Grimes * Page outside of range of object. 27326f9a767SRodney W. Grimes * Right now we essentially lose the 27426f9a767SRodney W. Grimes * changes by pretending it worked. 27526f9a767SRodney W. Grimes */ 27626f9a767SRodney W. Grimes ms[i]->flags &= ~PG_LAUNDRY; 27726f9a767SRodney W. Grimes ms[i]->flags |= PG_CLEAN; 27826f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(ms[i])); 27926f9a767SRodney W. Grimes break; 28026f9a767SRodney W. Grimes case VM_PAGER_ERROR: 28126f9a767SRodney W. Grimes case VM_PAGER_FAIL: 28226f9a767SRodney W. Grimes /* 28326f9a767SRodney W. Grimes * If page couldn't be paged out, then 28426f9a767SRodney W. Grimes * reactivate the page so it doesn't 28526f9a767SRodney W. Grimes * clog the inactive list. (We will 28626f9a767SRodney W. Grimes * try paging out it again later). 28726f9a767SRodney W. Grimes */ 28826f9a767SRodney W. Grimes if (ms[i]->flags & PG_INACTIVE) 28926f9a767SRodney W. Grimes vm_page_activate(ms[i]); 29026f9a767SRodney W. Grimes break; 29126f9a767SRodney W. Grimes case VM_PAGER_AGAIN: 29226f9a767SRodney W. Grimes break; 29326f9a767SRodney W. Grimes } 29426f9a767SRodney W. Grimes 29526f9a767SRodney W. Grimes 29626f9a767SRodney W. Grimes /* 29726f9a767SRodney W. Grimes * If the operation is still going, leave 29826f9a767SRodney W. Grimes * the page busy to block all other accesses. 29926f9a767SRodney W. Grimes * Also, leave the paging in progress 30026f9a767SRodney W. Grimes * indicator set so that we don't attempt an 30126f9a767SRodney W. Grimes * object collapse. 30226f9a767SRodney W. Grimes */ 30326f9a767SRodney W. Grimes if (pageout_status[i] != VM_PAGER_PEND) { 30426f9a767SRodney W. Grimes PAGE_WAKEUP(ms[i]); 30526f9a767SRodney W. Grimes if (--object->paging_in_progress == 0) 30626f9a767SRodney W. Grimes wakeup((caddr_t) object); 30726f9a767SRodney W. Grimes if (pmap_is_referenced(VM_PAGE_TO_PHYS(ms[i]))) { 30826f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(ms[i])); 30926f9a767SRodney W. Grimes if( ms[i]->flags & PG_INACTIVE) 31026f9a767SRodney W. Grimes vm_page_activate(ms[i]); 31126f9a767SRodney W. Grimes } 31226f9a767SRodney W. Grimes } 31326f9a767SRodney W. Grimes } 31426f9a767SRodney W. Grimes return anyok; 31526f9a767SRodney W. Grimes } 31626f9a767SRodney W. Grimes 31726f9a767SRodney W. Grimes /* 31826f9a767SRodney W. Grimes * vm_pageout_object_deactivate_pages 31926f9a767SRodney W. Grimes * 32026f9a767SRodney W. Grimes * deactivate enough pages to satisfy the inactive target 32126f9a767SRodney W. Grimes * requirements or if vm_page_proc_limit is set, then 32226f9a767SRodney W. Grimes * deactivate all of the pages in the object and its 32326f9a767SRodney W. Grimes * shadows. 32426f9a767SRodney W. Grimes * 32526f9a767SRodney W. Grimes * The object and map must be locked. 32626f9a767SRodney W. Grimes */ 32726f9a767SRodney W. Grimes int 32826f9a767SRodney W. Grimes vm_pageout_object_deactivate_pages(map, object, count) 32926f9a767SRodney W. Grimes vm_map_t map; 33026f9a767SRodney W. Grimes vm_object_t object; 33126f9a767SRodney W. Grimes int count; 33226f9a767SRodney W. Grimes { 33326f9a767SRodney W. Grimes register vm_page_t p, next; 33426f9a767SRodney W. Grimes int rcount; 33526f9a767SRodney W. Grimes int s; 33626f9a767SRodney W. Grimes int dcount; 33726f9a767SRodney W. Grimes 33826f9a767SRodney W. Grimes dcount = 0; 33926f9a767SRodney W. Grimes if (count == 0) 34026f9a767SRodney W. Grimes count = 1; 34126f9a767SRodney W. Grimes 34226f9a767SRodney W. Grimes if (object->shadow) { 34326f9a767SRodney W. Grimes int scount = count; 34426f9a767SRodney W. Grimes if( object->shadow->ref_count > 1) 34526f9a767SRodney W. Grimes scount /= object->shadow->ref_count; 34626f9a767SRodney W. Grimes if( scount) 34726f9a767SRodney W. Grimes dcount += vm_pageout_object_deactivate_pages(map, object->shadow, scount); 34826f9a767SRodney W. Grimes } 34926f9a767SRodney W. Grimes 35026f9a767SRodney W. Grimes if (object->paging_in_progress) 35126f9a767SRodney W. Grimes return dcount; 35226f9a767SRodney W. Grimes 35326f9a767SRodney W. Grimes /* 35426f9a767SRodney W. Grimes * scan the objects entire memory queue 35526f9a767SRodney W. Grimes */ 35626f9a767SRodney W. Grimes rcount = object->resident_page_count; 35726f9a767SRodney W. Grimes p = object->memq.tqh_first; 35826f9a767SRodney W. Grimes while (p && (rcount-- > 0)) { 35926f9a767SRodney W. Grimes next = p->listq.tqe_next; 36026f9a767SRodney W. Grimes vm_page_lock_queues(); 36126f9a767SRodney W. Grimes /* 36226f9a767SRodney W. Grimes * if a page is active, not wired and is in the processes pmap, 36326f9a767SRodney W. Grimes * then deactivate the page. 36426f9a767SRodney W. Grimes */ 36526f9a767SRodney W. Grimes if ((p->flags & (PG_ACTIVE|PG_BUSY)) == PG_ACTIVE && 36626f9a767SRodney W. Grimes p->wire_count == 0 && 36726f9a767SRodney W. Grimes p->hold_count == 0 && 36826f9a767SRodney W. Grimes pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) { 36926f9a767SRodney W. Grimes if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p))) { 37026f9a767SRodney W. Grimes p->act_count -= min(p->act_count, ACT_DECLINE); 37126f9a767SRodney W. Grimes /* 37226f9a767SRodney W. Grimes * if the page act_count is zero -- then we deactivate 37326f9a767SRodney W. Grimes */ 37426f9a767SRodney W. Grimes if (!p->act_count) { 37526f9a767SRodney W. Grimes vm_page_deactivate(p); 37626f9a767SRodney W. Grimes pmap_page_protect(VM_PAGE_TO_PHYS(p), 37726f9a767SRodney W. Grimes VM_PROT_NONE); 37826f9a767SRodney W. Grimes /* 37926f9a767SRodney W. Grimes * else if on the next go-around we will deactivate the page 38026f9a767SRodney W. Grimes * we need to place the page on the end of the queue to age 38126f9a767SRodney W. Grimes * the other pages in memory. 38226f9a767SRodney W. Grimes */ 38326f9a767SRodney W. Grimes } else { 38426f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, p, pageq); 38526f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq); 38626f9a767SRodney W. Grimes TAILQ_REMOVE(&object->memq, p, listq); 38726f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&object->memq, p, listq); 38826f9a767SRodney W. Grimes } 38926f9a767SRodney W. Grimes /* 39026f9a767SRodney W. Grimes * see if we are done yet 39126f9a767SRodney W. Grimes */ 39226f9a767SRodney W. Grimes if (p->flags & PG_INACTIVE) { 39326f9a767SRodney W. Grimes --count; 39426f9a767SRodney W. Grimes ++dcount; 39526f9a767SRodney W. Grimes if (count <= 0 && 39626f9a767SRodney W. Grimes cnt.v_inactive_count > cnt.v_inactive_target) { 39726f9a767SRodney W. Grimes vm_page_unlock_queues(); 39826f9a767SRodney W. Grimes return dcount; 39926f9a767SRodney W. Grimes } 40026f9a767SRodney W. Grimes } 40126f9a767SRodney W. Grimes 40226f9a767SRodney W. Grimes } else { 40326f9a767SRodney W. Grimes /* 40426f9a767SRodney W. Grimes * Move the page to the bottom of the queue. 40526f9a767SRodney W. Grimes */ 40626f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(p)); 40726f9a767SRodney W. Grimes if (p->act_count < ACT_MAX) 40826f9a767SRodney W. Grimes p->act_count += ACT_ADVANCE; 40926f9a767SRodney W. Grimes 41026f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, p, pageq); 41126f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq); 41226f9a767SRodney W. Grimes TAILQ_REMOVE(&object->memq, p, listq); 41326f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&object->memq, p, listq); 41426f9a767SRodney W. Grimes } 41526f9a767SRodney W. Grimes } 41626f9a767SRodney W. Grimes 41726f9a767SRodney W. Grimes vm_page_unlock_queues(); 41826f9a767SRodney W. Grimes p = next; 41926f9a767SRodney W. Grimes } 42026f9a767SRodney W. Grimes return dcount; 42126f9a767SRodney W. Grimes } 42226f9a767SRodney W. Grimes 42326f9a767SRodney W. Grimes 42426f9a767SRodney W. Grimes /* 42526f9a767SRodney W. Grimes * deactivate some number of pages in a map, try to do it fairly, but 42626f9a767SRodney W. Grimes * that is really hard to do. 42726f9a767SRodney W. Grimes */ 42826f9a767SRodney W. Grimes 42926f9a767SRodney W. Grimes void 43026f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(map, entry, count, freeer) 43126f9a767SRodney W. Grimes vm_map_t map; 43226f9a767SRodney W. Grimes vm_map_entry_t entry; 43326f9a767SRodney W. Grimes int *count; 43426f9a767SRodney W. Grimes int (*freeer)(vm_map_t, vm_object_t, int); 43526f9a767SRodney W. Grimes { 43626f9a767SRodney W. Grimes vm_map_t tmpm; 43726f9a767SRodney W. Grimes vm_map_entry_t tmpe; 43826f9a767SRodney W. Grimes vm_object_t obj; 43926f9a767SRodney W. Grimes if (*count <= 0) 44026f9a767SRodney W. Grimes return; 44126f9a767SRodney W. Grimes vm_map_reference(map); 44226f9a767SRodney W. Grimes if (!lock_try_read(&map->lock)) { 44326f9a767SRodney W. Grimes vm_map_deallocate(map); 44426f9a767SRodney W. Grimes return; 44526f9a767SRodney W. Grimes } 44626f9a767SRodney W. Grimes if (entry == 0) { 44726f9a767SRodney W. Grimes tmpe = map->header.next; 44826f9a767SRodney W. Grimes while (tmpe != &map->header && *count > 0) { 44926f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(map, tmpe, count, freeer); 45026f9a767SRodney W. Grimes tmpe = tmpe->next; 45126f9a767SRodney W. Grimes }; 45226f9a767SRodney W. Grimes } else if (entry->is_sub_map || entry->is_a_map) { 45326f9a767SRodney W. Grimes tmpm = entry->object.share_map; 45426f9a767SRodney W. Grimes tmpe = tmpm->header.next; 45526f9a767SRodney W. Grimes while (tmpe != &tmpm->header && *count > 0) { 45626f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(tmpm, tmpe, count, freeer); 45726f9a767SRodney W. Grimes tmpe = tmpe->next; 45826f9a767SRodney W. Grimes }; 45926f9a767SRodney W. Grimes } else if (obj = entry->object.vm_object) { 46026f9a767SRodney W. Grimes *count -= (*freeer)(map, obj, *count); 46126f9a767SRodney W. Grimes } 46226f9a767SRodney W. Grimes lock_read_done(&map->lock); 46326f9a767SRodney W. Grimes vm_map_deallocate(map); 46426f9a767SRodney W. Grimes return; 46526f9a767SRodney W. Grimes } 466df8bae1dSRodney W. Grimes 467df8bae1dSRodney W. Grimes /* 468df8bae1dSRodney W. Grimes * vm_pageout_scan does the dirty work for the pageout daemon. 469df8bae1dSRodney W. Grimes */ 47026f9a767SRodney W. Grimes int 471df8bae1dSRodney W. Grimes vm_pageout_scan() 472df8bae1dSRodney W. Grimes { 47326f9a767SRodney W. Grimes vm_page_t m; 47426f9a767SRodney W. Grimes int page_shortage, maxscan, maxlaunder; 47526f9a767SRodney W. Grimes int pages_freed, free, nproc; 47626f9a767SRodney W. Grimes int desired_free; 47726f9a767SRodney W. Grimes vm_page_t next; 47826f9a767SRodney W. Grimes struct proc *p; 479df8bae1dSRodney W. Grimes vm_object_t object; 48026f9a767SRodney W. Grimes int s; 48126f9a767SRodney W. Grimes int force_wakeup = 0; 482df8bae1dSRodney W. Grimes 48326f9a767SRodney W. Grimes morefree: 484df8bae1dSRodney W. Grimes /* 48526f9a767SRodney W. Grimes * scan the processes for exceeding their rlimits or if process 48626f9a767SRodney W. Grimes * is swapped out -- deactivate pages 487df8bae1dSRodney W. Grimes */ 488df8bae1dSRodney W. Grimes 48926f9a767SRodney W. Grimes rescanproc1: 49026f9a767SRodney W. Grimes for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 49126f9a767SRodney W. Grimes vm_offset_t size; 49226f9a767SRodney W. Grimes int overage; 49326f9a767SRodney W. Grimes vm_offset_t limit; 494df8bae1dSRodney W. Grimes 495df8bae1dSRodney W. Grimes /* 49626f9a767SRodney W. Grimes * if this is a system process or if we have already 49726f9a767SRodney W. Grimes * looked at this process, skip it. 498df8bae1dSRodney W. Grimes */ 49926f9a767SRodney W. Grimes if (p->p_flag & (P_SYSTEM|P_WEXIT)) { 50026f9a767SRodney W. Grimes continue; 501df8bae1dSRodney W. Grimes } 502df8bae1dSRodney W. Grimes 503df8bae1dSRodney W. Grimes /* 50426f9a767SRodney W. Grimes * if the process is in a non-running type state, 50526f9a767SRodney W. Grimes * don't touch it. 506df8bae1dSRodney W. Grimes */ 50726f9a767SRodney W. Grimes if (p->p_stat != SRUN && p->p_stat != SSLEEP) { 50826f9a767SRodney W. Grimes continue; 50926f9a767SRodney W. Grimes } 51026f9a767SRodney W. Grimes 51126f9a767SRodney W. Grimes /* 51226f9a767SRodney W. Grimes * get a limit 51326f9a767SRodney W. Grimes */ 51426f9a767SRodney W. Grimes limit = min(p->p_rlimit[RLIMIT_RSS].rlim_cur, 51526f9a767SRodney W. Grimes p->p_rlimit[RLIMIT_RSS].rlim_max); 51626f9a767SRodney W. Grimes 51726f9a767SRodney W. Grimes /* 51826f9a767SRodney W. Grimes * let processes that are swapped out really be swapped out 51926f9a767SRodney W. Grimes * set the limit to nothing (will force a swap-out.) 52026f9a767SRodney W. Grimes */ 52126f9a767SRodney W. Grimes if ((p->p_flag & P_INMEM) == 0) 52226f9a767SRodney W. Grimes limit = 0; 52326f9a767SRodney W. Grimes 52426f9a767SRodney W. Grimes size = p->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG; 52526f9a767SRodney W. Grimes if (size >= limit) { 52626f9a767SRodney W. Grimes overage = (size - limit) / NBPG; 52726f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map, 52826f9a767SRodney W. Grimes (vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages); 52926f9a767SRodney W. Grimes } 53026f9a767SRodney W. Grimes 53126f9a767SRodney W. Grimes } 53226f9a767SRodney W. Grimes 53326f9a767SRodney W. Grimes if (((cnt.v_free_count + cnt.v_inactive_count) >= 53426f9a767SRodney W. Grimes (cnt.v_inactive_target + cnt.v_free_target)) && 53526f9a767SRodney W. Grimes (cnt.v_free_count >= cnt.v_free_target)) 53626f9a767SRodney W. Grimes return force_wakeup; 53726f9a767SRodney W. Grimes 53826f9a767SRodney W. Grimes pages_freed = 0; 53926f9a767SRodney W. Grimes desired_free = cnt.v_free_target; 540df8bae1dSRodney W. Grimes 541df8bae1dSRodney W. Grimes /* 542df8bae1dSRodney W. Grimes * Start scanning the inactive queue for pages we can free. 543df8bae1dSRodney W. Grimes * We keep scanning until we have enough free pages or 544df8bae1dSRodney W. Grimes * we have scanned through the entire queue. If we 545df8bae1dSRodney W. Grimes * encounter dirty pages, we start cleaning them. 546df8bae1dSRodney W. Grimes */ 547df8bae1dSRodney W. Grimes 54826f9a767SRodney W. Grimes maxlaunder = (cnt.v_free_target - cnt.v_free_count); 54926f9a767SRodney W. Grimes maxscan = cnt.v_inactive_count; 55026f9a767SRodney W. Grimes rescan1: 55126f9a767SRodney W. Grimes m = vm_page_queue_inactive.tqh_first; 55226f9a767SRodney W. Grimes while (m && (maxscan-- > 0) && 55326f9a767SRodney W. Grimes (cnt.v_free_count < desired_free) ) { 55426f9a767SRodney W. Grimes vm_page_t next; 555df8bae1dSRodney W. Grimes 556df8bae1dSRodney W. Grimes next = m->pageq.tqe_next; 557df8bae1dSRodney W. Grimes 55826f9a767SRodney W. Grimes if( (m->flags & PG_INACTIVE) == 0) { 55926f9a767SRodney W. Grimes printf("vm_pageout_scan: page not inactive?"); 560df8bae1dSRodney W. Grimes continue; 561df8bae1dSRodney W. Grimes } 562df8bae1dSRodney W. Grimes 563df8bae1dSRodney W. Grimes /* 56426f9a767SRodney W. Grimes * activate held pages 56526f9a767SRodney W. Grimes */ 56626f9a767SRodney W. Grimes if (m->hold_count != 0) { 56726f9a767SRodney W. Grimes vm_page_activate(m); 56826f9a767SRodney W. Grimes m = next; 56926f9a767SRodney W. Grimes continue; 57026f9a767SRodney W. Grimes } 57126f9a767SRodney W. Grimes 57226f9a767SRodney W. Grimes /* 57326f9a767SRodney W. Grimes * dont mess with busy pages 57426f9a767SRodney W. Grimes */ 57526f9a767SRodney W. Grimes if (m->flags & PG_BUSY) { 57626f9a767SRodney W. Grimes m = next; 57726f9a767SRodney W. Grimes continue; 57826f9a767SRodney W. Grimes } 57926f9a767SRodney W. Grimes 58026f9a767SRodney W. Grimes /* 58126f9a767SRodney W. Grimes * if page is clean and but the page has been referenced, 58226f9a767SRodney W. Grimes * then reactivate the page, but if we are very low on memory 58326f9a767SRodney W. Grimes * or the page has not been referenced, then we free it to the 58426f9a767SRodney W. Grimes * vm system. 585df8bae1dSRodney W. Grimes */ 586df8bae1dSRodney W. Grimes if (m->flags & PG_CLEAN) { 58726f9a767SRodney W. Grimes if ((cnt.v_free_count > vm_pageout_free_min) /* XXX */ 58826f9a767SRodney W. Grimes && pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 58926f9a767SRodney W. Grimes vm_page_activate(m); 59026f9a767SRodney W. Grimes } else if (!m->act_count) { 591df8bae1dSRodney W. Grimes pmap_page_protect(VM_PAGE_TO_PHYS(m), 592df8bae1dSRodney W. Grimes VM_PROT_NONE); 593df8bae1dSRodney W. Grimes vm_page_free(m); 59426f9a767SRodney W. Grimes ++pages_freed; 59526f9a767SRodney W. Grimes } else { 59626f9a767SRodney W. Grimes m->act_count -= min(m->act_count, ACT_DECLINE); 59726f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq); 59826f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_inactive, m, pageq); 599df8bae1dSRodney W. Grimes } 60026f9a767SRodney W. Grimes } else if ((m->flags & PG_LAUNDRY) && maxlaunder > 0) { 60126f9a767SRodney W. Grimes int written; 60226f9a767SRodney W. Grimes if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 60326f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 60426f9a767SRodney W. Grimes vm_page_activate(m); 60526f9a767SRodney W. Grimes m = next; 606df8bae1dSRodney W. Grimes continue; 607df8bae1dSRodney W. Grimes } 608df8bae1dSRodney W. Grimes /* 60926f9a767SRodney W. Grimes * If a page is dirty, then it is either 61026f9a767SRodney W. Grimes * being washed (but not yet cleaned) 61126f9a767SRodney W. Grimes * or it is still in the laundry. If it is 61226f9a767SRodney W. Grimes * still in the laundry, then we start the 61326f9a767SRodney W. Grimes * cleaning operation. 614df8bae1dSRodney W. Grimes */ 615df8bae1dSRodney W. Grimes 61626f9a767SRodney W. Grimes if (written = vm_pageout_clean(m,0)) { 61726f9a767SRodney W. Grimes maxlaunder -= written; 61826f9a767SRodney W. Grimes } 619df8bae1dSRodney W. Grimes /* 62026f9a767SRodney W. Grimes * if the next page has been re-activated, start scanning again 621df8bae1dSRodney W. Grimes */ 622df8bae1dSRodney W. Grimes if (next && (next->flags & PG_INACTIVE) == 0) 62326f9a767SRodney W. Grimes goto rescan1; 62426f9a767SRodney W. Grimes } else if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 62526f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 62626f9a767SRodney W. Grimes vm_page_activate(m); 62726f9a767SRodney W. Grimes } 62826f9a767SRodney W. Grimes m = next; 62926f9a767SRodney W. Grimes } 63026f9a767SRodney W. Grimes 63126f9a767SRodney W. Grimes /* 63226f9a767SRodney W. Grimes * now check malloc area or swap processes out if we are in low 63326f9a767SRodney W. Grimes * memory conditions 63426f9a767SRodney W. Grimes */ 63526f9a767SRodney W. Grimes if (cnt.v_free_count <= cnt.v_free_min) { 63626f9a767SRodney W. Grimes /* 63726f9a767SRodney W. Grimes * swap out inactive processes 63826f9a767SRodney W. Grimes */ 63926f9a767SRodney W. Grimes swapout_threads(); 640df8bae1dSRodney W. Grimes } 641df8bae1dSRodney W. Grimes 642df8bae1dSRodney W. Grimes /* 643df8bae1dSRodney W. Grimes * Compute the page shortage. If we are still very low on memory 644df8bae1dSRodney W. Grimes * be sure that we will move a minimal amount of pages from active 645df8bae1dSRodney W. Grimes * to inactive. 646df8bae1dSRodney W. Grimes */ 647df8bae1dSRodney W. Grimes 64826f9a767SRodney W. Grimes page_shortage = cnt.v_inactive_target - 64926f9a767SRodney W. Grimes (cnt.v_free_count + cnt.v_inactive_count); 65026f9a767SRodney W. Grimes 65126f9a767SRodney W. Grimes if (page_shortage <= 0) { 65226f9a767SRodney W. Grimes if (pages_freed == 0) { 65326f9a767SRodney W. Grimes if( cnt.v_free_count < cnt.v_free_min) { 65426f9a767SRodney W. Grimes page_shortage = cnt.v_free_min - cnt.v_free_count; 65526f9a767SRodney W. Grimes } else if(((cnt.v_free_count + cnt.v_inactive_count) < 65626f9a767SRodney W. Grimes (cnt.v_free_min + cnt.v_inactive_target))) { 657df8bae1dSRodney W. Grimes page_shortage = 1; 65826f9a767SRodney W. Grimes } else { 65926f9a767SRodney W. Grimes page_shortage = 0; 66026f9a767SRodney W. Grimes } 661df8bae1dSRodney W. Grimes } 662df8bae1dSRodney W. Grimes 663df8bae1dSRodney W. Grimes } 664df8bae1dSRodney W. Grimes 66526f9a767SRodney W. Grimes maxscan = cnt.v_active_count; 66626f9a767SRodney W. Grimes m = vm_page_queue_active.tqh_first; 66726f9a767SRodney W. Grimes while (m && maxscan-- && (page_shortage > 0)) { 66826f9a767SRodney W. Grimes 66926f9a767SRodney W. Grimes next = m->pageq.tqe_next; 670df8bae1dSRodney W. Grimes 671df8bae1dSRodney W. Grimes /* 67226f9a767SRodney W. Grimes * Don't deactivate pages that are busy. 673df8bae1dSRodney W. Grimes */ 67426f9a767SRodney W. Grimes if ((m->flags & PG_BUSY) || (m->hold_count != 0)) { 67526f9a767SRodney W. Grimes m = next; 67626f9a767SRodney W. Grimes continue; 677df8bae1dSRodney W. Grimes } 678df8bae1dSRodney W. Grimes 67926f9a767SRodney W. Grimes if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 680df8bae1dSRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 68126f9a767SRodney W. Grimes if (m->act_count < ACT_MAX) 68226f9a767SRodney W. Grimes m->act_count += ACT_ADVANCE; 68326f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 68426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 68526f9a767SRodney W. Grimes TAILQ_REMOVE(&m->object->memq, m, listq); 68626f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&m->object->memq, m, listq); 68726f9a767SRodney W. Grimes } else { 68826f9a767SRodney W. Grimes m->act_count -= min(m->act_count, ACT_DECLINE); 689df8bae1dSRodney W. Grimes 690df8bae1dSRodney W. Grimes /* 69126f9a767SRodney W. Grimes * if the page act_count is zero -- then we deactivate 692df8bae1dSRodney W. Grimes */ 69326f9a767SRodney W. Grimes if (!m->act_count) { 69426f9a767SRodney W. Grimes vm_page_deactivate(m); 69526f9a767SRodney W. Grimes --page_shortage; 69626f9a767SRodney W. Grimes /* 69726f9a767SRodney W. Grimes * else if on the next go-around we will deactivate the page 69826f9a767SRodney W. Grimes * we need to place the page on the end of the queue to age 69926f9a767SRodney W. Grimes * the other pages in memory. 70026f9a767SRodney W. Grimes */ 70126f9a767SRodney W. Grimes } else { 70226f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 70326f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 70426f9a767SRodney W. Grimes TAILQ_REMOVE(&m->object->memq, m, listq); 70526f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&m->object->memq, m, listq); 706df8bae1dSRodney W. Grimes } 707df8bae1dSRodney W. Grimes } 708df8bae1dSRodney W. Grimes 70926f9a767SRodney W. Grimes m = next; 71026f9a767SRodney W. Grimes } 711df8bae1dSRodney W. Grimes 712df8bae1dSRodney W. Grimes /* 71326f9a767SRodney W. Grimes * if we have not freed any pages and we are desparate for memory 71426f9a767SRodney W. Grimes * then we keep trying until we get some (any) memory. 715df8bae1dSRodney W. Grimes */ 71626f9a767SRodney W. Grimes 71726f9a767SRodney W. Grimes if( !force_wakeup && (swap_pager_full || !force_wakeup || 71826f9a767SRodney W. Grimes (pages_freed == 0 && (cnt.v_free_count < cnt.v_free_min)))){ 71926f9a767SRodney W. Grimes vm_pager_sync(); 72026f9a767SRodney W. Grimes force_wakeup = 1; 72126f9a767SRodney W. Grimes goto morefree; 72226f9a767SRodney W. Grimes } 72326f9a767SRodney W. Grimes vm_page_pagesfreed += pages_freed; 72426f9a767SRodney W. Grimes return force_wakeup; 72526f9a767SRodney W. Grimes } 72626f9a767SRodney W. Grimes 727df8bae1dSRodney W. Grimes void 72826f9a767SRodney W. Grimes vm_pagescan() 729df8bae1dSRodney W. Grimes { 73026f9a767SRodney W. Grimes int maxscan, pages_scanned, pages_referenced, nextscan, scantick = hz/20; 73126f9a767SRodney W. Grimes int m_ref, next_ref; 73226f9a767SRodney W. Grimes vm_page_t m, next; 73326f9a767SRodney W. Grimes 73426f9a767SRodney W. Grimes (void) spl0(); 73526f9a767SRodney W. Grimes 73626f9a767SRodney W. Grimes nextscan = scantick; 73726f9a767SRodney W. Grimes 73826f9a767SRodney W. Grimes scanloop: 73926f9a767SRodney W. Grimes 74026f9a767SRodney W. Grimes pages_scanned = 0; 74126f9a767SRodney W. Grimes pages_referenced = 0; 74226f9a767SRodney W. Grimes maxscan = min(cnt.v_active_count, MAXSCAN); 743df8bae1dSRodney W. Grimes 744df8bae1dSRodney W. Grimes /* 74526f9a767SRodney W. Grimes * Gather statistics on page usage. 746df8bae1dSRodney W. Grimes */ 74726f9a767SRodney W. Grimes m = vm_page_queue_active.tqh_first; 74826f9a767SRodney W. Grimes while (m && (maxscan-- > 0)) { 74926f9a767SRodney W. Grimes 75026f9a767SRodney W. Grimes ++pages_scanned; 75126f9a767SRodney W. Grimes 75226f9a767SRodney W. Grimes next = m->pageq.tqe_next; 75326f9a767SRodney W. Grimes 75426f9a767SRodney W. Grimes /* 75526f9a767SRodney W. Grimes * Dont mess with pages that are busy. 75626f9a767SRodney W. Grimes */ 75726f9a767SRodney W. Grimes if ((m->flags & PG_BUSY) || (m->hold_count != 0)) { 75826f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 75926f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 76026f9a767SRodney W. Grimes m = next; 76126f9a767SRodney W. Grimes continue; 762df8bae1dSRodney W. Grimes } 763df8bae1dSRodney W. Grimes 764df8bae1dSRodney W. Grimes /* 76526f9a767SRodney W. Grimes * Advance pages that have been referenced, decline pages that 76626f9a767SRodney W. Grimes * have not. 767df8bae1dSRodney W. Grimes */ 76826f9a767SRodney W. Grimes if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 76926f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 77026f9a767SRodney W. Grimes pages_referenced++; 77126f9a767SRodney W. Grimes if (m->act_count < ACT_MAX) 77226f9a767SRodney W. Grimes m->act_count += ACT_ADVANCE; 77326f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 77426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 77526f9a767SRodney W. Grimes TAILQ_REMOVE(&m->object->memq, m, listq); 77626f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&m->object->memq, m, listq); 77726f9a767SRodney W. Grimes } else { 77826f9a767SRodney W. Grimes m->act_count -= min(m->act_count, ACT_DECLINE); 779df8bae1dSRodney W. Grimes /* 78026f9a767SRodney W. Grimes * if the page act_count is zero, and we are low on mem -- then we deactivate 781df8bae1dSRodney W. Grimes */ 78226f9a767SRodney W. Grimes if (!m->act_count && 78326f9a767SRodney W. Grimes (cnt.v_free_count+cnt.v_inactive_count < cnt.v_free_target+cnt.v_inactive_target )) { 78426f9a767SRodney W. Grimes vm_page_deactivate(m); 785df8bae1dSRodney W. Grimes /* 78626f9a767SRodney W. Grimes * else if on the next go-around we will deactivate the page 78726f9a767SRodney W. Grimes * we need to place the page on the end of the queue to age 78826f9a767SRodney W. Grimes * the other pages in memory. 789df8bae1dSRodney W. Grimes */ 79026f9a767SRodney W. Grimes } else { 79126f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 79226f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 79326f9a767SRodney W. Grimes TAILQ_REMOVE(&m->object->memq, m, listq); 79426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&m->object->memq, m, listq); 795df8bae1dSRodney W. Grimes } 796df8bae1dSRodney W. Grimes } 79726f9a767SRodney W. Grimes m = next; 798df8bae1dSRodney W. Grimes } 79926f9a767SRodney W. Grimes 80026f9a767SRodney W. Grimes if (pages_referenced) { 80126f9a767SRodney W. Grimes nextscan = (pages_scanned / pages_referenced) * scantick; 80226f9a767SRodney W. Grimes nextscan = max(nextscan, scantick); 80326f9a767SRodney W. Grimes nextscan = min(nextscan, hz); 80426f9a767SRodney W. Grimes } else 80526f9a767SRodney W. Grimes nextscan = hz; 80626f9a767SRodney W. Grimes tsleep((caddr_t) &vm_pagescanner, PVM, "scanw", nextscan); 80726f9a767SRodney W. Grimes 80826f9a767SRodney W. Grimes goto scanloop; 80926f9a767SRodney W. Grimes } 810df8bae1dSRodney W. Grimes 811df8bae1dSRodney W. Grimes /* 812df8bae1dSRodney W. Grimes * vm_pageout is the high level pageout daemon. 813df8bae1dSRodney W. Grimes */ 81426f9a767SRodney W. Grimes void 81526f9a767SRodney W. Grimes vm_pageout() 816df8bae1dSRodney W. Grimes { 81726f9a767SRodney W. Grimes extern npendingio, swiopend; 81826f9a767SRodney W. Grimes static nowakeup; 819df8bae1dSRodney W. Grimes (void) spl0(); 820df8bae1dSRodney W. Grimes 821df8bae1dSRodney W. Grimes /* 822df8bae1dSRodney W. Grimes * Initialize some paging parameters. 823df8bae1dSRodney W. Grimes */ 824df8bae1dSRodney W. Grimes 82526f9a767SRodney W. Grimes vmretry: 82626f9a767SRodney W. Grimes cnt.v_free_min = 12; 82726f9a767SRodney W. Grimes cnt.v_free_reserved = 8; 82826f9a767SRodney W. Grimes if (cnt.v_free_min < 8) 82926f9a767SRodney W. Grimes cnt.v_free_min = 8; 83026f9a767SRodney W. Grimes if (cnt.v_free_min > 32) 83126f9a767SRodney W. Grimes cnt.v_free_min = 32; 83226f9a767SRodney W. Grimes vm_pageout_free_min = 4; 83326f9a767SRodney W. Grimes cnt.v_free_target = 2*cnt.v_free_min + cnt.v_free_reserved; 83426f9a767SRodney W. Grimes cnt.v_inactive_target = cnt.v_free_count / 12; 83526f9a767SRodney W. Grimes cnt.v_free_min += cnt.v_free_reserved; 836df8bae1dSRodney W. Grimes 837df8bae1dSRodney W. Grimes /* XXX does not really belong here */ 838df8bae1dSRodney W. Grimes if (vm_page_max_wired == 0) 839df8bae1dSRodney W. Grimes vm_page_max_wired = cnt.v_free_count / 3; 840df8bae1dSRodney W. Grimes 84126f9a767SRodney W. Grimes 84226f9a767SRodney W. Grimes (void) swap_pager_alloc(0, 0, 0, 0); 84326f9a767SRodney W. Grimes 844df8bae1dSRodney W. Grimes /* 845df8bae1dSRodney W. Grimes * The pageout daemon is never done, so loop 846df8bae1dSRodney W. Grimes * forever. 847df8bae1dSRodney W. Grimes */ 848df8bae1dSRodney W. Grimes while (TRUE) { 84926f9a767SRodney W. Grimes int force_wakeup; 85026f9a767SRodney W. Grimes extern struct loadavg averunnable; 851df8bae1dSRodney W. Grimes /* 85226f9a767SRodney W. Grimes cnt.v_free_min = 12 + averunnable.ldavg[0] / 1024; 85326f9a767SRodney W. Grimes cnt.v_free_target = 2*cnt.v_free_min + cnt.v_free_reserved; 85426f9a767SRodney W. Grimes cnt.v_inactive_target = cnt.v_free_target*2; 855df8bae1dSRodney W. Grimes */ 856df8bae1dSRodney W. Grimes 85726f9a767SRodney W. Grimes tsleep((caddr_t) &vm_pages_needed, PVM, "psleep", 0); 85826f9a767SRodney W. Grimes 859df8bae1dSRodney W. Grimes vm_pager_sync(); 86026f9a767SRodney W. Grimes /* 86126f9a767SRodney W. Grimes * The force wakeup hack added to eliminate delays and potiential 86226f9a767SRodney W. Grimes * deadlock. It was possible for the page daemon to indefintely 86326f9a767SRodney W. Grimes * postpone waking up a process that it might be waiting for memory 86426f9a767SRodney W. Grimes * on. The putmulti stuff seems to have aggravated the situation. 86526f9a767SRodney W. Grimes */ 86626f9a767SRodney W. Grimes force_wakeup = vm_pageout_scan(); 86726f9a767SRodney W. Grimes vm_pager_sync(); 86826f9a767SRodney W. Grimes if( force_wakeup) 86926f9a767SRodney W. Grimes wakeup( (caddr_t) &cnt.v_free_count); 87026f9a767SRodney W. Grimes cnt.v_scan++; 87126f9a767SRodney W. Grimes wakeup((caddr_t) kmem_map); 872df8bae1dSRodney W. Grimes } 873df8bae1dSRodney W. Grimes } 87426f9a767SRodney W. Grimes 875