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 * 68f6b04d2bSDavid Greenman * $Id: vm_pageout.c,v 1.44 1995/03/28 05:58:35 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> 77b5e8ce9fSBruce Evans #include <sys/kernel.h> 7826f9a767SRodney W. Grimes #include <sys/proc.h> 7926f9a767SRodney W. Grimes #include <sys/resourcevar.h> 8026f9a767SRodney W. Grimes #include <sys/malloc.h> 810d94caffSDavid Greenman #include <sys/kernel.h> 82d2fc5315SPoul-Henning Kamp #include <sys/signalvar.h> 83f6b04d2bSDavid Greenman #include <sys/vnode.h> 84df8bae1dSRodney W. Grimes 85df8bae1dSRodney W. Grimes #include <vm/vm.h> 86df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 87df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h> 8805f0fdd2SPoul-Henning Kamp #include <vm/swap_pager.h> 89f6b04d2bSDavid Greenman #include <vm/vnode_pager.h> 90df8bae1dSRodney W. Grimes 9126f9a767SRodney W. Grimes extern vm_map_t kmem_map; 92df8bae1dSRodney W. Grimes int vm_pages_needed; /* Event on which pageout daemon sleeps */ 9326f9a767SRodney W. Grimes int vm_pagescanner; /* Event on which pagescanner sleeps */ 9426f9a767SRodney W. Grimes 9526f9a767SRodney W. Grimes int vm_pageout_pages_needed = 0;/* flag saying that the pageout daemon needs pages */ 9626f9a767SRodney W. Grimes int vm_page_pagesfreed; 9726f9a767SRodney W. Grimes 9826f9a767SRodney W. Grimes extern int npendingio; 9926f9a767SRodney W. Grimes int vm_pageout_proc_limit; 1002fe6e4d7SDavid Greenman int vm_pageout_req_swapout; 1012fe6e4d7SDavid Greenman int vm_daemon_needed; 10226f9a767SRodney W. Grimes extern int nswiodone; 10326f9a767SRodney W. Grimes extern int swap_pager_full; 1045663e6deSDavid Greenman extern int vm_swap_size; 10526f9a767SRodney W. Grimes extern int swap_pager_ready(); 106f6b04d2bSDavid Greenman extern int vfs_update_wakeup; 10726f9a767SRodney W. Grimes 1081ed81ef2SDavid Greenman #define MAXSCAN 1024 /* maximum number of pages to scan in queues */ 10926f9a767SRodney W. Grimes 1100d94caffSDavid Greenman #define MAXLAUNDER (cnt.v_page_count > 1800 ? 32 : 16) 11126f9a767SRodney W. Grimes 11226f9a767SRodney W. Grimes #define VM_PAGEOUT_PAGE_COUNT 8 113bbc0ec52SDavid Greenman int vm_pageout_page_count = VM_PAGEOUT_PAGE_COUNT; 11426f9a767SRodney W. Grimes int vm_pageout_req_do_stats; 115df8bae1dSRodney W. Grimes 116df8bae1dSRodney W. Grimes int vm_page_max_wired = 0; /* XXX max # of wired pages system-wide */ 117df8bae1dSRodney W. Grimes 11826f9a767SRodney W. Grimes /* 11926f9a767SRodney W. Grimes * vm_pageout_clean: 12026f9a767SRodney W. Grimes * cleans a vm_page 12126f9a767SRodney W. Grimes */ 12226f9a767SRodney W. Grimes int 12326f9a767SRodney W. Grimes vm_pageout_clean(m, sync) 12426f9a767SRodney W. Grimes register vm_page_t m; 12526f9a767SRodney W. Grimes int sync; 12626f9a767SRodney W. Grimes { 12726f9a767SRodney W. Grimes /* 1280d94caffSDavid Greenman * Clean the page and remove it from the laundry. 12926f9a767SRodney W. Grimes * 1300d94caffSDavid Greenman * We set the busy bit to cause potential page faults on this page to 13126f9a767SRodney W. Grimes * block. 13226f9a767SRodney W. Grimes * 1330d94caffSDavid Greenman * And we set pageout-in-progress to keep the object from disappearing 1340d94caffSDavid Greenman * during pageout. This guarantees that the page won't move from the 1350d94caffSDavid Greenman * inactive queue. (However, any other page on the inactive queue may 1360d94caffSDavid Greenman * move!) 13726f9a767SRodney W. Grimes */ 13826f9a767SRodney W. Grimes 13926f9a767SRodney W. Grimes register vm_object_t object; 14026f9a767SRodney W. Grimes register vm_pager_t pager; 14126f9a767SRodney W. Grimes int pageout_status[VM_PAGEOUT_PAGE_COUNT]; 142f6b04d2bSDavid Greenman vm_page_t ms[VM_PAGEOUT_PAGE_COUNT], mb[VM_PAGEOUT_PAGE_COUNT]; 143f6b04d2bSDavid Greenman int pageout_count, b_pageout_count; 14426f9a767SRodney W. Grimes int anyok = 0; 14526f9a767SRodney W. Grimes int i; 14626f9a767SRodney W. Grimes vm_offset_t offset = m->offset; 14726f9a767SRodney W. Grimes 14826f9a767SRodney W. Grimes object = m->object; 14926f9a767SRodney W. Grimes if (!object) { 15026f9a767SRodney W. Grimes printf("pager: object missing\n"); 15126f9a767SRodney W. Grimes return 0; 15226f9a767SRodney W. Grimes } 1530d94caffSDavid Greenman if (!object->pager && (object->flags & OBJ_INTERNAL) == 0) { 1540d94caffSDavid Greenman printf("pager: non internal obj without pager\n"); 1550d94caffSDavid Greenman } 15626f9a767SRodney W. Grimes /* 1570d94caffSDavid Greenman * Try to collapse the object before making a pager for it. We must 1580d94caffSDavid Greenman * unlock the page queues first. We try to defer the creation of a 1590d94caffSDavid Greenman * pager until all shadows are not paging. This allows 1600d94caffSDavid Greenman * vm_object_collapse to work better and helps control swap space 1610d94caffSDavid Greenman * size. (J. Dyson 11 Nov 93) 16226f9a767SRodney W. Grimes */ 16326f9a767SRodney W. Grimes 16426f9a767SRodney W. Grimes if (!object->pager && 1650d94caffSDavid Greenman (cnt.v_free_count + cnt.v_cache_count) < cnt.v_pageout_free_min) 16626f9a767SRodney W. Grimes return 0; 16726f9a767SRodney W. Grimes 168f6b04d2bSDavid Greenman if ((!sync && m->hold_count != 0) || 1690d94caffSDavid Greenman ((m->busy != 0) || (m->flags & PG_BUSY))) 1700d94caffSDavid Greenman return 0; 1710d94caffSDavid Greenman 1720d94caffSDavid Greenman if (!sync && object->shadow) { 17326f9a767SRodney W. Grimes vm_object_collapse(object); 17426f9a767SRodney W. Grimes } 17526f9a767SRodney W. Grimes pageout_count = 1; 17626f9a767SRodney W. Grimes ms[0] = m; 17726f9a767SRodney W. Grimes 1784e39a515SPoul-Henning Kamp pager = object->pager; 1794e39a515SPoul-Henning Kamp if (pager) { 180bbc0ec52SDavid Greenman for (i = 1; i < vm_pageout_page_count; i++) { 1810d94caffSDavid Greenman vm_page_t mt; 1820d94caffSDavid Greenman 1830d94caffSDavid Greenman ms[i] = mt = vm_page_lookup(object, offset + i * NBPG); 1840d94caffSDavid Greenman if (mt) { 185f6b04d2bSDavid Greenman if (mt->flags & (PG_BUSY|PG_CACHE) || mt->busy) 186f6b04d2bSDavid Greenman break; 1870d94caffSDavid Greenman /* 1880d94caffSDavid Greenman * we can cluster ONLY if: ->> the page is NOT 1890d94caffSDavid Greenman * busy, and is NOT clean the page is not 1900d94caffSDavid Greenman * wired, busy, held, or mapped into a buffer. 1910d94caffSDavid Greenman * and one of the following: 1) The page is 1920d94caffSDavid Greenman * inactive, or a seldom used active page. 2) 1930d94caffSDavid Greenman * or we force the issue. 1940d94caffSDavid Greenman */ 195f6b04d2bSDavid Greenman vm_page_test_dirty(mt); 1960d94caffSDavid Greenman if ((mt->dirty & mt->valid) != 0 197f6b04d2bSDavid Greenman && ((mt->flags & PG_INACTIVE) || 198f6b04d2bSDavid Greenman (sync == VM_PAGEOUT_FORCE)) 1990d94caffSDavid Greenman && (mt->wire_count == 0) 200f6b04d2bSDavid Greenman && (mt->hold_count == 0)) 20126f9a767SRodney W. Grimes pageout_count++; 20226f9a767SRodney W. Grimes else 20326f9a767SRodney W. Grimes break; 20426f9a767SRodney W. Grimes } else 20526f9a767SRodney W. Grimes break; 20626f9a767SRodney W. Grimes } 207f6b04d2bSDavid Greenman 208f6b04d2bSDavid Greenman if ((pageout_count < vm_pageout_page_count) && (offset != 0)) { 209f6b04d2bSDavid Greenman b_pageout_count = 0; 210f6b04d2bSDavid Greenman for (i = 0; i < vm_pageout_page_count-pageout_count; i++) { 211f6b04d2bSDavid Greenman vm_page_t mt; 212f6b04d2bSDavid Greenman 213f6b04d2bSDavid Greenman mt = vm_page_lookup(object, offset - (i + 1) * NBPG); 214f6b04d2bSDavid Greenman if (mt) { 215f6b04d2bSDavid Greenman if (mt->flags & (PG_BUSY|PG_CACHE) || mt->busy) 216f6b04d2bSDavid Greenman break; 217f6b04d2bSDavid Greenman vm_page_test_dirty(mt); 218f6b04d2bSDavid Greenman if ((mt->dirty & mt->valid) != 0 219f6b04d2bSDavid Greenman && ((mt->flags & PG_INACTIVE) || 220f6b04d2bSDavid Greenman (sync == VM_PAGEOUT_FORCE)) 221f6b04d2bSDavid Greenman && (mt->wire_count == 0) 222f6b04d2bSDavid Greenman && (mt->hold_count == 0)) { 223f6b04d2bSDavid Greenman mb[b_pageout_count] = mt; 224f6b04d2bSDavid Greenman b_pageout_count++; 225f6b04d2bSDavid Greenman if ((offset - (i + 1) * NBPG) == 0) 226f6b04d2bSDavid Greenman break; 227f6b04d2bSDavid Greenman } else 228f6b04d2bSDavid Greenman break; 229f6b04d2bSDavid Greenman } else 230f6b04d2bSDavid Greenman break; 231f6b04d2bSDavid Greenman } 232f6b04d2bSDavid Greenman if (b_pageout_count > 0) { 233f6b04d2bSDavid Greenman for(i=pageout_count - 1;i>=0;--i) { 234f6b04d2bSDavid Greenman ms[i+b_pageout_count] = ms[i]; 235f6b04d2bSDavid Greenman } 236f6b04d2bSDavid Greenman for(i=0;i<b_pageout_count;i++) { 237f6b04d2bSDavid Greenman ms[i] = mb[b_pageout_count - (i + 1)]; 238f6b04d2bSDavid Greenman } 239f6b04d2bSDavid Greenman pageout_count += b_pageout_count; 240f6b04d2bSDavid Greenman } 241f6b04d2bSDavid Greenman } 242f6b04d2bSDavid Greenman 2430d94caffSDavid Greenman /* 2440d94caffSDavid Greenman * we allow reads during pageouts... 2450d94caffSDavid Greenman */ 24626f9a767SRodney W. Grimes for (i = 0; i < pageout_count; i++) { 24726f9a767SRodney W. Grimes ms[i]->flags |= PG_BUSY; 248f919ebdeSDavid Greenman vm_page_protect(ms[i], VM_PROT_READ); 24926f9a767SRodney W. Grimes } 25026f9a767SRodney W. Grimes object->paging_in_progress += pageout_count; 25126f9a767SRodney W. Grimes } else { 25226f9a767SRodney W. Grimes 25326f9a767SRodney W. Grimes m->flags |= PG_BUSY; 25426f9a767SRodney W. Grimes 255f919ebdeSDavid Greenman vm_page_protect(m, VM_PROT_READ); 25626f9a767SRodney W. Grimes 25726f9a767SRodney W. Grimes object->paging_in_progress++; 25826f9a767SRodney W. Grimes 25926f9a767SRodney W. Grimes pager = vm_pager_allocate(PG_DFLT, (caddr_t) 0, 26026f9a767SRodney W. Grimes object->size, VM_PROT_ALL, 0); 26126f9a767SRodney W. Grimes if (pager != NULL) { 26261ca29b0SDavid Greenman object->pager = pager; 26326f9a767SRodney W. Grimes } 26426f9a767SRodney W. Grimes } 26526f9a767SRodney W. Grimes 26626f9a767SRodney W. Grimes /* 2670d94caffSDavid Greenman * If there is no pager for the page, use the default pager. If 2680d94caffSDavid Greenman * there's no place to put the page at the moment, leave it in the 2690d94caffSDavid Greenman * laundry and hope that there will be paging space later. 27026f9a767SRodney W. Grimes */ 27126f9a767SRodney W. Grimes 27226f9a767SRodney W. Grimes if ((pager && pager->pg_type == PG_SWAP) || 2730d94caffSDavid Greenman (cnt.v_free_count + cnt.v_cache_count) >= cnt.v_pageout_free_min) { 27426f9a767SRodney W. Grimes if (pageout_count == 1) { 27526f9a767SRodney W. Grimes pageout_status[0] = pager ? 27626f9a767SRodney W. Grimes vm_pager_put(pager, m, 27726f9a767SRodney W. Grimes ((sync || (object == kernel_object)) ? TRUE : FALSE)) : 27826f9a767SRodney W. Grimes VM_PAGER_FAIL; 27926f9a767SRodney W. Grimes } else { 28026f9a767SRodney W. Grimes if (!pager) { 28126f9a767SRodney W. Grimes for (i = 0; i < pageout_count; i++) 28226f9a767SRodney W. Grimes pageout_status[i] = VM_PAGER_FAIL; 28326f9a767SRodney W. Grimes } else { 28426f9a767SRodney W. Grimes vm_pager_put_pages(pager, ms, pageout_count, 28526f9a767SRodney W. Grimes ((sync || (object == kernel_object)) ? TRUE : FALSE), 28626f9a767SRodney W. Grimes pageout_status); 28726f9a767SRodney W. Grimes } 28826f9a767SRodney W. Grimes } 28926f9a767SRodney W. Grimes } else { 29026f9a767SRodney W. Grimes for (i = 0; i < pageout_count; i++) 29126f9a767SRodney W. Grimes pageout_status[i] = VM_PAGER_FAIL; 29226f9a767SRodney W. Grimes } 29326f9a767SRodney W. Grimes 29426f9a767SRodney W. Grimes for (i = 0; i < pageout_count; i++) { 29526f9a767SRodney W. Grimes switch (pageout_status[i]) { 29626f9a767SRodney W. Grimes case VM_PAGER_OK: 29726f9a767SRodney W. Grimes ++anyok; 29826f9a767SRodney W. Grimes break; 29926f9a767SRodney W. Grimes case VM_PAGER_PEND: 30026f9a767SRodney W. Grimes ++anyok; 30126f9a767SRodney W. Grimes break; 30226f9a767SRodney W. Grimes case VM_PAGER_BAD: 30326f9a767SRodney W. Grimes /* 3040d94caffSDavid Greenman * Page outside of range of object. Right now we 3050d94caffSDavid Greenman * essentially lose the changes by pretending it 3060d94caffSDavid Greenman * worked. 30726f9a767SRodney W. Grimes */ 30826f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(ms[i])); 3090d94caffSDavid Greenman ms[i]->dirty = 0; 31026f9a767SRodney W. Grimes break; 31126f9a767SRodney W. Grimes case VM_PAGER_ERROR: 31226f9a767SRodney W. Grimes case VM_PAGER_FAIL: 31326f9a767SRodney W. Grimes /* 3140d94caffSDavid Greenman * If page couldn't be paged out, then reactivate the 3150d94caffSDavid Greenman * page so it doesn't clog the inactive list. (We 3160d94caffSDavid Greenman * will try paging out it again later). 31726f9a767SRodney W. Grimes */ 31826f9a767SRodney W. Grimes if (ms[i]->flags & PG_INACTIVE) 31926f9a767SRodney W. Grimes vm_page_activate(ms[i]); 32026f9a767SRodney W. Grimes break; 32126f9a767SRodney W. Grimes case VM_PAGER_AGAIN: 32226f9a767SRodney W. Grimes break; 32326f9a767SRodney W. Grimes } 32426f9a767SRodney W. Grimes 32526f9a767SRodney W. Grimes 32626f9a767SRodney W. Grimes /* 3270d94caffSDavid Greenman * If the operation is still going, leave the page busy to 3280d94caffSDavid Greenman * block all other accesses. Also, leave the paging in 3290d94caffSDavid Greenman * progress indicator set so that we don't attempt an object 3300d94caffSDavid Greenman * collapse. 33126f9a767SRodney W. Grimes */ 33226f9a767SRodney W. Grimes if (pageout_status[i] != VM_PAGER_PEND) { 333f919ebdeSDavid Greenman vm_object_pip_wakeup(object); 3341ed81ef2SDavid Greenman if ((ms[i]->flags & (PG_REFERENCED|PG_WANTED)) || 335a647a309SDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(ms[i]))) { 33626f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(ms[i])); 337a647a309SDavid Greenman ms[i]->flags &= ~PG_REFERENCED; 33826f9a767SRodney W. Grimes if (ms[i]->flags & PG_INACTIVE) 33926f9a767SRodney W. Grimes vm_page_activate(ms[i]); 34026f9a767SRodney W. Grimes } 3411ed81ef2SDavid Greenman PAGE_WAKEUP(ms[i]); 34226f9a767SRodney W. Grimes } 34326f9a767SRodney W. Grimes } 34426f9a767SRodney W. Grimes return anyok; 34526f9a767SRodney W. Grimes } 34626f9a767SRodney W. Grimes 34726f9a767SRodney W. Grimes /* 34826f9a767SRodney W. Grimes * vm_pageout_object_deactivate_pages 34926f9a767SRodney W. Grimes * 35026f9a767SRodney W. Grimes * deactivate enough pages to satisfy the inactive target 35126f9a767SRodney W. Grimes * requirements or if vm_page_proc_limit is set, then 35226f9a767SRodney W. Grimes * deactivate all of the pages in the object and its 35326f9a767SRodney W. Grimes * shadows. 35426f9a767SRodney W. Grimes * 35526f9a767SRodney W. Grimes * The object and map must be locked. 35626f9a767SRodney W. Grimes */ 35726f9a767SRodney W. Grimes int 3580d94caffSDavid Greenman vm_pageout_object_deactivate_pages(map, object, count, map_remove_only) 35926f9a767SRodney W. Grimes vm_map_t map; 36026f9a767SRodney W. Grimes vm_object_t object; 36126f9a767SRodney W. Grimes int count; 3620d94caffSDavid Greenman int map_remove_only; 36326f9a767SRodney W. Grimes { 36426f9a767SRodney W. Grimes register vm_page_t p, next; 36526f9a767SRodney W. Grimes int rcount; 36626f9a767SRodney W. Grimes int dcount; 36726f9a767SRodney W. Grimes 36826f9a767SRodney W. Grimes dcount = 0; 36926f9a767SRodney W. Grimes if (count == 0) 37026f9a767SRodney W. Grimes count = 1; 37126f9a767SRodney W. Grimes 3728f895206SDavid Greenman if (object->pager && (object->pager->pg_type == PG_DEVICE)) 3738f895206SDavid Greenman return 0; 3748f895206SDavid Greenman 3752fe6e4d7SDavid Greenman if (object->shadow) { 3762fe6e4d7SDavid Greenman if (object->shadow->ref_count == 1) 3770d94caffSDavid Greenman dcount += vm_pageout_object_deactivate_pages(map, object->shadow, count / 2 + 1, map_remove_only); 3780d94caffSDavid Greenman else 3796d40c3d3SDavid Greenman vm_pageout_object_deactivate_pages(map, object->shadow, count, 1); 3802fe6e4d7SDavid Greenman } 3810d94caffSDavid Greenman if (object->paging_in_progress || !vm_object_lock_try(object)) 38226f9a767SRodney W. Grimes return dcount; 38326f9a767SRodney W. Grimes 38426f9a767SRodney W. Grimes /* 38526f9a767SRodney W. Grimes * scan the objects entire memory queue 38626f9a767SRodney W. Grimes */ 38726f9a767SRodney W. Grimes rcount = object->resident_page_count; 38826f9a767SRodney W. Grimes p = object->memq.tqh_first; 38926f9a767SRodney W. Grimes while (p && (rcount-- > 0)) { 39026f9a767SRodney W. Grimes next = p->listq.tqe_next; 391a58d1fa1SDavid Greenman cnt.v_pdpages++; 39226f9a767SRodney W. Grimes vm_page_lock_queues(); 3930d94caffSDavid Greenman if (p->wire_count != 0 || 3940d94caffSDavid Greenman p->hold_count != 0 || 3950d94caffSDavid Greenman p->busy != 0 || 3960d94caffSDavid Greenman !pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) { 3970d94caffSDavid Greenman p = next; 3980d94caffSDavid Greenman continue; 3990d94caffSDavid Greenman } 40026f9a767SRodney W. Grimes /* 4010d94caffSDavid Greenman * if a page is active, not wired and is in the processes 4020d94caffSDavid Greenman * pmap, then deactivate the page. 40326f9a767SRodney W. Grimes */ 4040d94caffSDavid Greenman if ((p->flags & (PG_ACTIVE | PG_BUSY)) == PG_ACTIVE) { 405a647a309SDavid Greenman if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p)) && 4061ed81ef2SDavid Greenman (p->flags & (PG_REFERENCED|PG_WANTED)) == 0) { 40726f9a767SRodney W. Grimes p->act_count -= min(p->act_count, ACT_DECLINE); 40826f9a767SRodney W. Grimes /* 4090d94caffSDavid Greenman * if the page act_count is zero -- then we 4100d94caffSDavid Greenman * deactivate 41126f9a767SRodney W. Grimes */ 41226f9a767SRodney W. Grimes if (!p->act_count) { 4130d94caffSDavid Greenman if (!map_remove_only) 41426f9a767SRodney W. Grimes vm_page_deactivate(p); 415f919ebdeSDavid Greenman vm_page_protect(p, VM_PROT_NONE); 41626f9a767SRodney W. Grimes /* 4170d94caffSDavid Greenman * else if on the next go-around we 4180d94caffSDavid Greenman * will deactivate the page we need to 4190d94caffSDavid Greenman * place the page on the end of the 4200d94caffSDavid Greenman * queue to age the other pages in 4210d94caffSDavid Greenman * memory. 42226f9a767SRodney W. Grimes */ 42326f9a767SRodney W. Grimes } else { 42426f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, p, pageq); 42526f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq); 42626f9a767SRodney W. Grimes } 42726f9a767SRodney W. Grimes /* 42826f9a767SRodney W. Grimes * see if we are done yet 42926f9a767SRodney W. Grimes */ 43026f9a767SRodney W. Grimes if (p->flags & PG_INACTIVE) { 43126f9a767SRodney W. Grimes --count; 43226f9a767SRodney W. Grimes ++dcount; 43326f9a767SRodney W. Grimes if (count <= 0 && 43426f9a767SRodney W. Grimes cnt.v_inactive_count > cnt.v_inactive_target) { 43526f9a767SRodney W. Grimes vm_page_unlock_queues(); 4360d94caffSDavid Greenman vm_object_unlock(object); 43726f9a767SRodney W. Grimes return dcount; 43826f9a767SRodney W. Grimes } 43926f9a767SRodney W. Grimes } 44026f9a767SRodney W. Grimes } else { 44126f9a767SRodney W. Grimes /* 44226f9a767SRodney W. Grimes * Move the page to the bottom of the queue. 44326f9a767SRodney W. Grimes */ 44426f9a767SRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(p)); 445a647a309SDavid Greenman p->flags &= ~PG_REFERENCED; 44626f9a767SRodney W. Grimes if (p->act_count < ACT_MAX) 44726f9a767SRodney W. Grimes p->act_count += ACT_ADVANCE; 44826f9a767SRodney W. Grimes 44926f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, p, pageq); 45026f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq); 45126f9a767SRodney W. Grimes } 4520d94caffSDavid Greenman } else if ((p->flags & (PG_INACTIVE | PG_BUSY)) == PG_INACTIVE) { 453f919ebdeSDavid Greenman vm_page_protect(p, VM_PROT_NONE); 45426f9a767SRodney W. Grimes } 45526f9a767SRodney W. Grimes vm_page_unlock_queues(); 45626f9a767SRodney W. Grimes p = next; 45726f9a767SRodney W. Grimes } 4580d94caffSDavid Greenman vm_object_unlock(object); 45926f9a767SRodney W. Grimes return dcount; 46026f9a767SRodney W. Grimes } 46126f9a767SRodney W. Grimes 46226f9a767SRodney W. Grimes 46326f9a767SRodney W. Grimes /* 46426f9a767SRodney W. Grimes * deactivate some number of pages in a map, try to do it fairly, but 46526f9a767SRodney W. Grimes * that is really hard to do. 46626f9a767SRodney W. Grimes */ 46726f9a767SRodney W. Grimes 46826f9a767SRodney W. Grimes void 46926f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(map, entry, count, freeer) 47026f9a767SRodney W. Grimes vm_map_t map; 47126f9a767SRodney W. Grimes vm_map_entry_t entry; 47226f9a767SRodney W. Grimes int *count; 47326f9a767SRodney W. Grimes int (*freeer) (vm_map_t, vm_object_t, int); 47426f9a767SRodney W. Grimes { 47526f9a767SRodney W. Grimes vm_map_t tmpm; 47626f9a767SRodney W. Grimes vm_map_entry_t tmpe; 47726f9a767SRodney W. Grimes vm_object_t obj; 4780d94caffSDavid Greenman 47926f9a767SRodney W. Grimes if (*count <= 0) 48026f9a767SRodney W. Grimes return; 48126f9a767SRodney W. Grimes vm_map_reference(map); 48226f9a767SRodney W. Grimes if (!lock_try_read(&map->lock)) { 48326f9a767SRodney W. Grimes vm_map_deallocate(map); 48426f9a767SRodney W. Grimes return; 48526f9a767SRodney W. Grimes } 48626f9a767SRodney W. Grimes if (entry == 0) { 48726f9a767SRodney W. Grimes tmpe = map->header.next; 48826f9a767SRodney W. Grimes while (tmpe != &map->header && *count > 0) { 4890d94caffSDavid Greenman vm_pageout_map_deactivate_pages(map, tmpe, count, freeer, 0); 49026f9a767SRodney W. Grimes tmpe = tmpe->next; 49126f9a767SRodney W. Grimes }; 49226f9a767SRodney W. Grimes } else if (entry->is_sub_map || entry->is_a_map) { 49326f9a767SRodney W. Grimes tmpm = entry->object.share_map; 49426f9a767SRodney W. Grimes tmpe = tmpm->header.next; 49526f9a767SRodney W. Grimes while (tmpe != &tmpm->header && *count > 0) { 4960d94caffSDavid Greenman vm_pageout_map_deactivate_pages(tmpm, tmpe, count, freeer, 0); 49726f9a767SRodney W. Grimes tmpe = tmpe->next; 49826f9a767SRodney W. Grimes }; 4994e39a515SPoul-Henning Kamp } else if ((obj = entry->object.vm_object) != 0) { 50026f9a767SRodney W. Grimes *count -= (*freeer) (map, obj, *count); 50126f9a767SRodney W. Grimes } 50226f9a767SRodney W. Grimes lock_read_done(&map->lock); 50326f9a767SRodney W. Grimes vm_map_deallocate(map); 50426f9a767SRodney W. Grimes return; 50526f9a767SRodney W. Grimes } 506df8bae1dSRodney W. Grimes 5072fe6e4d7SDavid Greenman void 5080d94caffSDavid Greenman vm_req_vmdaemon() 5090d94caffSDavid Greenman { 5100d94caffSDavid Greenman static int lastrun = 0; 5110d94caffSDavid Greenman 5122fe6e4d7SDavid Greenman if ((ticks > (lastrun + hz / 10)) || (ticks < lastrun)) { 5132fe6e4d7SDavid Greenman wakeup((caddr_t) &vm_daemon_needed); 5142fe6e4d7SDavid Greenman lastrun = ticks; 5152fe6e4d7SDavid Greenman } 5162fe6e4d7SDavid Greenman } 5172fe6e4d7SDavid Greenman 518df8bae1dSRodney W. Grimes /* 519df8bae1dSRodney W. Grimes * vm_pageout_scan does the dirty work for the pageout daemon. 520df8bae1dSRodney W. Grimes */ 52126f9a767SRodney W. Grimes int 522df8bae1dSRodney W. Grimes vm_pageout_scan() 523df8bae1dSRodney W. Grimes { 52426f9a767SRodney W. Grimes vm_page_t m; 525f6b04d2bSDavid Greenman int page_shortage, maxscan, maxlaunder, pcount; 5264e39a515SPoul-Henning Kamp int pages_freed; 52726f9a767SRodney W. Grimes vm_page_t next; 5285663e6deSDavid Greenman struct proc *p, *bigproc; 5295663e6deSDavid Greenman vm_offset_t size, bigsize; 530df8bae1dSRodney W. Grimes vm_object_t object; 53126f9a767SRodney W. Grimes int force_wakeup = 0; 532f6b04d2bSDavid Greenman int vnodes_skipped = 0; 5330d94caffSDavid Greenman 5342fe6e4d7SDavid Greenman /* calculate the total cached size */ 5352fe6e4d7SDavid Greenman 5360d94caffSDavid Greenman if ((cnt.v_inactive_count + cnt.v_free_count + cnt.v_cache_count) < 5370d94caffSDavid Greenman (cnt.v_inactive_target + cnt.v_free_min)) { 5382fe6e4d7SDavid Greenman vm_req_vmdaemon(); 5392fe6e4d7SDavid Greenman } 5402fe6e4d7SDavid Greenman /* 5412fe6e4d7SDavid Greenman * now swap processes out if we are in low memory conditions 5422fe6e4d7SDavid Greenman */ 5430d94caffSDavid Greenman if ((cnt.v_free_count <= cnt.v_free_min) && 5440d94caffSDavid Greenman !swap_pager_full && vm_swap_size && vm_pageout_req_swapout == 0) { 5452fe6e4d7SDavid Greenman vm_pageout_req_swapout = 1; 5462fe6e4d7SDavid Greenman vm_req_vmdaemon(); 5472fe6e4d7SDavid Greenman } 54826f9a767SRodney W. Grimes pages_freed = 0; 549df8bae1dSRodney W. Grimes 550df8bae1dSRodney W. Grimes /* 5510d94caffSDavid Greenman * Start scanning the inactive queue for pages we can free. We keep 5520d94caffSDavid Greenman * scanning until we have enough free pages or we have scanned through 5530d94caffSDavid Greenman * the entire queue. If we encounter dirty pages, we start cleaning 5540d94caffSDavid Greenman * them. 555df8bae1dSRodney W. Grimes */ 556df8bae1dSRodney W. Grimes 5570d94caffSDavid Greenman maxlaunder = (cnt.v_inactive_target > MAXLAUNDER) ? 5580d94caffSDavid Greenman MAXLAUNDER : cnt.v_inactive_target; 5590d94caffSDavid Greenman 56026f9a767SRodney W. Grimes rescan1: 561f6b04d2bSDavid Greenman maxscan = cnt.v_inactive_count; 56226f9a767SRodney W. Grimes m = vm_page_queue_inactive.tqh_first; 563f6b04d2bSDavid Greenman while ((m != NULL) && (maxscan-- > 0) && 564f6b04d2bSDavid Greenman ((cnt.v_cache_count + cnt.v_free_count) < (cnt.v_cache_min + cnt.v_free_target))) { 56526f9a767SRodney W. Grimes vm_page_t next; 566df8bae1dSRodney W. Grimes 567a58d1fa1SDavid Greenman cnt.v_pdpages++; 568df8bae1dSRodney W. Grimes next = m->pageq.tqe_next; 569df8bae1dSRodney W. Grimes 5700d94caffSDavid Greenman #if defined(VM_DIAGNOSE) 57126f9a767SRodney W. Grimes if ((m->flags & PG_INACTIVE) == 0) { 572832f3afdSAndreas Schulz printf("vm_pageout_scan: page not inactive?\n"); 5730d94caffSDavid Greenman break; 574df8bae1dSRodney W. Grimes } 5750d94caffSDavid Greenman #endif 57626f9a767SRodney W. Grimes 57726f9a767SRodney W. Grimes /* 57826f9a767SRodney W. Grimes * dont mess with busy pages 57926f9a767SRodney W. Grimes */ 580f6b04d2bSDavid Greenman if (m->hold_count || m->busy || (m->flags & PG_BUSY)) { 5810d94caffSDavid Greenman TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq); 5820d94caffSDavid Greenman TAILQ_INSERT_TAIL(&vm_page_queue_inactive, m, pageq); 58326f9a767SRodney W. Grimes m = next; 58426f9a767SRodney W. Grimes continue; 58526f9a767SRodney W. Grimes } 5860d94caffSDavid Greenman if (((m->flags & PG_REFERENCED) == 0) && 5870d94caffSDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 5882fe6e4d7SDavid Greenman m->flags |= PG_REFERENCED; 5890d94caffSDavid Greenman } 5900d94caffSDavid Greenman if (m->object->ref_count == 0) { 5910d94caffSDavid Greenman m->flags &= ~PG_REFERENCED; 5922fe6e4d7SDavid Greenman pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 5932fe6e4d7SDavid Greenman } 5941ed81ef2SDavid Greenman if ((m->flags & (PG_REFERENCED|PG_WANTED)) != 0) { 595a647a309SDavid Greenman m->flags &= ~PG_REFERENCED; 5960d94caffSDavid Greenman pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 59726f9a767SRodney W. Grimes vm_page_activate(m); 5986d40c3d3SDavid Greenman if (m->act_count < ACT_MAX) 5996d40c3d3SDavid Greenman m->act_count += ACT_ADVANCE; 6000d94caffSDavid Greenman m = next; 6010d94caffSDavid Greenman continue; 6020d94caffSDavid Greenman } 6030d94caffSDavid Greenman 604f6b04d2bSDavid Greenman vm_page_test_dirty(m); 605f6b04d2bSDavid Greenman if (m->dirty == 0) { 606f6b04d2bSDavid Greenman if (m->bmapped == 0) { 6076d40c3d3SDavid Greenman if (m->valid == 0) { 6086d40c3d3SDavid Greenman pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE); 6096d40c3d3SDavid Greenman vm_page_free(m); 6100bb3a0d2SDavid Greenman cnt.v_dfree++; 6116f2b142eSDavid Greenman } else { 6120d94caffSDavid Greenman vm_page_cache(m); 6136d40c3d3SDavid Greenman } 614f6b04d2bSDavid Greenman ++pages_freed; 615f6b04d2bSDavid Greenman } else { 616f6b04d2bSDavid Greenman m = next; 617f6b04d2bSDavid Greenman continue; 618f6b04d2bSDavid Greenman } 6190d94caffSDavid Greenman } else if (maxlaunder > 0) { 6200d94caffSDavid Greenman int written; 621f6b04d2bSDavid Greenman struct vnode *vp = NULL; 6220d94caffSDavid Greenman 6230d94caffSDavid Greenman object = m->object; 624a1f6d91cSDavid Greenman if ((object->flags & OBJ_DEAD) || !vm_object_lock_try(object)) { 6250d94caffSDavid Greenman m = next; 6260d94caffSDavid Greenman continue; 6270d94caffSDavid Greenman } 628f6b04d2bSDavid Greenman 629f6b04d2bSDavid Greenman if (object->pager && object->pager->pg_type == PG_VNODE) { 630f6b04d2bSDavid Greenman vp = ((vn_pager_t) object->pager->pg_data)->vnp_vp; 631f6b04d2bSDavid Greenman if (VOP_ISLOCKED(vp) || vget(vp, 1)) { 632f6b04d2bSDavid Greenman vm_object_unlock(object); 633f6b04d2bSDavid Greenman if (object->flags & OBJ_WRITEABLE) 634f6b04d2bSDavid Greenman ++vnodes_skipped; 635f6b04d2bSDavid Greenman m = next; 636f6b04d2bSDavid Greenman continue; 637f6b04d2bSDavid Greenman } 638f6b04d2bSDavid Greenman } 639f6b04d2bSDavid Greenman 6400d94caffSDavid Greenman /* 6410d94caffSDavid Greenman * If a page is dirty, then it is either being washed 6420d94caffSDavid Greenman * (but not yet cleaned) or it is still in the 6430d94caffSDavid Greenman * laundry. If it is still in the laundry, then we 6440d94caffSDavid Greenman * start the cleaning operation. 6450d94caffSDavid Greenman */ 6460d94caffSDavid Greenman written = vm_pageout_clean(m, 0); 647f6b04d2bSDavid Greenman 648f6b04d2bSDavid Greenman if (vp) 649f6b04d2bSDavid Greenman vput(vp); 650f6b04d2bSDavid Greenman 6510d94caffSDavid Greenman vm_object_unlock(object); 6520d94caffSDavid Greenman 6530d94caffSDavid Greenman if (!next) { 6540d94caffSDavid Greenman break; 6550d94caffSDavid Greenman } 6560d94caffSDavid Greenman maxlaunder -= written; 6570d94caffSDavid Greenman /* 6580d94caffSDavid Greenman * if the next page has been re-activated, start 6590d94caffSDavid Greenman * scanning again 6600d94caffSDavid Greenman */ 6610d94caffSDavid Greenman if ((next->flags & PG_INACTIVE) == 0) { 6620d94caffSDavid Greenman goto rescan1; 6630d94caffSDavid Greenman } 664df8bae1dSRodney W. Grimes } 66526f9a767SRodney W. Grimes m = next; 66626f9a767SRodney W. Grimes } 66726f9a767SRodney W. Grimes 668df8bae1dSRodney W. Grimes /* 6690d94caffSDavid Greenman * Compute the page shortage. If we are still very low on memory be 6700d94caffSDavid Greenman * sure that we will move a minimal amount of pages from active to 6710d94caffSDavid Greenman * inactive. 672df8bae1dSRodney W. Grimes */ 673df8bae1dSRodney W. Grimes 67426f9a767SRodney W. Grimes page_shortage = cnt.v_inactive_target - 6750d94caffSDavid Greenman (cnt.v_free_count + cnt.v_inactive_count + cnt.v_cache_count); 67626f9a767SRodney W. Grimes if (page_shortage <= 0) { 67726f9a767SRodney W. Grimes if (pages_freed == 0) { 67817c4c408SDavid Greenman page_shortage = cnt.v_free_min - cnt.v_free_count; 679f6b04d2bSDavid Greenman } else { 680f6b04d2bSDavid Greenman page_shortage = 1; 68126f9a767SRodney W. Grimes } 682df8bae1dSRodney W. Grimes } 683f6b04d2bSDavid Greenman maxscan = MAXSCAN; 684f6b04d2bSDavid Greenman pcount = cnt.v_active_count; 68526f9a767SRodney W. Grimes m = vm_page_queue_active.tqh_first; 686f6b04d2bSDavid Greenman while ((m != NULL) && (maxscan > 0) && (pcount-- > 0) && (page_shortage > 0)) { 68726f9a767SRodney W. Grimes 688a58d1fa1SDavid Greenman cnt.v_pdpages++; 68926f9a767SRodney W. Grimes next = m->pageq.tqe_next; 690df8bae1dSRodney W. Grimes 691df8bae1dSRodney W. Grimes /* 69226f9a767SRodney W. Grimes * Don't deactivate pages that are busy. 693df8bae1dSRodney W. Grimes */ 694a647a309SDavid Greenman if ((m->busy != 0) || 6950d94caffSDavid Greenman (m->flags & PG_BUSY) || 696f6b04d2bSDavid Greenman (m->hold_count != 0)) { 6976d40c3d3SDavid Greenman TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 6986d40c3d3SDavid Greenman TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 69926f9a767SRodney W. Grimes m = next; 70026f9a767SRodney W. Grimes continue; 701df8bae1dSRodney W. Grimes } 7021ed81ef2SDavid Greenman if (m->object->ref_count && ((m->flags & (PG_REFERENCED|PG_WANTED)) || 7030d94caffSDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(m)))) { 7040d94caffSDavid Greenman int s; 705df8bae1dSRodney W. Grimes 706df8bae1dSRodney W. Grimes pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 707a647a309SDavid Greenman m->flags &= ~PG_REFERENCED; 7080d94caffSDavid Greenman if (m->act_count < ACT_MAX) { 70926f9a767SRodney W. Grimes m->act_count += ACT_ADVANCE; 7100d94caffSDavid Greenman } 71126f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 71226f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 71326f9a767SRodney W. Grimes } else { 7146d40c3d3SDavid Greenman m->flags &= ~PG_REFERENCED; 7156d40c3d3SDavid Greenman pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 71626f9a767SRodney W. Grimes m->act_count -= min(m->act_count, ACT_DECLINE); 717df8bae1dSRodney W. Grimes 718df8bae1dSRodney W. Grimes /* 71926f9a767SRodney W. Grimes * if the page act_count is zero -- then we deactivate 720df8bae1dSRodney W. Grimes */ 7210d94caffSDavid Greenman if (!m->act_count && (page_shortage > 0)) { 7220d94caffSDavid Greenman if (m->object->ref_count == 0) { 7230d94caffSDavid Greenman --page_shortage; 724f6b04d2bSDavid Greenman vm_page_test_dirty(m); 725f6b04d2bSDavid Greenman if ((m->bmapped == 0) && (m->dirty == 0) ) { 7260d94caffSDavid Greenman m->act_count = 0; 7270d94caffSDavid Greenman vm_page_cache(m); 7280d94caffSDavid Greenman } else { 7290d94caffSDavid Greenman vm_page_deactivate(m); 7300d94caffSDavid Greenman } 7310d94caffSDavid Greenman } else { 73226f9a767SRodney W. Grimes vm_page_deactivate(m); 73326f9a767SRodney W. Grimes --page_shortage; 7340d94caffSDavid Greenman } 7356d40c3d3SDavid Greenman } else if (m->act_count) { 73626f9a767SRodney W. Grimes TAILQ_REMOVE(&vm_page_queue_active, m, pageq); 73726f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq); 738df8bae1dSRodney W. Grimes } 739df8bae1dSRodney W. Grimes } 740f6b04d2bSDavid Greenman maxscan--; 74126f9a767SRodney W. Grimes m = next; 74226f9a767SRodney W. Grimes } 743df8bae1dSRodney W. Grimes 744df8bae1dSRodney W. Grimes /* 7450d94caffSDavid Greenman * We try to maintain some *really* free pages, this allows interrupt 7460d94caffSDavid Greenman * code to be guaranteed space. 747df8bae1dSRodney W. Grimes */ 748a1f6d91cSDavid Greenman while (cnt.v_free_count < cnt.v_free_reserved) { 7490d94caffSDavid Greenman m = vm_page_queue_cache.tqh_first; 7500d94caffSDavid Greenman if (!m) 7510d94caffSDavid Greenman break; 7520d94caffSDavid Greenman vm_page_free(m); 7530bb3a0d2SDavid Greenman cnt.v_dfree++; 75426f9a767SRodney W. Grimes } 7555663e6deSDavid Greenman 7565663e6deSDavid Greenman /* 757f6b04d2bSDavid Greenman * If we didn't get enough free pages, and we have skipped a vnode 758f6b04d2bSDavid Greenman * in a writeable object, wakeup the sync daemon. 759f6b04d2bSDavid Greenman */ 760f6b04d2bSDavid Greenman if (vnodes_skipped && 761f6b04d2bSDavid Greenman (cnt.v_cache_count + cnt.v_free_count) < cnt.v_free_min) { 762f6b04d2bSDavid Greenman if (!vfs_update_wakeup) { 763f6b04d2bSDavid Greenman vfs_update_wakeup = 1; 764f6b04d2bSDavid Greenman wakeup((caddr_t) &vfs_update_wakeup); 765f6b04d2bSDavid Greenman } 766f6b04d2bSDavid Greenman } 767f6b04d2bSDavid Greenman 768f6b04d2bSDavid Greenman /* 7690d94caffSDavid Greenman * make sure that we have swap space -- if we are low on memory and 7700d94caffSDavid Greenman * swap -- then kill the biggest process. 7715663e6deSDavid Greenman */ 7725663e6deSDavid Greenman if ((vm_swap_size == 0 || swap_pager_full) && 7730d94caffSDavid Greenman ((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min)) { 7745663e6deSDavid Greenman bigproc = NULL; 7755663e6deSDavid Greenman bigsize = 0; 7765663e6deSDavid Greenman for (p = (struct proc *) allproc; p != NULL; p = p->p_next) { 7775663e6deSDavid Greenman /* 7785663e6deSDavid Greenman * if this is a system process, skip it 7795663e6deSDavid Greenman */ 78079221631SDavid Greenman if ((p->p_flag & P_SYSTEM) || (p->p_pid == 1) || 78179221631SDavid Greenman ((p->p_pid < 48) && (vm_swap_size != 0))) { 7825663e6deSDavid Greenman continue; 7835663e6deSDavid Greenman } 7845663e6deSDavid Greenman /* 7855663e6deSDavid Greenman * if the process is in a non-running type state, 7865663e6deSDavid Greenman * don't touch it. 7875663e6deSDavid Greenman */ 7885663e6deSDavid Greenman if (p->p_stat != SRUN && p->p_stat != SSLEEP) { 7895663e6deSDavid Greenman continue; 7905663e6deSDavid Greenman } 7915663e6deSDavid Greenman /* 7925663e6deSDavid Greenman * get the process size 7935663e6deSDavid Greenman */ 7945663e6deSDavid Greenman size = p->p_vmspace->vm_pmap.pm_stats.resident_count; 7955663e6deSDavid Greenman /* 7965663e6deSDavid Greenman * if the this process is bigger than the biggest one 7975663e6deSDavid Greenman * remember it. 7985663e6deSDavid Greenman */ 7995663e6deSDavid Greenman if (size > bigsize) { 8005663e6deSDavid Greenman bigproc = p; 8015663e6deSDavid Greenman bigsize = size; 8025663e6deSDavid Greenman } 8035663e6deSDavid Greenman } 8045663e6deSDavid Greenman if (bigproc != NULL) { 8055663e6deSDavid Greenman printf("Process %lu killed by vm_pageout -- out of swap\n", (u_long) bigproc->p_pid); 8065663e6deSDavid Greenman psignal(bigproc, SIGKILL); 8075663e6deSDavid Greenman bigproc->p_estcpu = 0; 8085663e6deSDavid Greenman bigproc->p_nice = PRIO_MIN; 8095663e6deSDavid Greenman resetpriority(bigproc); 8105663e6deSDavid Greenman wakeup((caddr_t) &cnt.v_free_count); 8115663e6deSDavid Greenman } 8125663e6deSDavid Greenman } 81326f9a767SRodney W. Grimes vm_page_pagesfreed += pages_freed; 81426f9a767SRodney W. Grimes return force_wakeup; 81526f9a767SRodney W. Grimes } 81626f9a767SRodney W. Grimes 817df8bae1dSRodney W. Grimes /* 818df8bae1dSRodney W. Grimes * vm_pageout is the high level pageout daemon. 819df8bae1dSRodney W. Grimes */ 82026f9a767SRodney W. Grimes void 82126f9a767SRodney W. Grimes vm_pageout() 822df8bae1dSRodney W. Grimes { 823df8bae1dSRodney W. Grimes (void) spl0(); 824df8bae1dSRodney W. Grimes 825df8bae1dSRodney W. Grimes /* 826df8bae1dSRodney W. Grimes * Initialize some paging parameters. 827df8bae1dSRodney W. Grimes */ 828df8bae1dSRodney W. Grimes 829f6b04d2bSDavid Greenman cnt.v_interrupt_free_min = 2; 830f6b04d2bSDavid Greenman 8310d94caffSDavid Greenman if (cnt.v_page_count > 1024) 8320d94caffSDavid Greenman cnt.v_free_min = 4 + (cnt.v_page_count - 1024) / 200; 8330d94caffSDavid Greenman else 8340d94caffSDavid Greenman cnt.v_free_min = 4; 835ed74321bSDavid Greenman /* 8360d94caffSDavid Greenman * free_reserved needs to include enough for the largest swap pager 8370d94caffSDavid Greenman * structures plus enough for any pv_entry structs when paging. 838ed74321bSDavid Greenman */ 839f6b04d2bSDavid Greenman cnt.v_pageout_free_min = 6 + cnt.v_page_count / 1024 + 840f6b04d2bSDavid Greenman cnt.v_interrupt_free_min; 8410d94caffSDavid Greenman cnt.v_free_reserved = cnt.v_pageout_free_min + 2; 8420d94caffSDavid Greenman cnt.v_free_target = 3 * cnt.v_free_min + cnt.v_free_reserved; 84326f9a767SRodney W. Grimes cnt.v_free_min += cnt.v_free_reserved; 8446f2b142eSDavid Greenman 8450d94caffSDavid Greenman if (cnt.v_page_count > 1024) { 8460d94caffSDavid Greenman cnt.v_cache_max = (cnt.v_free_count - 1024) / 2; 8476f2b142eSDavid Greenman cnt.v_cache_min = (cnt.v_free_count - 1024) / 8; 8486f2b142eSDavid Greenman cnt.v_inactive_target = 2*cnt.v_cache_min + 192; 8490d94caffSDavid Greenman } else { 8500d94caffSDavid Greenman cnt.v_cache_min = 0; 8510d94caffSDavid Greenman cnt.v_cache_max = 0; 8526f2b142eSDavid Greenman cnt.v_inactive_target = cnt.v_free_count / 4; 8530d94caffSDavid Greenman } 854df8bae1dSRodney W. Grimes 855df8bae1dSRodney W. Grimes /* XXX does not really belong here */ 856df8bae1dSRodney W. Grimes if (vm_page_max_wired == 0) 857df8bae1dSRodney W. Grimes vm_page_max_wired = cnt.v_free_count / 3; 858df8bae1dSRodney W. Grimes 85926f9a767SRodney W. Grimes 86026f9a767SRodney W. Grimes (void) swap_pager_alloc(0, 0, 0, 0); 861df8bae1dSRodney W. Grimes /* 8620d94caffSDavid Greenman * The pageout daemon is never done, so loop forever. 863df8bae1dSRodney W. Grimes */ 864df8bae1dSRodney W. Grimes while (TRUE) { 865f919ebdeSDavid Greenman int s = splhigh(); 866f919ebdeSDavid Greenman 867f919ebdeSDavid Greenman if (!vm_pages_needed || 868f919ebdeSDavid Greenman ((cnt.v_free_count >= cnt.v_free_reserved) && 869f919ebdeSDavid Greenman (cnt.v_free_count + cnt.v_cache_count >= cnt.v_free_min))) { 870f919ebdeSDavid Greenman vm_pages_needed = 0; 87126f9a767SRodney W. Grimes tsleep((caddr_t) &vm_pages_needed, PVM, "psleep", 0); 872f919ebdeSDavid Greenman } 873f919ebdeSDavid Greenman vm_pages_needed = 0; 874f919ebdeSDavid Greenman splx(s); 875a58d1fa1SDavid Greenman cnt.v_pdwakeups++; 876df8bae1dSRodney W. Grimes vm_pager_sync(); 8770d94caffSDavid Greenman vm_pageout_scan(); 87826f9a767SRodney W. Grimes vm_pager_sync(); 87926f9a767SRodney W. Grimes wakeup((caddr_t) &cnt.v_free_count); 88026f9a767SRodney W. Grimes wakeup((caddr_t) kmem_map); 881df8bae1dSRodney W. Grimes } 882df8bae1dSRodney W. Grimes } 88326f9a767SRodney W. Grimes 8842fe6e4d7SDavid Greenman void 8854f9fb771SBruce Evans vm_daemon() 8860d94caffSDavid Greenman { 8872fe6e4d7SDavid Greenman vm_object_t object; 8882fe6e4d7SDavid Greenman struct proc *p; 8890d94caffSDavid Greenman 8902fe6e4d7SDavid Greenman while (TRUE) { 8912fe6e4d7SDavid Greenman tsleep((caddr_t) &vm_daemon_needed, PUSER, "psleep", 0); 8922fe6e4d7SDavid Greenman swapout_threads(); 8932fe6e4d7SDavid Greenman /* 8940d94caffSDavid Greenman * scan the processes for exceeding their rlimits or if 8950d94caffSDavid Greenman * process is swapped out -- deactivate pages 8962fe6e4d7SDavid Greenman */ 8972fe6e4d7SDavid Greenman 8982fe6e4d7SDavid Greenman for (p = (struct proc *) allproc; p != NULL; p = p->p_next) { 8992fe6e4d7SDavid Greenman int overage; 9002fe6e4d7SDavid Greenman quad_t limit; 9012fe6e4d7SDavid Greenman vm_offset_t size; 9022fe6e4d7SDavid Greenman 9032fe6e4d7SDavid Greenman /* 9042fe6e4d7SDavid Greenman * if this is a system process or if we have already 9052fe6e4d7SDavid Greenman * looked at this process, skip it. 9062fe6e4d7SDavid Greenman */ 9072fe6e4d7SDavid Greenman if (p->p_flag & (P_SYSTEM | P_WEXIT)) { 9082fe6e4d7SDavid Greenman continue; 9092fe6e4d7SDavid Greenman } 9102fe6e4d7SDavid Greenman /* 9112fe6e4d7SDavid Greenman * if the process is in a non-running type state, 9122fe6e4d7SDavid Greenman * don't touch it. 9132fe6e4d7SDavid Greenman */ 9142fe6e4d7SDavid Greenman if (p->p_stat != SRUN && p->p_stat != SSLEEP) { 9152fe6e4d7SDavid Greenman continue; 9162fe6e4d7SDavid Greenman } 9172fe6e4d7SDavid Greenman /* 9182fe6e4d7SDavid Greenman * get a limit 9192fe6e4d7SDavid Greenman */ 9202fe6e4d7SDavid Greenman limit = qmin(p->p_rlimit[RLIMIT_RSS].rlim_cur, 9212fe6e4d7SDavid Greenman p->p_rlimit[RLIMIT_RSS].rlim_max); 9222fe6e4d7SDavid Greenman 9232fe6e4d7SDavid Greenman /* 9240d94caffSDavid Greenman * let processes that are swapped out really be 9250d94caffSDavid Greenman * swapped out set the limit to nothing (will force a 9260d94caffSDavid Greenman * swap-out.) 9272fe6e4d7SDavid Greenman */ 9282fe6e4d7SDavid Greenman if ((p->p_flag & P_INMEM) == 0) 9290d94caffSDavid Greenman limit = 0; /* XXX */ 9302fe6e4d7SDavid Greenman 9312fe6e4d7SDavid Greenman size = p->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG; 9322fe6e4d7SDavid Greenman if (limit >= 0 && size >= limit) { 9332fe6e4d7SDavid Greenman overage = (size - limit) / NBPG; 9342fe6e4d7SDavid Greenman vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map, 9352fe6e4d7SDavid Greenman (vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages); 9362fe6e4d7SDavid Greenman } 9372fe6e4d7SDavid Greenman } 9382fe6e4d7SDavid Greenman } 9392fe6e4d7SDavid Greenman 9400d94caffSDavid Greenman /* 9410d94caffSDavid Greenman * we remove cached objects that have no RSS... 9420d94caffSDavid Greenman */ 9430d94caffSDavid Greenman restart: 9442fe6e4d7SDavid Greenman vm_object_cache_lock(); 9452fe6e4d7SDavid Greenman object = vm_object_cached_list.tqh_first; 9462fe6e4d7SDavid Greenman while (object) { 9472fe6e4d7SDavid Greenman vm_object_cache_unlock(); 9482fe6e4d7SDavid Greenman /* 9492fe6e4d7SDavid Greenman * if there are no resident pages -- get rid of the object 9502fe6e4d7SDavid Greenman */ 9512fe6e4d7SDavid Greenman if (object->resident_page_count == 0) { 9522fe6e4d7SDavid Greenman if (object != vm_object_lookup(object->pager)) 9532fe6e4d7SDavid Greenman panic("vm_object_cache_trim: I'm sooo confused."); 9542fe6e4d7SDavid Greenman pager_cache(object, FALSE); 9552fe6e4d7SDavid Greenman goto restart; 9562fe6e4d7SDavid Greenman } 9572fe6e4d7SDavid Greenman object = object->cached_list.tqe_next; 9582fe6e4d7SDavid Greenman vm_object_cache_lock(); 9592fe6e4d7SDavid Greenman } 9602fe6e4d7SDavid Greenman vm_object_cache_unlock(); 9612fe6e4d7SDavid Greenman } 962