145748Smckusick /* 245748Smckusick * Copyright (c) 1991 Regents of the University of California. 345748Smckusick * All rights reserved. 445748Smckusick * 545748Smckusick * This code is derived from software contributed to Berkeley by 645748Smckusick * The Mach Operating System project at Carnegie-Mellon University. 745748Smckusick * 848493Smckusick * %sccs.include.redist.c% 945748Smckusick * 10*56918Shibler * @(#)vm_pageout.c 7.10 (Berkeley) 11/29/92 1148493Smckusick * 1248493Smckusick * 1348493Smckusick * Copyright (c) 1987, 1990 Carnegie-Mellon University. 1448493Smckusick * All rights reserved. 1548493Smckusick * 1648493Smckusick * Authors: Avadis Tevanian, Jr., Michael Wayne Young 1748493Smckusick * 1848493Smckusick * Permission to use, copy, modify and distribute this software and 1948493Smckusick * its documentation is hereby granted, provided that both the copyright 2048493Smckusick * notice and this permission notice appear in all copies of the 2148493Smckusick * software, derivative works or modified versions, and any portions 2248493Smckusick * thereof, and that both notices appear in supporting documentation. 2348493Smckusick * 2448493Smckusick * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 2548493Smckusick * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 2648493Smckusick * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 2748493Smckusick * 2848493Smckusick * Carnegie Mellon requests users of this software to return to 2948493Smckusick * 3048493Smckusick * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 3148493Smckusick * School of Computer Science 3248493Smckusick * Carnegie Mellon University 3348493Smckusick * Pittsburgh PA 15213-3890 3448493Smckusick * 3548493Smckusick * any improvements or extensions that they make and grant Carnegie the 3648493Smckusick * rights to redistribute these changes. 3745748Smckusick */ 3845748Smckusick 3945748Smckusick /* 4045748Smckusick * The proverbial page-out daemon. 4145748Smckusick */ 4245748Smckusick 4353359Sbostic #include <sys/param.h> 4445748Smckusick 4553359Sbostic #include <vm/vm.h> 4653359Sbostic #include <vm/vm_page.h> 4753359Sbostic #include <vm/vm_pageout.h> 4848386Skarels 4950554Smckusick int vm_pages_needed; /* Event on which pageout daemon sleeps */ 5045748Smckusick 5145748Smckusick int vm_page_free_min_sanity = 40; 5245748Smckusick 5345748Smckusick /* 5445748Smckusick * vm_pageout_scan does the dirty work for the pageout daemon. 5545748Smckusick */ 5653359Sbostic void 5745748Smckusick vm_pageout_scan() 5845748Smckusick { 5945748Smckusick register vm_page_t m; 6045748Smckusick register int page_shortage; 6145748Smckusick register int s; 6245748Smckusick register int pages_freed; 6345748Smckusick int free; 6445748Smckusick 6545748Smckusick /* 6645748Smckusick * Only continue when we want more pages to be "free" 6745748Smckusick */ 6845748Smckusick 6945748Smckusick s = splimp(); 7045748Smckusick simple_lock(&vm_page_queue_free_lock); 7150922Smckusick free = cnt.v_free_count; 7245748Smckusick simple_unlock(&vm_page_queue_free_lock); 7345748Smckusick splx(s); 7445748Smckusick 7550922Smckusick if (free < cnt.v_free_target) { 7645748Smckusick swapout_threads(); 7745748Smckusick 7845748Smckusick /* 7945748Smckusick * Be sure the pmap system is updated so 8045748Smckusick * we can scan the inactive queue. 8145748Smckusick */ 8245748Smckusick 8345748Smckusick pmap_update(); 8445748Smckusick } 8545748Smckusick 8645748Smckusick /* 8745748Smckusick * Acquire the resident page system lock, 8845748Smckusick * as we may be changing what's resident quite a bit. 8945748Smckusick */ 9045748Smckusick vm_page_lock_queues(); 9145748Smckusick 9245748Smckusick /* 9345748Smckusick * Start scanning the inactive queue for pages we can free. 9445748Smckusick * We keep scanning until we have enough free pages or 9545748Smckusick * we have scanned through the entire queue. If we 9645748Smckusick * encounter dirty pages, we start cleaning them. 9745748Smckusick */ 9845748Smckusick 9945748Smckusick pages_freed = 0; 10045748Smckusick m = (vm_page_t) queue_first(&vm_page_queue_inactive); 10145748Smckusick while (!queue_end(&vm_page_queue_inactive, (queue_entry_t) m)) { 102*56918Shibler vm_page_t next; 103*56918Shibler vm_object_t object; 104*56918Shibler vm_pager_t pager; 105*56918Shibler int pageout_status; 10645748Smckusick 10745748Smckusick s = splimp(); 10845748Smckusick simple_lock(&vm_page_queue_free_lock); 10950922Smckusick free = cnt.v_free_count; 11045748Smckusick simple_unlock(&vm_page_queue_free_lock); 11145748Smckusick splx(s); 11245748Smckusick 11350922Smckusick if (free >= cnt.v_free_target) 11445748Smckusick break; 11545748Smckusick 116*56918Shibler /* 117*56918Shibler * If the page has been referenced, move it back to the 118*56918Shibler * active queue. 119*56918Shibler */ 120*56918Shibler if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 121*56918Shibler next = (vm_page_t) queue_next(&m->pageq); 122*56918Shibler vm_page_activate(m); 123*56918Shibler cnt.v_reactivated++; 124*56918Shibler m = next; 125*56918Shibler continue; 126*56918Shibler } 127*56918Shibler 128*56918Shibler /* 129*56918Shibler * If the page is clean, free it up. 130*56918Shibler */ 13156382Smckusick if (m->flags & PG_CLEAN) { 13245748Smckusick next = (vm_page_t) queue_next(&m->pageq); 133*56918Shibler object = m->object; 134*56918Shibler if (vm_object_lock_try(object)) { 13549293Shibler pmap_page_protect(VM_PAGE_TO_PHYS(m), 13649293Shibler VM_PROT_NONE); 137*56918Shibler vm_page_free(m); 13845748Smckusick pages_freed++; 13945748Smckusick vm_object_unlock(object); 14045748Smckusick } 14145748Smckusick m = next; 142*56918Shibler continue; 14345748Smckusick } 14445748Smckusick 145*56918Shibler /* 146*56918Shibler * If the page is dirty but already being washed, skip it. 147*56918Shibler */ 148*56918Shibler if ((m->flags & PG_LAUNDRY) == 0) { 149*56918Shibler m = (vm_page_t) queue_next(&m->pageq); 150*56918Shibler continue; 151*56918Shibler } 15245748Smckusick 153*56918Shibler /* 154*56918Shibler * Otherwise the page is dirty and still in the laundry, 155*56918Shibler * so we start the cleaning operation and remove it from 156*56918Shibler * the laundry. 157*56918Shibler * 158*56918Shibler * We set the busy bit to cause potential page faults on 159*56918Shibler * this page to block. 160*56918Shibler * 161*56918Shibler * We also set pageout-in-progress to keep the object from 162*56918Shibler * disappearing during pageout. This guarantees that the 163*56918Shibler * page won't move from the inactive queue. (However, any 164*56918Shibler * other page on the inactive queue may move!) 165*56918Shibler */ 166*56918Shibler object = m->object; 167*56918Shibler if (!vm_object_lock_try(object)) { 168*56918Shibler m = (vm_page_t) queue_next(&m->pageq); 169*56918Shibler continue; 170*56918Shibler } 171*56918Shibler pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE); 172*56918Shibler m->flags |= PG_BUSY; 173*56918Shibler cnt.v_pageouts++; 17445748Smckusick 175*56918Shibler /* 176*56918Shibler * Try to collapse the object before making a pager for it. 177*56918Shibler * We must unlock the page queues first. 178*56918Shibler */ 179*56918Shibler vm_page_unlock_queues(); 180*56918Shibler vm_object_collapse(object); 18145748Smckusick 182*56918Shibler object->paging_in_progress++; 183*56918Shibler vm_object_unlock(object); 18445748Smckusick 185*56918Shibler /* 186*56918Shibler * Do a wakeup here in case the following operations block. 187*56918Shibler */ 188*56918Shibler thread_wakeup((int) &cnt.v_free_count); 18945748Smckusick 190*56918Shibler /* 191*56918Shibler * If there is no pager for the page, use the default pager. 192*56918Shibler * If there is no place to put the page at the moment, 193*56918Shibler * leave it in the laundry and hope that there will be 194*56918Shibler * paging space later. 195*56918Shibler */ 196*56918Shibler if ((pager = object->pager) == NULL) { 197*56918Shibler pager = vm_pager_allocate(PG_DFLT, (caddr_t)0, 198*56918Shibler object->size, VM_PROT_ALL); 199*56918Shibler if (pager != NULL) 200*56918Shibler vm_object_setpager(object, pager, 0, FALSE); 201*56918Shibler } 202*56918Shibler pageout_status = pager ? 203*56918Shibler vm_pager_put(pager, m, FALSE) : VM_PAGER_FAIL; 204*56918Shibler vm_object_lock(object); 205*56918Shibler vm_page_lock_queues(); 206*56918Shibler next = (vm_page_t) queue_next(&m->pageq); 20745748Smckusick 208*56918Shibler switch (pageout_status) { 209*56918Shibler case VM_PAGER_OK: 210*56918Shibler case VM_PAGER_PEND: 211*56918Shibler m->flags &= ~PG_LAUNDRY; 212*56918Shibler break; 213*56918Shibler case VM_PAGER_BAD: 214*56918Shibler /* 215*56918Shibler * Page outside of range of object. Right now we 216*56918Shibler * essentially lose the changes by pretending it 217*56918Shibler * worked. 218*56918Shibler * 219*56918Shibler * XXX dubious, what should we do? 220*56918Shibler */ 221*56918Shibler m->flags &= ~PG_LAUNDRY; 222*56918Shibler m->flags |= PG_CLEAN; 223*56918Shibler pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 224*56918Shibler break; 225*56918Shibler case VM_PAGER_FAIL: 226*56918Shibler case VM_PAGER_ERROR: 227*56918Shibler /* 228*56918Shibler * If page couldn't be paged out, then reactivate 229*56918Shibler * the page so it doesn't clog the inactive list. 230*56918Shibler * (We will try paging out it again later). 231*56918Shibler */ 232*56918Shibler vm_page_activate(m); 233*56918Shibler break; 234*56918Shibler } 23545748Smckusick 236*56918Shibler pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 23745748Smckusick 238*56918Shibler /* 239*56918Shibler * If the operation is still going, leave the page busy 240*56918Shibler * to block all other accesses. Also, leave the paging 241*56918Shibler * in progress indicator set so that we don't attempt an 242*56918Shibler * object collapse. 243*56918Shibler */ 244*56918Shibler if (pageout_status != VM_PAGER_PEND) { 245*56918Shibler m->flags &= ~PG_BUSY; 246*56918Shibler PAGE_WAKEUP(m); 247*56918Shibler object->paging_in_progress--; 24845748Smckusick } 249*56918Shibler thread_wakeup((int) object); 250*56918Shibler vm_object_unlock(object); 251*56918Shibler m = next; 25245748Smckusick } 25345748Smckusick 25445748Smckusick /* 25545748Smckusick * Compute the page shortage. If we are still very low on memory 25645748Smckusick * be sure that we will move a minimal amount of pages from active 25745748Smckusick * to inactive. 25845748Smckusick */ 25945748Smckusick 26050922Smckusick page_shortage = cnt.v_inactive_target - cnt.v_inactive_count; 261*56918Shibler if (page_shortage <= 0 && pages_freed == 0) 26245748Smckusick page_shortage = 1; 26345748Smckusick 26445748Smckusick while (page_shortage > 0) { 26545748Smckusick /* 26645748Smckusick * Move some more pages from active to inactive. 26745748Smckusick */ 26845748Smckusick 26945748Smckusick if (queue_empty(&vm_page_queue_active)) { 27045748Smckusick break; 27145748Smckusick } 27245748Smckusick m = (vm_page_t) queue_first(&vm_page_queue_active); 27345748Smckusick vm_page_deactivate(m); 27445748Smckusick page_shortage--; 27545748Smckusick } 27645748Smckusick 27745748Smckusick vm_page_unlock_queues(); 27845748Smckusick } 27945748Smckusick 28045748Smckusick /* 28145748Smckusick * vm_pageout is the high level pageout daemon. 28245748Smckusick */ 28345748Smckusick 28445748Smckusick void vm_pageout() 28545748Smckusick { 28645748Smckusick (void) spl0(); 28745748Smckusick 28845748Smckusick /* 28945748Smckusick * Initialize some paging parameters. 29045748Smckusick */ 29145748Smckusick 29250922Smckusick if (cnt.v_free_min == 0) { 29350922Smckusick cnt.v_free_min = cnt.v_free_count / 20; 29450922Smckusick if (cnt.v_free_min < 3) 29550922Smckusick cnt.v_free_min = 3; 29645748Smckusick 29750922Smckusick if (cnt.v_free_min > vm_page_free_min_sanity) 29850922Smckusick cnt.v_free_min = vm_page_free_min_sanity; 29945748Smckusick } 30045748Smckusick 30150922Smckusick if (cnt.v_free_target == 0) 30250922Smckusick cnt.v_free_target = (cnt.v_free_min * 4) / 3; 30345748Smckusick 30450922Smckusick if (cnt.v_free_target <= cnt.v_free_min) 30550922Smckusick cnt.v_free_target = cnt.v_free_min + 1; 30645748Smckusick 30745748Smckusick /* 30845748Smckusick * The pageout daemon is never done, so loop 30945748Smckusick * forever. 31045748Smckusick */ 31145748Smckusick 31245748Smckusick simple_lock(&vm_pages_needed_lock); 31345748Smckusick while (TRUE) { 31445748Smckusick thread_sleep((int) &vm_pages_needed, &vm_pages_needed_lock, 31545748Smckusick FALSE); 316*56918Shibler /* 317*56918Shibler * Compute the inactive target for this scan. 318*56918Shibler * We need to keep a reasonable amount of memory in the 319*56918Shibler * inactive list to better simulate LRU behavior. 320*56918Shibler */ 321*56918Shibler cnt.v_inactive_target = 322*56918Shibler (cnt.v_active_count + cnt.v_inactive_count) / 3; 323*56918Shibler if (cnt.v_inactive_target <= cnt.v_free_target) 324*56918Shibler cnt.v_inactive_target = cnt.v_free_target + 1; 325*56918Shibler 32645748Smckusick vm_pageout_scan(); 32745748Smckusick vm_pager_sync(); 32845748Smckusick simple_lock(&vm_pages_needed_lock); 32950922Smckusick thread_wakeup((int) &cnt.v_free_count); 33045748Smckusick } 33145748Smckusick } 332