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 * 403c4dd356SDavid Greenman * from: @(#)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 * 682fe6e4d7SDavid Greenman * $Id: vm_pageout.c,v 1.23 1994/10/25 05:35:44 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> 8405f0fdd2SPoul-Henning Kamp #include <vm/swap_pager.h> 85df8bae1dSRodney W. Grimes 8626f9a767SRodney W. Grimes extern vm_map_t kmem_map; 87df8bae1dSRodney W. Grimes int vm_pages_needed; /* Event on which pageout daemon sleeps */ 8826f9a767SRodney W. Grimes int vm_pagescanner; /* Event on which pagescanner sleeps */ 8926f9a767SRodney W. Grimes int vm_pageout_free_min = 0; /* Stop pageout to wait for pagers at this free level */ 9026f9a767SRodney W. Grimes 9126f9a767SRodney W. Grimes int vm_pageout_pages_needed = 0; /* flag saying that the pageout daemon needs pages */ 9226f9a767SRodney W. Grimes int vm_page_pagesfreed; 93a647a309SDavid Greenman int vm_desired_cache_size; 9426f9a767SRodney W. Grimes 9526f9a767SRodney W. Grimes extern int npendingio; 9626f9a767SRodney W. Grimes extern int hz; 9726f9a767SRodney W. Grimes int vm_pageout_proc_limit; 982fe6e4d7SDavid Greenman int vm_pageout_req_swapout; 992fe6e4d7SDavid Greenman int vm_daemon_needed; 10026f9a767SRodney W. Grimes extern int nswiodone; 10126f9a767SRodney W. Grimes extern int swap_pager_full; 1025663e6deSDavid Greenman extern int vm_swap_size; 10326f9a767SRodney W. Grimes extern int swap_pager_ready(); 10426f9a767SRodney W. Grimes 10526f9a767SRodney W. Grimes #define MAXREF 32767 10626f9a767SRodney W. Grimes 10726f9a767SRodney W. Grimes #define MAXSCAN 512 /* maximum number of pages to scan in active queue */ 10826f9a767SRodney W. Grimes /* set the "clock" hands to be (MAXSCAN * 4096) Bytes */ 10926f9a767SRodney W. Grimes #define ACT_DECLINE 1 11003e6c253SDavid Greenman #define ACT_ADVANCE 3 111a6ca859eSDavid Greenman #define ACT_MAX 100 11226f9a767SRodney W. Grimes 11326f9a767SRodney W. Grimes #define LOWATER ((2048*1024)/NBPG) 11426f9a767SRodney W. Grimes 11526f9a767SRodney W. Grimes #define VM_PAGEOUT_PAGE_COUNT 8 116bbc0ec52SDavid Greenman int vm_pageout_page_count = VM_PAGEOUT_PAGE_COUNT; 11726f9a767SRodney W. Grimes int vm_pageout_req_do_stats; 118df8bae1dSRodney W. Grimes 119df8bae1dSRodney W. Grimes int vm_page_max_wired = 0; /* XXX max # of wired pages system-wide */ 120df8bae1dSRodney W. Grimes 12126f9a767SRodney W. Grimes 12226f9a767SRodney W. Grimes /* 12326f9a767SRodney W. Grimes * vm_pageout_clean: 12426f9a767SRodney W. Grimes * cleans a vm_page 12526f9a767SRodney W. Grimes */ 12626f9a767SRodney W. Grimes int 12726f9a767SRodney W. Grimes vm_pageout_clean(m, sync) 12826f9a767SRodney W. Grimes register vm_page_t m; 12926f9a767SRodney W. Grimes int sync; 13026f9a767SRodney W. Grimes { 13126f9a767SRodney W. Grimes /* 13226f9a767SRodney W. Grimes * Clean the page and remove it from the 13326f9a767SRodney W. Grimes * laundry. 13426f9a767SRodney W. Grimes * 13526f9a767SRodney W. Grimes * We set the busy bit to cause 13626f9a767SRodney W. Grimes * potential page faults on this page to 13726f9a767SRodney W. Grimes * block. 13826f9a767SRodney W. Grimes * 13926f9a767SRodney W. Grimes * And we set pageout-in-progress to keep 14026f9a767SRodney W. Grimes * the object from disappearing during 14126f9a767SRodney W. Grimes * pageout. This guarantees that the 14226f9a767SRodney W. Grimes * page won't move from the inactive 14326f9a767SRodney W. Grimes * queue. (However, any other page on 14426f9a767SRodney W. Grimes * the inactive queue may move!) 14526f9a767SRodney W. Grimes */ 14626f9a767SRodney W. Grimes 14726f9a767SRodney W. Grimes register vm_object_t object; 14826f9a767SRodney W. Grimes register vm_pager_t pager; 14926f9a767SRodney W. Grimes int pageout_status[VM_PAGEOUT_PAGE_COUNT]; 15026f9a767SRodney W. Grimes vm_page_t ms[VM_PAGEOUT_PAGE_COUNT]; 15126f9a767SRodney W. Grimes int pageout_count; 15226f9a767SRodney W. Grimes int anyok=0; 15326f9a767SRodney W. Grimes int i; 15426f9a767SRodney W. Grimes vm_offset_t offset = m->offset; 15526f9a767SRodney W. Grimes 15626f9a767SRodney W. Grimes object = m->object; 15726f9a767SRodney W. Grimes if (!object) { 15826f9a767SRodney W. Grimes printf("pager: object missing\n"); 15926f9a767SRodney W. Grimes return 0; 16026f9a767SRodney W. Grimes } 16126f9a767SRodney W. Grimes 16226f9a767SRodney W. Grimes /* 16326f9a767SRodney W. Grimes * Try to collapse the object before 16426f9a767SRodney W. Grimes * making a pager for it. We must 16526f9a767SRodney W. Grimes * unlock the page queues first. 16626f9a767SRodney W. Grimes * We try to defer the creation of a pager 16726f9a767SRodney W. Grimes * until all shadows are not paging. This 16826f9a767SRodney W. Grimes * allows vm_object_collapse to work better and 16926f9a767SRodney W. Grimes * helps control swap space size. 17026f9a767SRodney W. Grimes * (J. Dyson 11 Nov 93) 17126f9a767SRodney W. Grimes */ 17226f9a767SRodney W. Grimes 17326f9a767SRodney W. Grimes if (!object->pager && 17426f9a767SRodney W. Grimes cnt.v_free_count < vm_pageout_free_min) 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 } 18126f9a767SRodney W. Grimes 182a647a309SDavid Greenman if ((m->busy != 0) || 183a647a309SDavid Greenman (m->flags & PG_BUSY) || (m->hold_count != 0)) { 18426f9a767SRodney W. Grimes return 0; 18526f9a767SRodney W. Grimes } 18626f9a767SRodney W. Grimes } 18726f9a767SRodney W. Grimes 18826f9a767SRodney W. Grimes pageout_count = 1; 18926f9a767SRodney W. Grimes ms[0] = m; 19026f9a767SRodney W. Grimes 1914e39a515SPoul-Henning Kamp pager = object->pager; 1924e39a515SPoul-Henning Kamp if (pager) { 193bbc0ec52SDavid Greenman for (i = 1; i < vm_pageout_page_count; i++) { 1944e39a515SPoul-Henning Kamp ms[i] = vm_page_lookup(object, offset+i*NBPG); 1954e39a515SPoul-Henning Kamp if (ms[i]) { 1962fe6e4d7SDavid Greenman if (((ms[i]->flags & PG_CLEAN) != 0) && 1972fe6e4d7SDavid Greenman pmap_is_modified(VM_PAGE_TO_PHYS(ms[i]))) { 1982fe6e4d7SDavid Greenman ms[i]->flags &= ~PG_CLEAN; 1992fe6e4d7SDavid Greenman } 20026f9a767SRodney W. Grimes if (( ((ms[i]->flags & (PG_CLEAN|PG_INACTIVE|PG_BUSY)) == PG_INACTIVE) 2015cedf680SDavid Greenman || ( (ms[i]->flags & (PG_CLEAN|PG_BUSY)) == 0 && sync == VM_PAGEOUT_FORCE)) 20226f9a767SRodney W. Grimes && (ms[i]->wire_count == 0) 203a647a309SDavid Greenman && (ms[i]->busy == 0) 20426f9a767SRodney W. Grimes && (ms[i]->hold_count == 0)) 20526f9a767SRodney W. Grimes pageout_count++; 20626f9a767SRodney W. Grimes else 20726f9a767SRodney W. Grimes break; 20826f9a767SRodney W. Grimes } else 20926f9a767SRodney W. Grimes break; 21026f9a767SRodney W. Grimes } 21126f9a767SRodney W. Grimes for(i=0;i<pageout_count;i++) { 21226f9a767SRodney W. Grimes ms[i]->flags |= PG_BUSY; 21326f9a767SRodney W. Grimes pmap_page_protect(VM_PAGE_TO_PHYS(ms[i]), VM_PROT_READ); 21426f9a767SRodney W. Grimes } 21526f9a767SRodney W. Grimes object->paging_in_progress += pageout_count; 21626f9a767SRodney W. Grimes } else { 21726f9a767SRodney W. Grimes 21826f9a767SRodney W. Grimes m->flags |= PG_BUSY; 21926f9a767SRodney W. Grimes 22026f9a767SRodney W. Grimes pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_READ); 22126f9a767SRodney W. Grimes 22226f9a767SRodney W. Grimes object->paging_in_progress++; 22326f9a767SRodney W. Grimes 22426f9a767SRodney W. Grimes pager = vm_pager_allocate(PG_DFLT, (caddr_t)0, 22526f9a767SRodney W. Grimes object->size, VM_PROT_ALL, 0); 22626f9a767SRodney W. Grimes if (pager != NULL) { 22726f9a767SRodney W. Grimes vm_object_setpager(object, pager, 0, FALSE); 22826f9a767SRodney W. Grimes } 22926f9a767SRodney W. Grimes } 23026f9a767SRodney W. Grimes 23126f9a767SRodney W. Grimes /* 23226f9a767SRodney W. Grimes * If there is no pager for the page, 23326f9a767SRodney W. Grimes * use the default pager. If there's 23426f9a767SRodney W. Grimes * no place to put the page at the 23526f9a767SRodney W. Grimes * moment, leave it in the laundry and 23626f9a767SRodney W. Grimes * hope that there will be paging space 23726f9a767SRodney W. Grimes * later. 23826f9a767SRodney W. Grimes */ 23926f9a767SRodney W. Grimes 24026f9a767SRodney W. Grimes if ((pager && pager->pg_type == PG_SWAP) || 24126f9a767SRodney W. Grimes cnt.v_free_count >= vm_pageout_free_min) { 24226f9a767SRodney W. Grimes if( pageout_count == 1) { 24326f9a767SRodney W. Grimes pageout_status[0] = pager ? 24426f9a767SRodney W. Grimes vm_pager_put(pager, m, 24526f9a767SRodney W. Grimes ((sync || (object == kernel_object)) ? TRUE: FALSE)) : 24626f9a767SRodney W. Grimes VM_PAGER_FAIL; 24726f9a767SRodney W. Grimes } else { 24826f9a767SRodney W. Grimes if( !pager) { 24926f9a767SRodney W. Grimes for(i=0;i<pageout_count;i++) 25026f9a767SRodney W. Grimes pageout_status[i] = VM_PAGER_FAIL; 25126f9a767SRodney W. Grimes } else { 25226f9a767SRodney W. Grimes vm_pager_put_pages(pager, ms, pageout_count, 25326f9a767SRodney W. Grimes ((sync || (object == kernel_object)) ? TRUE : FALSE), 25426f9a767SRodney W. Grimes pageout_status); 25526f9a767SRodney W. Grimes } 25626f9a767SRodney W. Grimes } 25726f9a767SRodney W. Grimes 25826f9a767SRodney W. Grimes } else { 25926f9a767SRodney W. Grimes for(i=0;i<pageout_count;i++) 26026f9a767SRodney W. Grimes pageout_status[i] = VM_PAGER_FAIL; 26126f9a767SRodney W. Grimes } 26226f9a767SRodney W. Grimes 26326f9a767SRodney W. Grimes for(i=0;i<pageout_count;i++) { 26426f9a767SRodney W. Grimes switch (pageout_status[i]) { 26526f9a767SRodney W. Grimes case VM_PAGER_OK: 26626f9a767SRodney W. Grimes ms[i]->flags &= ~PG_LAUNDRY; 26726f9a767SRodney W. Grimes ++anyok; 26826f9a767SRodney W. Grimes break; 26926f9a767SRodney W. Grimes case VM_PAGER_PEND: 27026f9a767SRodney W. Grimes ms[i]->flags &= ~PG_LAUNDRY; 27126f9a767SRodney W. Grimes ++anyok; 27226f9a767SRodney W. Grimes break; 27326f9a767SRodney W. Grimes case VM_PAGER_BAD: 27426f9a767SRodney W. Grimes /* 27526f9a767SRodney W. Grimes * Page outside of range of object. 27626f9a767SRodney W. Grimes * Right now we essentially lose the 27726f9a767SRodney W. Grimes * changes by pretending it worked. 27826f9a767SRodney W. Grimes */ 27926f9a767SRodney W. Grimes ms[i]->flags &= ~PG_LAUNDRY; 28026f9a767SRodney W. Grimes ms[i]->flags |= PG_CLEAN; 28126f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(ms[i])); 28226f9a767SRodney W. Grimes break; 28326f9a767SRodney W. Grimes case VM_PAGER_ERROR: 28426f9a767SRodney W. Grimes case VM_PAGER_FAIL: 28526f9a767SRodney W. Grimes /* 28626f9a767SRodney W. Grimes * If page couldn't be paged out, then 28726f9a767SRodney W. Grimes * reactivate the page so it doesn't 28826f9a767SRodney W. Grimes * clog the inactive list. (We will 28926f9a767SRodney W. Grimes * try paging out it again later). 29026f9a767SRodney W. Grimes */ 29126f9a767SRodney W. Grimes if (ms[i]->flags & PG_INACTIVE) 29226f9a767SRodney W. Grimes vm_page_activate(ms[i]); 29326f9a767SRodney W. Grimes break; 29426f9a767SRodney W. Grimes case VM_PAGER_AGAIN: 29526f9a767SRodney W. Grimes break; 29626f9a767SRodney W. Grimes } 29726f9a767SRodney W. Grimes 29826f9a767SRodney W. Grimes 29926f9a767SRodney W. Grimes /* 30026f9a767SRodney W. Grimes * If the operation is still going, leave 30126f9a767SRodney W. Grimes * the page busy to block all other accesses. 30226f9a767SRodney W. Grimes * Also, leave the paging in progress 30326f9a767SRodney W. Grimes * indicator set so that we don't attempt an 30426f9a767SRodney W. Grimes * object collapse. 30526f9a767SRodney W. Grimes */ 30626f9a767SRodney W. Grimes if (pageout_status[i] != VM_PAGER_PEND) { 30726f9a767SRodney W. Grimes PAGE_WAKEUP(ms[i]); 30826f9a767SRodney W. Grimes if (--object->paging_in_progress == 0) 30926f9a767SRodney W. Grimes wakeup((caddr_t) object); 310a647a309SDavid Greenman if ((ms[i]->flags & PG_REFERENCED) || 311a647a309SDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(ms[i]))) { 31226f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(ms[i])); 313a647a309SDavid Greenman ms[i]->flags &= ~PG_REFERENCED; 31426f9a767SRodney W. Grimes if( ms[i]->flags & PG_INACTIVE) 31526f9a767SRodney W. Grimes vm_page_activate(ms[i]); 31626f9a767SRodney W. Grimes } 31726f9a767SRodney W. Grimes } 31826f9a767SRodney W. Grimes } 31926f9a767SRodney W. Grimes return anyok; 32026f9a767SRodney W. Grimes } 32126f9a767SRodney W. Grimes 32226f9a767SRodney W. Grimes /* 32326f9a767SRodney W. Grimes * vm_pageout_object_deactivate_pages 32426f9a767SRodney W. Grimes * 32526f9a767SRodney W. Grimes * deactivate enough pages to satisfy the inactive target 32626f9a767SRodney W. Grimes * requirements or if vm_page_proc_limit is set, then 32726f9a767SRodney W. Grimes * deactivate all of the pages in the object and its 32826f9a767SRodney W. Grimes * shadows. 32926f9a767SRodney W. Grimes * 33026f9a767SRodney W. Grimes * The object and map must be locked. 33126f9a767SRodney W. Grimes */ 33226f9a767SRodney W. Grimes int 33326f9a767SRodney W. Grimes vm_pageout_object_deactivate_pages(map, object, count) 33426f9a767SRodney W. Grimes vm_map_t map; 33526f9a767SRodney W. Grimes vm_object_t object; 33626f9a767SRodney W. Grimes int count; 33726f9a767SRodney W. Grimes { 33826f9a767SRodney W. Grimes register vm_page_t p, next; 33926f9a767SRodney W. Grimes int rcount; 34026f9a767SRodney W. Grimes int dcount; 34126f9a767SRodney W. Grimes 34226f9a767SRodney W. Grimes dcount = 0; 34326f9a767SRodney W. Grimes if (count == 0) 34426f9a767SRodney W. Grimes count = 1; 34526f9a767SRodney W. Grimes 3462fe6e4d7SDavid Greenman #ifndef REL2_1 34726f9a767SRodney W. Grimes if (object->shadow) { 34826f9a767SRodney W. Grimes int scount = count; 34926f9a767SRodney W. Grimes if( object->shadow->ref_count > 1) 35026f9a767SRodney W. Grimes scount /= object->shadow->ref_count; 35126f9a767SRodney W. Grimes if( scount) 35226f9a767SRodney W. Grimes dcount += vm_pageout_object_deactivate_pages(map, object->shadow, scount); 35326f9a767SRodney W. Grimes } 3542fe6e4d7SDavid Greenman #else 3552fe6e4d7SDavid Greenman if (object->shadow) { 3562fe6e4d7SDavid Greenman if( object->shadow->ref_count == 1) 3572fe6e4d7SDavid Greenman dcount += vm_pageout_object_deactivate_pages(map, object->shadow, count/2); 3582fe6e4d7SDavid Greenman } 3592fe6e4d7SDavid Greenman #endif 36026f9a767SRodney W. Grimes 36126f9a767SRodney W. Grimes if (object->paging_in_progress) 36226f9a767SRodney W. Grimes return dcount; 36326f9a767SRodney W. Grimes 36426f9a767SRodney W. Grimes /* 36526f9a767SRodney W. Grimes * scan the objects entire memory queue 36626f9a767SRodney W. Grimes */ 36726f9a767SRodney W. Grimes rcount = object->resident_page_count; 36826f9a767SRodney W. Grimes p = object->memq.tqh_first; 36926f9a767SRodney W. Grimes while (p && (rcount-- > 0)) { 37026f9a767SRodney W. Grimes next = p->listq.tqe_next; 371a58d1fa1SDavid Greenman cnt.v_pdpages++; 37226f9a767SRodney W. Grimes vm_page_lock_queues(); 37326f9a767SRodney W. Grimes /* 37426f9a767SRodney W. Grimes * if a page is active, not wired and is in the processes pmap, 37526f9a767SRodney W. Grimes * then deactivate the page. 37626f9a767SRodney W. Grimes */ 37726f9a767SRodney W. Grimes if ((p->flags & (PG_ACTIVE|PG_BUSY)) == PG_ACTIVE && 37826f9a767SRodney W. Grimes p->wire_count == 0 && 37926f9a767SRodney W. Grimes p->hold_count == 0 && 380a647a309SDavid Greenman p->busy == 0 && 38126f9a767SRodney W. Grimes pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) { 382a647a309SDavid Greenman if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p)) && 383a647a309SDavid Greenman (p->flags & PG_REFERENCED) == 0) { 38426f9a767SRodney W. Grimes p->act_count -= min(p->act_count, ACT_DECLINE); 38526f9a767SRodney W. Grimes /* 38626f9a767SRodney W. Grimes * if the page act_count is zero -- then we deactivate 38726f9a767SRodney W. Grimes */ 38826f9a767SRodney W. Grimes if (!p->act_count) { 38926f9a767SRodney W. Grimes vm_page_deactivate(p); 39026f9a767SRodney W. Grimes pmap_page_protect(VM_PAGE_TO_PHYS(p), 39126f9a767SRodney W. Grimes VM_PROT_NONE); 39226f9a767SRodney W. Grimes /* 39326f9a767SRodney W. Grimes * else if on the next go-around we will deactivate the page 39426f9a767SRodney W. Grimes * we need to place the page on the end of the queue to age 39526f9a767SRodney W. Grimes * the other pages in memory. 39626f9a767SRodney W. Grimes */ 39726f9a767SRodney W. Grimes } else { 39826f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, p, pageq); 39926f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq); 40026f9a767SRodney W. Grimes TAILQ_REMOVE(&object->memq, p, listq); 40126f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&object->memq, p, listq); 40226f9a767SRodney W. Grimes } 40326f9a767SRodney W. Grimes /* 40426f9a767SRodney W. Grimes * see if we are done yet 40526f9a767SRodney W. Grimes */ 40626f9a767SRodney W. Grimes if (p->flags & PG_INACTIVE) { 40726f9a767SRodney W. Grimes --count; 40826f9a767SRodney W. Grimes ++dcount; 40926f9a767SRodney W. Grimes if (count <= 0 && 41026f9a767SRodney W. Grimes cnt.v_inactive_count > cnt.v_inactive_target) { 41126f9a767SRodney W. Grimes vm_page_unlock_queues(); 41226f9a767SRodney W. Grimes return dcount; 41326f9a767SRodney W. Grimes } 41426f9a767SRodney W. Grimes } 41526f9a767SRodney W. Grimes 41626f9a767SRodney W. Grimes } else { 41726f9a767SRodney W. Grimes /* 41826f9a767SRodney W. Grimes * Move the page to the bottom of the queue. 41926f9a767SRodney W. Grimes */ 42026f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(p)); 421a647a309SDavid Greenman p->flags &= ~PG_REFERENCED; 42226f9a767SRodney W. Grimes if (p->act_count < ACT_MAX) 42326f9a767SRodney W. Grimes p->act_count += ACT_ADVANCE; 42426f9a767SRodney W. Grimes 42526f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, p, pageq); 42626f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq); 42726f9a767SRodney W. Grimes TAILQ_REMOVE(&object->memq, p, listq); 42826f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&object->memq, p, listq); 42926f9a767SRodney W. Grimes } 43026f9a767SRodney W. Grimes } 43126f9a767SRodney W. Grimes 43226f9a767SRodney W. Grimes vm_page_unlock_queues(); 43326f9a767SRodney W. Grimes p = next; 43426f9a767SRodney W. Grimes } 43526f9a767SRodney W. Grimes return dcount; 43626f9a767SRodney W. Grimes } 43726f9a767SRodney W. Grimes 43826f9a767SRodney W. Grimes 43926f9a767SRodney W. Grimes /* 44026f9a767SRodney W. Grimes * deactivate some number of pages in a map, try to do it fairly, but 44126f9a767SRodney W. Grimes * that is really hard to do. 44226f9a767SRodney W. Grimes */ 44326f9a767SRodney W. Grimes 44426f9a767SRodney W. Grimes void 44526f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(map, entry, count, freeer) 44626f9a767SRodney W. Grimes vm_map_t map; 44726f9a767SRodney W. Grimes vm_map_entry_t entry; 44826f9a767SRodney W. Grimes int *count; 44926f9a767SRodney W. Grimes int (*freeer)(vm_map_t, vm_object_t, int); 45026f9a767SRodney W. Grimes { 45126f9a767SRodney W. Grimes vm_map_t tmpm; 45226f9a767SRodney W. Grimes vm_map_entry_t tmpe; 45326f9a767SRodney W. Grimes vm_object_t obj; 45426f9a767SRodney W. Grimes if (*count <= 0) 45526f9a767SRodney W. Grimes return; 45626f9a767SRodney W. Grimes vm_map_reference(map); 45726f9a767SRodney W. Grimes if (!lock_try_read(&map->lock)) { 45826f9a767SRodney W. Grimes vm_map_deallocate(map); 45926f9a767SRodney W. Grimes return; 46026f9a767SRodney W. Grimes } 46126f9a767SRodney W. Grimes if (entry == 0) { 46226f9a767SRodney W. Grimes tmpe = map->header.next; 46326f9a767SRodney W. Grimes while (tmpe != &map->header && *count > 0) { 46426f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(map, tmpe, count, freeer); 46526f9a767SRodney W. Grimes tmpe = tmpe->next; 46626f9a767SRodney W. Grimes }; 46726f9a767SRodney W. Grimes } else if (entry->is_sub_map || entry->is_a_map) { 46826f9a767SRodney W. Grimes tmpm = entry->object.share_map; 46926f9a767SRodney W. Grimes tmpe = tmpm->header.next; 47026f9a767SRodney W. Grimes while (tmpe != &tmpm->header && *count > 0) { 47126f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(tmpm, tmpe, count, freeer); 47226f9a767SRodney W. Grimes tmpe = tmpe->next; 47326f9a767SRodney W. Grimes }; 4744e39a515SPoul-Henning Kamp } else if ((obj = entry->object.vm_object) != 0) { 47526f9a767SRodney W. Grimes *count -= (*freeer)(map, obj, *count); 47626f9a767SRodney W. Grimes } 47726f9a767SRodney W. Grimes lock_read_done(&map->lock); 47826f9a767SRodney W. Grimes vm_map_deallocate(map); 47926f9a767SRodney W. Grimes return; 48026f9a767SRodney W. Grimes } 481df8bae1dSRodney W. Grimes 4822fe6e4d7SDavid Greenman #ifdef REL2_1 4832fe6e4d7SDavid Greenman void 4842fe6e4d7SDavid Greenman vm_req_vmdaemon() { 4852fe6e4d7SDavid Greenman extern int ticks; 4862fe6e4d7SDavid Greenman static lastrun = 0; 4872fe6e4d7SDavid Greenman if( (ticks > (lastrun + hz/10)) || (ticks < lastrun)) { 4882fe6e4d7SDavid Greenman wakeup((caddr_t) &vm_daemon_needed); 4892fe6e4d7SDavid Greenman lastrun = ticks; 4902fe6e4d7SDavid Greenman } 4912fe6e4d7SDavid Greenman } 4922fe6e4d7SDavid Greenman #endif 4932fe6e4d7SDavid Greenman 494df8bae1dSRodney W. Grimes /* 495df8bae1dSRodney W. Grimes * vm_pageout_scan does the dirty work for the pageout daemon. 496df8bae1dSRodney W. Grimes */ 49726f9a767SRodney W. Grimes int 498df8bae1dSRodney W. Grimes vm_pageout_scan() 499df8bae1dSRodney W. Grimes { 50026f9a767SRodney W. Grimes vm_page_t m; 50126f9a767SRodney W. Grimes int page_shortage, maxscan, maxlaunder; 5024e39a515SPoul-Henning Kamp int pages_freed; 50326f9a767SRodney W. Grimes int desired_free; 50426f9a767SRodney W. Grimes vm_page_t next; 5055663e6deSDavid Greenman struct proc *p, *bigproc; 5065663e6deSDavid Greenman vm_offset_t size, bigsize; 507df8bae1dSRodney W. Grimes vm_object_t object; 50826f9a767SRodney W. Grimes int force_wakeup = 0; 509a647a309SDavid Greenman int cache_size, orig_cache_size; 510a647a309SDavid Greenman 5112fe6e4d7SDavid Greenman #ifndef REL2_1 51226f9a767SRodney W. Grimes morefree: 513df8bae1dSRodney W. Grimes /* 51411b224dcSDavid Greenman * now swap processes out if we are in low memory conditions 515a647a309SDavid Greenman */ 5165663e6deSDavid Greenman if ((cnt.v_free_count <= cnt.v_free_min) && !swap_pager_full && vm_swap_size) { 517a647a309SDavid Greenman /* 518a647a309SDavid Greenman * swap out inactive processes 519a647a309SDavid Greenman */ 520a647a309SDavid Greenman swapout_threads(); 521a647a309SDavid Greenman } 52211b224dcSDavid Greenman 523a647a309SDavid Greenman /* 52426f9a767SRodney W. Grimes * scan the processes for exceeding their rlimits or if process 52526f9a767SRodney W. Grimes * is swapped out -- deactivate pages 526df8bae1dSRodney W. Grimes */ 527df8bae1dSRodney W. Grimes 52826f9a767SRodney W. Grimes for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 52926f9a767SRodney W. Grimes int overage; 530a6ca859eSDavid Greenman quad_t limit; 531df8bae1dSRodney W. Grimes 532df8bae1dSRodney W. Grimes /* 53326f9a767SRodney W. Grimes * if this is a system process or if we have already 53426f9a767SRodney W. Grimes * looked at this process, skip it. 535df8bae1dSRodney W. Grimes */ 53626f9a767SRodney W. Grimes if (p->p_flag & (P_SYSTEM|P_WEXIT)) { 53726f9a767SRodney W. Grimes continue; 538df8bae1dSRodney W. Grimes } 539df8bae1dSRodney W. Grimes 540df8bae1dSRodney W. Grimes /* 54126f9a767SRodney W. Grimes * if the process is in a non-running type state, 54226f9a767SRodney W. Grimes * don't touch it. 543df8bae1dSRodney W. Grimes */ 54426f9a767SRodney W. Grimes if (p->p_stat != SRUN && p->p_stat != SSLEEP) { 54526f9a767SRodney W. Grimes continue; 54626f9a767SRodney W. Grimes } 54726f9a767SRodney W. Grimes 54826f9a767SRodney W. Grimes /* 54926f9a767SRodney W. Grimes * get a limit 55026f9a767SRodney W. Grimes */ 551a6ca859eSDavid Greenman limit = qmin(p->p_rlimit[RLIMIT_RSS].rlim_cur, 55226f9a767SRodney W. Grimes p->p_rlimit[RLIMIT_RSS].rlim_max); 55326f9a767SRodney W. Grimes 55426f9a767SRodney W. Grimes /* 55526f9a767SRodney W. Grimes * let processes that are swapped out really be swapped out 55626f9a767SRodney W. Grimes * set the limit to nothing (will force a swap-out.) 55726f9a767SRodney W. Grimes */ 55826f9a767SRodney W. Grimes if ((p->p_flag & P_INMEM) == 0) 55926f9a767SRodney W. Grimes limit = 0; 56026f9a767SRodney W. Grimes 56126f9a767SRodney W. Grimes size = p->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG; 56211b224dcSDavid Greenman if (limit >= 0 && size >= limit) { 56326f9a767SRodney W. Grimes overage = (size - limit) / NBPG; 56426f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map, 56526f9a767SRodney W. Grimes (vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages); 56626f9a767SRodney W. Grimes } 56726f9a767SRodney W. Grimes } 56826f9a767SRodney W. Grimes 56926f9a767SRodney W. Grimes if (((cnt.v_free_count + cnt.v_inactive_count) >= 57026f9a767SRodney W. Grimes (cnt.v_inactive_target + cnt.v_free_target)) && 57126f9a767SRodney W. Grimes (cnt.v_free_count >= cnt.v_free_target)) 57226f9a767SRodney W. Grimes return force_wakeup; 5732fe6e4d7SDavid Greenman #else 5742fe6e4d7SDavid Greenman /* calculate the total cached size */ 5752fe6e4d7SDavid Greenman 5762fe6e4d7SDavid Greenman if( cnt.v_inactive_count < cnt.v_inactive_target) { 5772fe6e4d7SDavid Greenman vm_req_vmdaemon(); 5782fe6e4d7SDavid Greenman } 5792fe6e4d7SDavid Greenman 5802fe6e4d7SDavid Greenman morefree: 5812fe6e4d7SDavid Greenman /* 5822fe6e4d7SDavid Greenman * now swap processes out if we are in low memory conditions 5832fe6e4d7SDavid Greenman */ 5842fe6e4d7SDavid Greenman if ((cnt.v_free_count <= cnt.v_free_min) && !swap_pager_full && vm_swap_size&& vm_pageout_req_swapout == 0) { 5852fe6e4d7SDavid Greenman vm_pageout_req_swapout = 1; 5862fe6e4d7SDavid Greenman vm_req_vmdaemon(); 5872fe6e4d7SDavid Greenman } 5882fe6e4d7SDavid Greenman 5892fe6e4d7SDavid Greenman #endif 59026f9a767SRodney W. Grimes 59126f9a767SRodney W. Grimes pages_freed = 0; 59226f9a767SRodney W. Grimes desired_free = cnt.v_free_target; 593df8bae1dSRodney W. Grimes 594df8bae1dSRodney W. Grimes /* 595df8bae1dSRodney W. Grimes * Start scanning the inactive queue for pages we can free. 596df8bae1dSRodney W. Grimes * We keep scanning until we have enough free pages or 597df8bae1dSRodney W. Grimes * we have scanned through the entire queue. If we 598df8bae1dSRodney W. Grimes * encounter dirty pages, we start cleaning them. 599df8bae1dSRodney W. Grimes */ 600df8bae1dSRodney W. Grimes 60126f9a767SRodney W. Grimes maxlaunder = (cnt.v_free_target - cnt.v_free_count); 60226f9a767SRodney W. Grimes maxscan = cnt.v_inactive_count; 60326f9a767SRodney W. Grimes rescan1: 60426f9a767SRodney W. Grimes m = vm_page_queue_inactive.tqh_first; 60526f9a767SRodney W. Grimes while (m && (maxscan-- > 0) && 60626f9a767SRodney W. Grimes (cnt.v_free_count < desired_free) ) { 60726f9a767SRodney W. Grimes vm_page_t next; 608df8bae1dSRodney W. Grimes 609a58d1fa1SDavid Greenman cnt.v_pdpages++; 610df8bae1dSRodney W. Grimes next = m->pageq.tqe_next; 611df8bae1dSRodney W. Grimes 61226f9a767SRodney W. Grimes if( (m->flags & PG_INACTIVE) == 0) { 61326f9a767SRodney W. Grimes printf("vm_pageout_scan: page not inactive?"); 614df8bae1dSRodney W. Grimes continue; 615df8bae1dSRodney W. Grimes } 616df8bae1dSRodney W. Grimes 617df8bae1dSRodney W. Grimes /* 61826f9a767SRodney W. Grimes * activate held pages 61926f9a767SRodney W. Grimes */ 62026f9a767SRodney W. Grimes if (m->hold_count != 0) { 62126f9a767SRodney W. Grimes vm_page_activate(m); 62226f9a767SRodney W. Grimes m = next; 62326f9a767SRodney W. Grimes continue; 62426f9a767SRodney W. Grimes } 62526f9a767SRodney W. Grimes 62626f9a767SRodney W. Grimes /* 62726f9a767SRodney W. Grimes * dont mess with busy pages 62826f9a767SRodney W. Grimes */ 629a647a309SDavid Greenman if (m->busy || (m->flags & PG_BUSY)) { 63026f9a767SRodney W. Grimes m = next; 63126f9a767SRodney W. Grimes continue; 63226f9a767SRodney W. Grimes } 63326f9a767SRodney W. Grimes 6342fe6e4d7SDavid Greenman if (((m->flags & PG_CLEAN) != 0) && pmap_is_modified(VM_PAGE_TO_PHYS(m))) 6352fe6e4d7SDavid Greenman m->flags &= ~PG_CLEAN; 6362fe6e4d7SDavid Greenman 6372fe6e4d7SDavid Greenman if (((m->flags & PG_REFERENCED) == 0) && pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 6382fe6e4d7SDavid Greenman m->flags |= PG_REFERENCED; 6392fe6e4d7SDavid Greenman pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 6402fe6e4d7SDavid Greenman } 6412fe6e4d7SDavid Greenman 642df8bae1dSRodney W. Grimes if (m->flags & PG_CLEAN) { 643edaaafdbSDavid Greenman /* 644edaaafdbSDavid Greenman * If we're not low on memory and the page has been reference, 6452fe6e4d7SDavid Greenman * then reactivate the page. 646edaaafdbSDavid Greenman */ 6472fe6e4d7SDavid Greenman if ((cnt.v_free_count > vm_pageout_free_min) && 6482fe6e4d7SDavid Greenman ((m->flags & PG_REFERENCED) != 0)) { 649a647a309SDavid Greenman m->flags &= ~PG_REFERENCED; 65026f9a767SRodney W. Grimes vm_page_activate(m); 6512fe6e4d7SDavid Greenman } else if (m->act_count == 0) { 652df8bae1dSRodney W. Grimes pmap_page_protect(VM_PAGE_TO_PHYS(m), 653df8bae1dSRodney W. Grimes VM_PROT_NONE); 654df8bae1dSRodney W. Grimes vm_page_free(m); 655ed74321bSDavid Greenman ++cnt.v_dfree; 65626f9a767SRodney W. Grimes ++pages_freed; 65726f9a767SRodney W. Grimes } else { 65826f9a767SRodney W. Grimes m->act_count -= min(m->act_count, ACT_DECLINE); 65926f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq); 66026f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_inactive, m, pageq); 661df8bae1dSRodney W. Grimes } 66226f9a767SRodney W. Grimes } else if ((m->flags & PG_LAUNDRY) && maxlaunder > 0) { 66326f9a767SRodney W. Grimes int written; 6642fe6e4d7SDavid Greenman if ((m->flags & PG_REFERENCED) != 0) { 665a647a309SDavid Greenman m->flags &= ~PG_REFERENCED; 6662fe6e4d7SDavid Greenman vm_page_activate(m); 66726f9a767SRodney W. Grimes m = next; 668df8bae1dSRodney W. Grimes continue; 669df8bae1dSRodney W. Grimes } 6702fe6e4d7SDavid Greenman 671df8bae1dSRodney W. Grimes /* 67226f9a767SRodney W. Grimes * If a page is dirty, then it is either 67326f9a767SRodney W. Grimes * being washed (but not yet cleaned) 67426f9a767SRodney W. Grimes * or it is still in the laundry. If it is 67526f9a767SRodney W. Grimes * still in the laundry, then we start the 67626f9a767SRodney W. Grimes * cleaning operation. 677df8bae1dSRodney W. Grimes */ 6784e39a515SPoul-Henning Kamp written = vm_pageout_clean(m,0); 6794e39a515SPoul-Henning Kamp if (written) 68026f9a767SRodney W. Grimes maxlaunder -= written; 6814e39a515SPoul-Henning Kamp 68216f62314SDavid Greenman if (!next) 68316f62314SDavid Greenman break; 684df8bae1dSRodney W. Grimes /* 68526f9a767SRodney W. Grimes * if the next page has been re-activated, start scanning again 686df8bae1dSRodney W. Grimes */ 6872fe6e4d7SDavid Greenman if ((written != 0) || ((next->flags & PG_INACTIVE) == 0)) 68826f9a767SRodney W. Grimes goto rescan1; 6892fe6e4d7SDavid Greenman } else if ((m->flags & PG_REFERENCED) != 0) { 690a647a309SDavid Greenman m->flags &= ~PG_REFERENCED; 69126f9a767SRodney W. Grimes vm_page_activate(m); 69226f9a767SRodney W. Grimes } 69326f9a767SRodney W. Grimes m = next; 69426f9a767SRodney W. Grimes } 69526f9a767SRodney W. Grimes 696df8bae1dSRodney W. Grimes /* 697df8bae1dSRodney W. Grimes * Compute the page shortage. If we are still very low on memory 698df8bae1dSRodney W. Grimes * be sure that we will move a minimal amount of pages from active 699df8bae1dSRodney W. Grimes * to inactive. 700df8bae1dSRodney W. Grimes */ 701df8bae1dSRodney W. Grimes 70226f9a767SRodney W. Grimes page_shortage = cnt.v_inactive_target - 70326f9a767SRodney W. Grimes (cnt.v_free_count + cnt.v_inactive_count); 70426f9a767SRodney W. Grimes 70526f9a767SRodney W. Grimes if (page_shortage <= 0) { 70626f9a767SRodney W. Grimes if (pages_freed == 0) { 70726f9a767SRodney W. Grimes if( cnt.v_free_count < cnt.v_free_min) { 7085663e6deSDavid Greenman page_shortage = cnt.v_free_min - cnt.v_free_count + 1; 70926f9a767SRodney W. Grimes } else if(((cnt.v_free_count + cnt.v_inactive_count) < 71026f9a767SRodney W. Grimes (cnt.v_free_min + cnt.v_inactive_target))) { 711df8bae1dSRodney W. Grimes page_shortage = 1; 71226f9a767SRodney W. Grimes } else { 71326f9a767SRodney W. Grimes page_shortage = 0; 71426f9a767SRodney W. Grimes } 715df8bae1dSRodney W. Grimes } 716df8bae1dSRodney W. Grimes 717df8bae1dSRodney W. Grimes } 718df8bae1dSRodney W. Grimes 71926f9a767SRodney W. Grimes maxscan = cnt.v_active_count; 72026f9a767SRodney W. Grimes m = vm_page_queue_active.tqh_first; 72126f9a767SRodney W. Grimes while (m && maxscan-- && (page_shortage > 0)) { 72226f9a767SRodney W. Grimes 723a58d1fa1SDavid Greenman cnt.v_pdpages++; 72426f9a767SRodney W. Grimes next = m->pageq.tqe_next; 725df8bae1dSRodney W. Grimes 726df8bae1dSRodney W. Grimes /* 72726f9a767SRodney W. Grimes * Don't deactivate pages that are busy. 728df8bae1dSRodney W. Grimes */ 729a647a309SDavid Greenman if ((m->busy != 0) || 730a647a309SDavid Greenman (m->flags & PG_BUSY) || (m->hold_count != 0)) { 73126f9a767SRodney W. Grimes m = next; 73226f9a767SRodney W. Grimes continue; 733df8bae1dSRodney W. Grimes } 734df8bae1dSRodney W. Grimes 735a647a309SDavid Greenman if ((m->flags & PG_REFERENCED) || 736a647a309SDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 737df8bae1dSRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 738a647a309SDavid Greenman m->flags &= ~PG_REFERENCED; 73926f9a767SRodney W. Grimes if (m->act_count < ACT_MAX) 74026f9a767SRodney W. Grimes m->act_count += ACT_ADVANCE; 74126f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 74226f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 74326f9a767SRodney W. Grimes TAILQ_REMOVE(&m->object->memq, m, listq); 74426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&m->object->memq, m, listq); 74526f9a767SRodney W. Grimes } else { 74626f9a767SRodney W. Grimes m->act_count -= min(m->act_count, ACT_DECLINE); 747df8bae1dSRodney W. Grimes 748df8bae1dSRodney W. Grimes /* 74926f9a767SRodney W. Grimes * if the page act_count is zero -- then we deactivate 750df8bae1dSRodney W. Grimes */ 75126f9a767SRodney W. Grimes if (!m->act_count) { 75226f9a767SRodney W. Grimes vm_page_deactivate(m); 75326f9a767SRodney W. Grimes --page_shortage; 75426f9a767SRodney W. Grimes /* 75526f9a767SRodney W. Grimes * else if on the next go-around we will deactivate the page 75626f9a767SRodney W. Grimes * we need to place the page on the end of the queue to age 75726f9a767SRodney W. Grimes * the other pages in memory. 75826f9a767SRodney W. Grimes */ 75926f9a767SRodney W. Grimes } else { 76026f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 76126f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 76226f9a767SRodney W. Grimes TAILQ_REMOVE(&m->object->memq, m, listq); 76326f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&m->object->memq, m, listq); 764df8bae1dSRodney W. Grimes } 765df8bae1dSRodney W. Grimes } 76626f9a767SRodney W. Grimes m = next; 76726f9a767SRodney W. Grimes } 768df8bae1dSRodney W. Grimes 769df8bae1dSRodney W. Grimes /* 77026f9a767SRodney W. Grimes * if we have not freed any pages and we are desparate for memory 77126f9a767SRodney W. Grimes * then we keep trying until we get some (any) memory. 772df8bae1dSRodney W. Grimes */ 77326f9a767SRodney W. Grimes 77426f9a767SRodney W. Grimes if (!force_wakeup && (swap_pager_full || !force_wakeup || 77526f9a767SRodney W. Grimes (pages_freed == 0 && (cnt.v_free_count < cnt.v_free_min)))){ 77626f9a767SRodney W. Grimes vm_pager_sync(); 77726f9a767SRodney W. Grimes force_wakeup = 1; 77826f9a767SRodney W. Grimes goto morefree; 77926f9a767SRodney W. Grimes } 7805663e6deSDavid Greenman 7815663e6deSDavid Greenman /* 7825663e6deSDavid Greenman * make sure that we have swap space -- if we are low on 7835663e6deSDavid Greenman * memory and swap -- then kill the biggest process. 7845663e6deSDavid Greenman */ 7855663e6deSDavid Greenman if ((vm_swap_size == 0 || swap_pager_full) && 7865663e6deSDavid Greenman (cnt.v_free_count < cnt.v_free_min)) { 7875663e6deSDavid Greenman bigproc = NULL; 7885663e6deSDavid Greenman bigsize = 0; 7895663e6deSDavid Greenman for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 7905663e6deSDavid Greenman /* 7915663e6deSDavid Greenman * if this is a system process, skip it 7925663e6deSDavid Greenman */ 7935663e6deSDavid Greenman if ((p->p_flag & P_SYSTEM) || ((p->p_pid < 48) && (vm_swap_size != 0))) { 7945663e6deSDavid Greenman continue; 7955663e6deSDavid Greenman } 7965663e6deSDavid Greenman 7975663e6deSDavid Greenman /* 7985663e6deSDavid Greenman * if the process is in a non-running type state, 7995663e6deSDavid Greenman * don't touch it. 8005663e6deSDavid Greenman */ 8015663e6deSDavid Greenman if (p->p_stat != SRUN && p->p_stat != SSLEEP) { 8025663e6deSDavid Greenman continue; 8035663e6deSDavid Greenman } 8045663e6deSDavid Greenman /* 8055663e6deSDavid Greenman * get the process size 8065663e6deSDavid Greenman */ 8075663e6deSDavid Greenman size = p->p_vmspace->vm_pmap.pm_stats.resident_count; 8085663e6deSDavid Greenman /* 8095663e6deSDavid Greenman * if the this process is bigger than the biggest one 8105663e6deSDavid Greenman * remember it. 8115663e6deSDavid Greenman */ 8125663e6deSDavid Greenman if (size > bigsize) { 8135663e6deSDavid Greenman bigproc = p; 8145663e6deSDavid Greenman bigsize = size; 8155663e6deSDavid Greenman } 8165663e6deSDavid Greenman } 8175663e6deSDavid Greenman if (bigproc != NULL) { 8185663e6deSDavid Greenman printf("Process %lu killed by vm_pageout -- out of swap\n", (u_long)bigproc->p_pid); 8195663e6deSDavid Greenman psignal(bigproc, SIGKILL); 8205663e6deSDavid Greenman bigproc->p_estcpu = 0; 8215663e6deSDavid Greenman bigproc->p_nice = PRIO_MIN; 8225663e6deSDavid Greenman resetpriority(bigproc); 8235663e6deSDavid Greenman wakeup( (caddr_t) &cnt.v_free_count); 8245663e6deSDavid Greenman } 8255663e6deSDavid Greenman } 82626f9a767SRodney W. Grimes vm_page_pagesfreed += pages_freed; 82726f9a767SRodney W. Grimes return force_wakeup; 82826f9a767SRodney W. Grimes } 82926f9a767SRodney W. Grimes 830df8bae1dSRodney W. Grimes /* 831df8bae1dSRodney W. Grimes * vm_pageout is the high level pageout daemon. 832df8bae1dSRodney W. Grimes */ 83326f9a767SRodney W. Grimes void 83426f9a767SRodney W. Grimes vm_pageout() 835df8bae1dSRodney W. Grimes { 836df8bae1dSRodney W. Grimes (void) spl0(); 837df8bae1dSRodney W. Grimes 838df8bae1dSRodney W. Grimes /* 839df8bae1dSRodney W. Grimes * Initialize some paging parameters. 840df8bae1dSRodney W. Grimes */ 841df8bae1dSRodney W. Grimes 84226f9a767SRodney W. Grimes cnt.v_free_min = 12; 843ed74321bSDavid Greenman /* 844ed74321bSDavid Greenman * free_reserved needs to include enough for the largest 845ed74321bSDavid Greenman * swap pager structures plus enough for any pv_entry 846ed74321bSDavid Greenman * structs when paging. 847ed74321bSDavid Greenman */ 848389918eeSDavid Greenman vm_pageout_free_min = 4 + cnt.v_page_count / 1024; 849389918eeSDavid Greenman cnt.v_free_reserved = vm_pageout_free_min + 2; 85026f9a767SRodney W. Grimes if (cnt.v_free_min < 8) 85126f9a767SRodney W. Grimes cnt.v_free_min = 8; 85226f9a767SRodney W. Grimes if (cnt.v_free_min > 32) 85326f9a767SRodney W. Grimes cnt.v_free_min = 32; 85426f9a767SRodney W. Grimes cnt.v_free_target = 2*cnt.v_free_min + cnt.v_free_reserved; 85526f9a767SRodney W. Grimes cnt.v_inactive_target = cnt.v_free_count / 12; 85626f9a767SRodney W. Grimes cnt.v_free_min += cnt.v_free_reserved; 857a647a309SDavid Greenman vm_desired_cache_size = cnt.v_page_count / 3; 858df8bae1dSRodney W. Grimes 859df8bae1dSRodney W. Grimes /* XXX does not really belong here */ 860df8bae1dSRodney W. Grimes if (vm_page_max_wired == 0) 861df8bae1dSRodney W. Grimes vm_page_max_wired = cnt.v_free_count / 3; 862df8bae1dSRodney W. Grimes 86326f9a767SRodney W. Grimes 86426f9a767SRodney W. Grimes (void) swap_pager_alloc(0, 0, 0, 0); 86526f9a767SRodney W. Grimes 866df8bae1dSRodney W. Grimes /* 867df8bae1dSRodney W. Grimes * The pageout daemon is never done, so loop 868df8bae1dSRodney W. Grimes * forever. 869df8bae1dSRodney W. Grimes */ 870df8bae1dSRodney W. Grimes while (TRUE) { 87126f9a767SRodney W. Grimes int force_wakeup; 872df8bae1dSRodney W. Grimes 87326f9a767SRodney W. Grimes tsleep((caddr_t) &vm_pages_needed, PVM, "psleep", 0); 874a58d1fa1SDavid Greenman cnt.v_pdwakeups++; 87526f9a767SRodney W. Grimes 876df8bae1dSRodney W. Grimes vm_pager_sync(); 87726f9a767SRodney W. Grimes /* 87826f9a767SRodney W. Grimes * The force wakeup hack added to eliminate delays and potiential 87926f9a767SRodney W. Grimes * deadlock. It was possible for the page daemon to indefintely 88026f9a767SRodney W. Grimes * postpone waking up a process that it might be waiting for memory 88126f9a767SRodney W. Grimes * on. The putmulti stuff seems to have aggravated the situation. 88226f9a767SRodney W. Grimes */ 88326f9a767SRodney W. Grimes force_wakeup = vm_pageout_scan(); 88426f9a767SRodney W. Grimes vm_pager_sync(); 88526f9a767SRodney W. Grimes if( force_wakeup) 88626f9a767SRodney W. Grimes wakeup( (caddr_t) &cnt.v_free_count); 88726f9a767SRodney W. Grimes wakeup((caddr_t) kmem_map); 888df8bae1dSRodney W. Grimes } 889df8bae1dSRodney W. Grimes } 89026f9a767SRodney W. Grimes 8912fe6e4d7SDavid Greenman #ifdef REL2_1 8922fe6e4d7SDavid Greenman void 8932fe6e4d7SDavid Greenman vm_daemon() { 8942fe6e4d7SDavid Greenman int cache_size; 8952fe6e4d7SDavid Greenman vm_object_t object; 8962fe6e4d7SDavid Greenman struct proc *p; 8972fe6e4d7SDavid Greenman while(TRUE) { 8982fe6e4d7SDavid Greenman tsleep((caddr_t) &vm_daemon_needed, PUSER, "psleep", 0); 8992fe6e4d7SDavid Greenman if( vm_pageout_req_swapout) { 9002fe6e4d7SDavid Greenman /* 9012fe6e4d7SDavid Greenman * swap out inactive processes 9022fe6e4d7SDavid Greenman */ 9032fe6e4d7SDavid Greenman swapout_threads(); 9042fe6e4d7SDavid Greenman vm_pageout_req_swapout = 0; 9052fe6e4d7SDavid Greenman } 9062fe6e4d7SDavid Greenman /* 9072fe6e4d7SDavid Greenman * scan the processes for exceeding their rlimits or if process 9082fe6e4d7SDavid Greenman * is swapped out -- deactivate pages 9092fe6e4d7SDavid Greenman */ 9102fe6e4d7SDavid Greenman 9112fe6e4d7SDavid Greenman for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 9122fe6e4d7SDavid Greenman int overage; 9132fe6e4d7SDavid Greenman quad_t limit; 9142fe6e4d7SDavid Greenman vm_offset_t size; 9152fe6e4d7SDavid Greenman 9162fe6e4d7SDavid Greenman /* 9172fe6e4d7SDavid Greenman * if this is a system process or if we have already 9182fe6e4d7SDavid Greenman * looked at this process, skip it. 9192fe6e4d7SDavid Greenman */ 9202fe6e4d7SDavid Greenman if (p->p_flag & (P_SYSTEM|P_WEXIT)) { 9212fe6e4d7SDavid Greenman continue; 9222fe6e4d7SDavid Greenman } 9232fe6e4d7SDavid Greenman 9242fe6e4d7SDavid Greenman /* 9252fe6e4d7SDavid Greenman * if the process is in a non-running type state, 9262fe6e4d7SDavid Greenman * don't touch it. 9272fe6e4d7SDavid Greenman */ 9282fe6e4d7SDavid Greenman if (p->p_stat != SRUN && p->p_stat != SSLEEP) { 9292fe6e4d7SDavid Greenman continue; 9302fe6e4d7SDavid Greenman } 9312fe6e4d7SDavid Greenman 9322fe6e4d7SDavid Greenman /* 9332fe6e4d7SDavid Greenman * get a limit 9342fe6e4d7SDavid Greenman */ 9352fe6e4d7SDavid Greenman limit = qmin(p->p_rlimit[RLIMIT_RSS].rlim_cur, 9362fe6e4d7SDavid Greenman p->p_rlimit[RLIMIT_RSS].rlim_max); 9372fe6e4d7SDavid Greenman 9382fe6e4d7SDavid Greenman /* 9392fe6e4d7SDavid Greenman * let processes that are swapped out really be swapped out 9402fe6e4d7SDavid Greenman * set the limit to nothing (will force a swap-out.) 9412fe6e4d7SDavid Greenman */ 9422fe6e4d7SDavid Greenman if ((p->p_flag & P_INMEM) == 0) 9432fe6e4d7SDavid Greenman limit = 0; 9442fe6e4d7SDavid Greenman 9452fe6e4d7SDavid Greenman size = p->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG; 9462fe6e4d7SDavid Greenman if (limit >= 0 && size >= limit) { 9472fe6e4d7SDavid Greenman overage = (size - limit) / NBPG; 9482fe6e4d7SDavid Greenman vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map, 9492fe6e4d7SDavid Greenman (vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages); 9502fe6e4d7SDavid Greenman } 9512fe6e4d7SDavid Greenman } 9522fe6e4d7SDavid Greenman 9532fe6e4d7SDavid Greenman /* 9542fe6e4d7SDavid Greenman * We manage the cached memory by attempting to keep it 9552fe6e4d7SDavid Greenman * at about the desired level. 9562fe6e4d7SDavid Greenman * We deactivate the pages for the oldest cached objects 9572fe6e4d7SDavid Greenman * first. This keeps pages that are "cached" from hogging 9582fe6e4d7SDavid Greenman * physical memory. 9592fe6e4d7SDavid Greenman */ 9602fe6e4d7SDavid Greenman restart: 9612fe6e4d7SDavid Greenman cache_size = 0; 9622fe6e4d7SDavid Greenman object = vm_object_cached_list.tqh_first; 9632fe6e4d7SDavid Greenman /* calculate the total cached size */ 9642fe6e4d7SDavid Greenman while( object) { 9652fe6e4d7SDavid Greenman cache_size += object->resident_page_count; 9662fe6e4d7SDavid Greenman object = object->cached_list.tqe_next; 9672fe6e4d7SDavid Greenman } 9682fe6e4d7SDavid Greenman 9692fe6e4d7SDavid Greenman vm_object_cache_lock(); 9702fe6e4d7SDavid Greenman object = vm_object_cached_list.tqh_first; 9712fe6e4d7SDavid Greenman while ( object) { 9722fe6e4d7SDavid Greenman vm_object_cache_unlock(); 9732fe6e4d7SDavid Greenman /* 9742fe6e4d7SDavid Greenman * if there are no resident pages -- get rid of the object 9752fe6e4d7SDavid Greenman */ 9762fe6e4d7SDavid Greenman if( object->resident_page_count == 0) { 9772fe6e4d7SDavid Greenman if (object != vm_object_lookup(object->pager)) 9782fe6e4d7SDavid Greenman panic("vm_object_cache_trim: I'm sooo confused."); 9792fe6e4d7SDavid Greenman pager_cache(object, FALSE); 9802fe6e4d7SDavid Greenman goto restart; 9812fe6e4d7SDavid Greenman } else if( cache_size >= (vm_swap_size?vm_desired_cache_size:0)) { 9822fe6e4d7SDavid Greenman /* 9832fe6e4d7SDavid Greenman * if there are resident pages -- deactivate them 9842fe6e4d7SDavid Greenman */ 9852fe6e4d7SDavid Greenman vm_object_deactivate_pages(object); 9862fe6e4d7SDavid Greenman cache_size -= object->resident_page_count; 9872fe6e4d7SDavid Greenman } 9882fe6e4d7SDavid Greenman object = object->cached_list.tqe_next; 9892fe6e4d7SDavid Greenman vm_object_cache_lock(); 9902fe6e4d7SDavid Greenman } 9912fe6e4d7SDavid Greenman vm_object_cache_unlock(); 9922fe6e4d7SDavid Greenman } 9932fe6e4d7SDavid Greenman } 9942fe6e4d7SDavid Greenman #endif 995