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*61003Shibler * @(#)vm_pageout.c 7.11 (Berkeley) 06/02/93 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 53*61003Shibler int vm_page_max_wired = 0; /* XXX max # of wired pages system-wide */ 54*61003Shibler 5545748Smckusick /* 5645748Smckusick * vm_pageout_scan does the dirty work for the pageout daemon. 5745748Smckusick */ 5853359Sbostic void 5945748Smckusick vm_pageout_scan() 6045748Smckusick { 6145748Smckusick register vm_page_t m; 6245748Smckusick register int page_shortage; 6345748Smckusick register int s; 6445748Smckusick register int pages_freed; 6545748Smckusick int free; 6645748Smckusick 6745748Smckusick /* 6845748Smckusick * Only continue when we want more pages to be "free" 6945748Smckusick */ 7045748Smckusick 7145748Smckusick s = splimp(); 7245748Smckusick simple_lock(&vm_page_queue_free_lock); 7350922Smckusick free = cnt.v_free_count; 7445748Smckusick simple_unlock(&vm_page_queue_free_lock); 7545748Smckusick splx(s); 7645748Smckusick 7750922Smckusick if (free < cnt.v_free_target) { 7845748Smckusick swapout_threads(); 7945748Smckusick 8045748Smckusick /* 8145748Smckusick * Be sure the pmap system is updated so 8245748Smckusick * we can scan the inactive queue. 8345748Smckusick */ 8445748Smckusick 8545748Smckusick pmap_update(); 8645748Smckusick } 8745748Smckusick 8845748Smckusick /* 8945748Smckusick * Acquire the resident page system lock, 9045748Smckusick * as we may be changing what's resident quite a bit. 9145748Smckusick */ 9245748Smckusick vm_page_lock_queues(); 9345748Smckusick 9445748Smckusick /* 9545748Smckusick * Start scanning the inactive queue for pages we can free. 9645748Smckusick * We keep scanning until we have enough free pages or 9745748Smckusick * we have scanned through the entire queue. If we 9845748Smckusick * encounter dirty pages, we start cleaning them. 9945748Smckusick */ 10045748Smckusick 10145748Smckusick pages_freed = 0; 10245748Smckusick m = (vm_page_t) queue_first(&vm_page_queue_inactive); 10345748Smckusick while (!queue_end(&vm_page_queue_inactive, (queue_entry_t) m)) { 10456918Shibler vm_page_t next; 10556918Shibler vm_object_t object; 10656918Shibler vm_pager_t pager; 10756918Shibler int pageout_status; 10845748Smckusick 10945748Smckusick s = splimp(); 11045748Smckusick simple_lock(&vm_page_queue_free_lock); 11150922Smckusick free = cnt.v_free_count; 11245748Smckusick simple_unlock(&vm_page_queue_free_lock); 11345748Smckusick splx(s); 11445748Smckusick 11550922Smckusick if (free >= cnt.v_free_target) 11645748Smckusick break; 11745748Smckusick 11856918Shibler /* 11956918Shibler * If the page has been referenced, move it back to the 12056918Shibler * active queue. 12156918Shibler */ 12256918Shibler if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { 12356918Shibler next = (vm_page_t) queue_next(&m->pageq); 12456918Shibler vm_page_activate(m); 12556918Shibler cnt.v_reactivated++; 12656918Shibler m = next; 12756918Shibler continue; 12856918Shibler } 12956918Shibler 13056918Shibler /* 13156918Shibler * If the page is clean, free it up. 13256918Shibler */ 13356382Smckusick if (m->flags & PG_CLEAN) { 13445748Smckusick next = (vm_page_t) queue_next(&m->pageq); 13556918Shibler object = m->object; 13656918Shibler if (vm_object_lock_try(object)) { 13749293Shibler pmap_page_protect(VM_PAGE_TO_PHYS(m), 13849293Shibler VM_PROT_NONE); 13956918Shibler vm_page_free(m); 14045748Smckusick pages_freed++; 14145748Smckusick vm_object_unlock(object); 14245748Smckusick } 14345748Smckusick m = next; 14456918Shibler continue; 14545748Smckusick } 14645748Smckusick 14756918Shibler /* 14856918Shibler * If the page is dirty but already being washed, skip it. 14956918Shibler */ 15056918Shibler if ((m->flags & PG_LAUNDRY) == 0) { 15156918Shibler m = (vm_page_t) queue_next(&m->pageq); 15256918Shibler continue; 15356918Shibler } 15445748Smckusick 15556918Shibler /* 15656918Shibler * Otherwise the page is dirty and still in the laundry, 15756918Shibler * so we start the cleaning operation and remove it from 15856918Shibler * the laundry. 15956918Shibler * 16056918Shibler * We set the busy bit to cause potential page faults on 16156918Shibler * this page to block. 16256918Shibler * 16356918Shibler * We also set pageout-in-progress to keep the object from 16456918Shibler * disappearing during pageout. This guarantees that the 16556918Shibler * page won't move from the inactive queue. (However, any 16656918Shibler * other page on the inactive queue may move!) 16756918Shibler */ 16856918Shibler object = m->object; 16956918Shibler if (!vm_object_lock_try(object)) { 17056918Shibler m = (vm_page_t) queue_next(&m->pageq); 17156918Shibler continue; 17256918Shibler } 17356918Shibler pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE); 17456918Shibler m->flags |= PG_BUSY; 17556918Shibler cnt.v_pageouts++; 17645748Smckusick 17756918Shibler /* 17856918Shibler * Try to collapse the object before making a pager for it. 17956918Shibler * We must unlock the page queues first. 18056918Shibler */ 18156918Shibler vm_page_unlock_queues(); 18256918Shibler vm_object_collapse(object); 18345748Smckusick 18456918Shibler object->paging_in_progress++; 18556918Shibler vm_object_unlock(object); 18645748Smckusick 18756918Shibler /* 18856918Shibler * Do a wakeup here in case the following operations block. 18956918Shibler */ 19056918Shibler thread_wakeup((int) &cnt.v_free_count); 19145748Smckusick 19256918Shibler /* 19356918Shibler * If there is no pager for the page, use the default pager. 19456918Shibler * If there is no place to put the page at the moment, 19556918Shibler * leave it in the laundry and hope that there will be 19656918Shibler * paging space later. 19756918Shibler */ 19856918Shibler if ((pager = object->pager) == NULL) { 19956918Shibler pager = vm_pager_allocate(PG_DFLT, (caddr_t)0, 20056918Shibler object->size, VM_PROT_ALL); 20156918Shibler if (pager != NULL) 20256918Shibler vm_object_setpager(object, pager, 0, FALSE); 20356918Shibler } 20456918Shibler pageout_status = pager ? 20556918Shibler vm_pager_put(pager, m, FALSE) : VM_PAGER_FAIL; 20656918Shibler vm_object_lock(object); 20756918Shibler vm_page_lock_queues(); 20856918Shibler next = (vm_page_t) queue_next(&m->pageq); 20945748Smckusick 21056918Shibler switch (pageout_status) { 21156918Shibler case VM_PAGER_OK: 21256918Shibler case VM_PAGER_PEND: 21356918Shibler m->flags &= ~PG_LAUNDRY; 21456918Shibler break; 21556918Shibler case VM_PAGER_BAD: 21656918Shibler /* 21756918Shibler * Page outside of range of object. Right now we 21856918Shibler * essentially lose the changes by pretending it 21956918Shibler * worked. 22056918Shibler * 22156918Shibler * XXX dubious, what should we do? 22256918Shibler */ 22356918Shibler m->flags &= ~PG_LAUNDRY; 22456918Shibler m->flags |= PG_CLEAN; 22556918Shibler pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 22656918Shibler break; 22756918Shibler case VM_PAGER_FAIL: 22856918Shibler case VM_PAGER_ERROR: 22956918Shibler /* 23056918Shibler * If page couldn't be paged out, then reactivate 23156918Shibler * the page so it doesn't clog the inactive list. 23256918Shibler * (We will try paging out it again later). 23356918Shibler */ 23456918Shibler vm_page_activate(m); 23556918Shibler break; 23656918Shibler } 23745748Smckusick 23856918Shibler pmap_clear_reference(VM_PAGE_TO_PHYS(m)); 23945748Smckusick 24056918Shibler /* 24156918Shibler * If the operation is still going, leave the page busy 24256918Shibler * to block all other accesses. Also, leave the paging 24356918Shibler * in progress indicator set so that we don't attempt an 24456918Shibler * object collapse. 24556918Shibler */ 24656918Shibler if (pageout_status != VM_PAGER_PEND) { 24756918Shibler m->flags &= ~PG_BUSY; 24856918Shibler PAGE_WAKEUP(m); 24956918Shibler object->paging_in_progress--; 25045748Smckusick } 25156918Shibler thread_wakeup((int) object); 25256918Shibler vm_object_unlock(object); 25356918Shibler m = next; 25445748Smckusick } 25545748Smckusick 25645748Smckusick /* 25745748Smckusick * Compute the page shortage. If we are still very low on memory 25845748Smckusick * be sure that we will move a minimal amount of pages from active 25945748Smckusick * to inactive. 26045748Smckusick */ 26145748Smckusick 26250922Smckusick page_shortage = cnt.v_inactive_target - cnt.v_inactive_count; 26356918Shibler if (page_shortage <= 0 && pages_freed == 0) 26445748Smckusick page_shortage = 1; 26545748Smckusick 26645748Smckusick while (page_shortage > 0) { 26745748Smckusick /* 26845748Smckusick * Move some more pages from active to inactive. 26945748Smckusick */ 27045748Smckusick 27145748Smckusick if (queue_empty(&vm_page_queue_active)) { 27245748Smckusick break; 27345748Smckusick } 27445748Smckusick m = (vm_page_t) queue_first(&vm_page_queue_active); 27545748Smckusick vm_page_deactivate(m); 27645748Smckusick page_shortage--; 27745748Smckusick } 27845748Smckusick 27945748Smckusick vm_page_unlock_queues(); 28045748Smckusick } 28145748Smckusick 28245748Smckusick /* 28345748Smckusick * vm_pageout is the high level pageout daemon. 28445748Smckusick */ 28545748Smckusick 28645748Smckusick void vm_pageout() 28745748Smckusick { 28845748Smckusick (void) spl0(); 28945748Smckusick 29045748Smckusick /* 29145748Smckusick * Initialize some paging parameters. 29245748Smckusick */ 29345748Smckusick 29450922Smckusick if (cnt.v_free_min == 0) { 29550922Smckusick cnt.v_free_min = cnt.v_free_count / 20; 29650922Smckusick if (cnt.v_free_min < 3) 29750922Smckusick cnt.v_free_min = 3; 29845748Smckusick 29950922Smckusick if (cnt.v_free_min > vm_page_free_min_sanity) 30050922Smckusick cnt.v_free_min = vm_page_free_min_sanity; 30145748Smckusick } 30245748Smckusick 30350922Smckusick if (cnt.v_free_target == 0) 30450922Smckusick cnt.v_free_target = (cnt.v_free_min * 4) / 3; 30545748Smckusick 30650922Smckusick if (cnt.v_free_target <= cnt.v_free_min) 30750922Smckusick cnt.v_free_target = cnt.v_free_min + 1; 30845748Smckusick 309*61003Shibler /* XXX does not really belong here */ 310*61003Shibler if (vm_page_max_wired == 0) 311*61003Shibler vm_page_max_wired = cnt.v_free_count / 3; 312*61003Shibler 31345748Smckusick /* 31445748Smckusick * The pageout daemon is never done, so loop 31545748Smckusick * forever. 31645748Smckusick */ 31745748Smckusick 31845748Smckusick simple_lock(&vm_pages_needed_lock); 31945748Smckusick while (TRUE) { 32045748Smckusick thread_sleep((int) &vm_pages_needed, &vm_pages_needed_lock, 32145748Smckusick FALSE); 32256918Shibler /* 32356918Shibler * Compute the inactive target for this scan. 32456918Shibler * We need to keep a reasonable amount of memory in the 32556918Shibler * inactive list to better simulate LRU behavior. 32656918Shibler */ 32756918Shibler cnt.v_inactive_target = 32856918Shibler (cnt.v_active_count + cnt.v_inactive_count) / 3; 32956918Shibler if (cnt.v_inactive_target <= cnt.v_free_target) 33056918Shibler cnt.v_inactive_target = cnt.v_free_target + 1; 33156918Shibler 33245748Smckusick vm_pageout_scan(); 33345748Smckusick vm_pager_sync(); 33445748Smckusick simple_lock(&vm_pages_needed_lock); 33550922Smckusick thread_wakeup((int) &cnt.v_free_count); 33645748Smckusick } 33745748Smckusick } 338