xref: /csrg-svn/sys/vm/vm_pageout.c (revision 56918)
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