xref: /freebsd/sys/vm/vm_pageout.c (revision df8bae1de4b67ccf57f4afebd4e2bf258c38910d)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1991, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
6df8bae1dSRodney W. Grimes  * The Mach Operating System project at Carnegie-Mellon University.
7df8bae1dSRodney W. Grimes  *
8df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
9df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
10df8bae1dSRodney W. Grimes  * are met:
11df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
12df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
13df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
14df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
15df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
16df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
17df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
18df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
19df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
20df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
21df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
22df8bae1dSRodney W. Grimes  *    without specific prior written permission.
23df8bae1dSRodney W. Grimes  *
24df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
35df8bae1dSRodney W. Grimes  *
36df8bae1dSRodney W. Grimes  *	@(#)vm_pageout.c	8.5 (Berkeley) 2/14/94
37df8bae1dSRodney W. Grimes  *
38df8bae1dSRodney W. Grimes  *
39df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
40df8bae1dSRodney W. Grimes  * All rights reserved.
41df8bae1dSRodney W. Grimes  *
42df8bae1dSRodney W. Grimes  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
43df8bae1dSRodney W. Grimes  *
44df8bae1dSRodney W. Grimes  * Permission to use, copy, modify and distribute this software and
45df8bae1dSRodney W. Grimes  * its documentation is hereby granted, provided that both the copyright
46df8bae1dSRodney W. Grimes  * notice and this permission notice appear in all copies of the
47df8bae1dSRodney W. Grimes  * software, derivative works or modified versions, and any portions
48df8bae1dSRodney W. Grimes  * thereof, and that both notices appear in supporting documentation.
49df8bae1dSRodney W. Grimes  *
50df8bae1dSRodney W. Grimes  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51df8bae1dSRodney W. Grimes  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52df8bae1dSRodney W. Grimes  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53df8bae1dSRodney W. Grimes  *
54df8bae1dSRodney W. Grimes  * Carnegie Mellon requests users of this software to return to
55df8bae1dSRodney W. Grimes  *
56df8bae1dSRodney W. Grimes  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57df8bae1dSRodney W. Grimes  *  School of Computer Science
58df8bae1dSRodney W. Grimes  *  Carnegie Mellon University
59df8bae1dSRodney W. Grimes  *  Pittsburgh PA 15213-3890
60df8bae1dSRodney W. Grimes  *
61df8bae1dSRodney W. Grimes  * any improvements or extensions that they make and grant Carnegie the
62df8bae1dSRodney W. Grimes  * rights to redistribute these changes.
63df8bae1dSRodney W. Grimes  */
64df8bae1dSRodney W. Grimes 
65df8bae1dSRodney W. Grimes /*
66df8bae1dSRodney W. Grimes  *	The proverbial page-out daemon.
67df8bae1dSRodney W. Grimes  */
68df8bae1dSRodney W. Grimes 
69df8bae1dSRodney W. Grimes #include <sys/param.h>
70df8bae1dSRodney W. Grimes 
71df8bae1dSRodney W. Grimes #include <vm/vm.h>
72df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
73df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h>
74df8bae1dSRodney W. Grimes 
75df8bae1dSRodney W. Grimes #ifndef VM_PAGE_FREE_MIN
76df8bae1dSRodney W. Grimes #define VM_PAGE_FREE_MIN	(cnt.v_free_count / 20)
77df8bae1dSRodney W. Grimes #endif
78df8bae1dSRodney W. Grimes 
79df8bae1dSRodney W. Grimes #ifndef VM_PAGE_FREE_TARGET
80df8bae1dSRodney W. Grimes #define VM_PAGE_FREE_TARGET	((cnt.v_free_min * 4) / 3)
81df8bae1dSRodney W. Grimes #endif
82df8bae1dSRodney W. Grimes 
83df8bae1dSRodney W. Grimes int	vm_page_free_min_min = 16 * 1024;
84df8bae1dSRodney W. Grimes int	vm_page_free_min_max = 256 * 1024;
85df8bae1dSRodney W. Grimes 
86df8bae1dSRodney W. Grimes int	vm_pages_needed;	/* Event on which pageout daemon sleeps */
87df8bae1dSRodney W. Grimes 
88df8bae1dSRodney W. Grimes int	vm_page_max_wired = 0;	/* XXX max # of wired pages system-wide */
89df8bae1dSRodney W. Grimes 
90df8bae1dSRodney W. Grimes #ifdef CLUSTERED_PAGEOUT
91df8bae1dSRodney W. Grimes #define MAXPOCLUSTER		(MAXPHYS/NBPG)	/* XXX */
92df8bae1dSRodney W. Grimes int doclustered_pageout = 1;
93df8bae1dSRodney W. Grimes #endif
94df8bae1dSRodney W. Grimes 
95df8bae1dSRodney W. Grimes /*
96df8bae1dSRodney W. Grimes  *	vm_pageout_scan does the dirty work for the pageout daemon.
97df8bae1dSRodney W. Grimes  */
98df8bae1dSRodney W. Grimes void
99df8bae1dSRodney W. Grimes vm_pageout_scan()
100df8bae1dSRodney W. Grimes {
101df8bae1dSRodney W. Grimes 	register vm_page_t	m, next;
102df8bae1dSRodney W. Grimes 	register int		page_shortage;
103df8bae1dSRodney W. Grimes 	register int		s;
104df8bae1dSRodney W. Grimes 	register int		pages_freed;
105df8bae1dSRodney W. Grimes 	int			free;
106df8bae1dSRodney W. Grimes 	vm_object_t		object;
107df8bae1dSRodney W. Grimes 
108df8bae1dSRodney W. Grimes 	/*
109df8bae1dSRodney W. Grimes 	 *	Only continue when we want more pages to be "free"
110df8bae1dSRodney W. Grimes 	 */
111df8bae1dSRodney W. Grimes 
112df8bae1dSRodney W. Grimes 	cnt.v_rev++;
113df8bae1dSRodney W. Grimes 
114df8bae1dSRodney W. Grimes 	s = splimp();
115df8bae1dSRodney W. Grimes 	simple_lock(&vm_page_queue_free_lock);
116df8bae1dSRodney W. Grimes 	free = cnt.v_free_count;
117df8bae1dSRodney W. Grimes 	simple_unlock(&vm_page_queue_free_lock);
118df8bae1dSRodney W. Grimes 	splx(s);
119df8bae1dSRodney W. Grimes 
120df8bae1dSRodney W. Grimes 	if (free < cnt.v_free_target) {
121df8bae1dSRodney W. Grimes 		swapout_threads();
122df8bae1dSRodney W. Grimes 
123df8bae1dSRodney W. Grimes 		/*
124df8bae1dSRodney W. Grimes 		 *	Be sure the pmap system is updated so
125df8bae1dSRodney W. Grimes 		 *	we can scan the inactive queue.
126df8bae1dSRodney W. Grimes 		 */
127df8bae1dSRodney W. Grimes 
128df8bae1dSRodney W. Grimes 		pmap_update();
129df8bae1dSRodney W. Grimes 	}
130df8bae1dSRodney W. Grimes 
131df8bae1dSRodney W. Grimes 	/*
132df8bae1dSRodney W. Grimes 	 *	Acquire the resident page system lock,
133df8bae1dSRodney W. Grimes 	 *	as we may be changing what's resident quite a bit.
134df8bae1dSRodney W. Grimes 	 */
135df8bae1dSRodney W. Grimes 	vm_page_lock_queues();
136df8bae1dSRodney W. Grimes 
137df8bae1dSRodney W. Grimes 	/*
138df8bae1dSRodney W. Grimes 	 *	Start scanning the inactive queue for pages we can free.
139df8bae1dSRodney W. Grimes 	 *	We keep scanning until we have enough free pages or
140df8bae1dSRodney W. Grimes 	 *	we have scanned through the entire queue.  If we
141df8bae1dSRodney W. Grimes 	 *	encounter dirty pages, we start cleaning them.
142df8bae1dSRodney W. Grimes 	 */
143df8bae1dSRodney W. Grimes 
144df8bae1dSRodney W. Grimes 	pages_freed = 0;
145df8bae1dSRodney W. Grimes 	for (m = vm_page_queue_inactive.tqh_first; m != NULL; m = next) {
146df8bae1dSRodney W. Grimes 		s = splimp();
147df8bae1dSRodney W. Grimes 		simple_lock(&vm_page_queue_free_lock);
148df8bae1dSRodney W. Grimes 		free = cnt.v_free_count;
149df8bae1dSRodney W. Grimes 		simple_unlock(&vm_page_queue_free_lock);
150df8bae1dSRodney W. Grimes 		splx(s);
151df8bae1dSRodney W. Grimes 		if (free >= cnt.v_free_target)
152df8bae1dSRodney W. Grimes 			break;
153df8bae1dSRodney W. Grimes 
154df8bae1dSRodney W. Grimes 		cnt.v_scan++;
155df8bae1dSRodney W. Grimes 		next = m->pageq.tqe_next;
156df8bae1dSRodney W. Grimes 
157df8bae1dSRodney W. Grimes 		/*
158df8bae1dSRodney W. Grimes 		 * If the page has been referenced, move it back to the
159df8bae1dSRodney W. Grimes 		 * active queue.
160df8bae1dSRodney W. Grimes 		 */
161df8bae1dSRodney W. Grimes 		if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
162df8bae1dSRodney W. Grimes 			vm_page_activate(m);
163df8bae1dSRodney W. Grimes 			cnt.v_reactivated++;
164df8bae1dSRodney W. Grimes 			continue;
165df8bae1dSRodney W. Grimes 		}
166df8bae1dSRodney W. Grimes 
167df8bae1dSRodney W. Grimes 		/*
168df8bae1dSRodney W. Grimes 		 * If the page is clean, free it up.
169df8bae1dSRodney W. Grimes 		 */
170df8bae1dSRodney W. Grimes 		if (m->flags & PG_CLEAN) {
171df8bae1dSRodney W. Grimes 			object = m->object;
172df8bae1dSRodney W. Grimes 			if (vm_object_lock_try(object)) {
173df8bae1dSRodney W. Grimes 				pmap_page_protect(VM_PAGE_TO_PHYS(m),
174df8bae1dSRodney W. Grimes 						  VM_PROT_NONE);
175df8bae1dSRodney W. Grimes 				vm_page_free(m);
176df8bae1dSRodney W. Grimes 				pages_freed++;
177df8bae1dSRodney W. Grimes 				cnt.v_dfree++;
178df8bae1dSRodney W. Grimes 				vm_object_unlock(object);
179df8bae1dSRodney W. Grimes 			}
180df8bae1dSRodney W. Grimes 			continue;
181df8bae1dSRodney W. Grimes 		}
182df8bae1dSRodney W. Grimes 
183df8bae1dSRodney W. Grimes 		/*
184df8bae1dSRodney W. Grimes 		 * If the page is dirty but already being washed, skip it.
185df8bae1dSRodney W. Grimes 		 */
186df8bae1dSRodney W. Grimes 		if ((m->flags & PG_LAUNDRY) == 0)
187df8bae1dSRodney W. Grimes 			continue;
188df8bae1dSRodney W. Grimes 
189df8bae1dSRodney W. Grimes 		/*
190df8bae1dSRodney W. Grimes 		 * Otherwise the page is dirty and still in the laundry,
191df8bae1dSRodney W. Grimes 		 * so we start the cleaning operation and remove it from
192df8bae1dSRodney W. Grimes 		 * the laundry.
193df8bae1dSRodney W. Grimes 		 */
194df8bae1dSRodney W. Grimes 		object = m->object;
195df8bae1dSRodney W. Grimes 		if (!vm_object_lock_try(object))
196df8bae1dSRodney W. Grimes 			continue;
197df8bae1dSRodney W. Grimes 		cnt.v_pageouts++;
198df8bae1dSRodney W. Grimes #ifdef CLUSTERED_PAGEOUT
199df8bae1dSRodney W. Grimes 		if (object->pager &&
200df8bae1dSRodney W. Grimes 		    vm_pager_cancluster(object->pager, PG_CLUSTERPUT))
201df8bae1dSRodney W. Grimes 			vm_pageout_cluster(m, object);
202df8bae1dSRodney W. Grimes 		else
203df8bae1dSRodney W. Grimes #endif
204df8bae1dSRodney W. Grimes 		vm_pageout_page(m, object);
205df8bae1dSRodney W. Grimes 		thread_wakeup((int) object);
206df8bae1dSRodney W. Grimes 		vm_object_unlock(object);
207df8bae1dSRodney W. Grimes 		/*
208df8bae1dSRodney W. Grimes 		 * Former next page may no longer even be on the inactive
209df8bae1dSRodney W. Grimes 		 * queue (due to potential blocking in the pager with the
210df8bae1dSRodney W. Grimes 		 * queues unlocked).  If it isn't, we just start over.
211df8bae1dSRodney W. Grimes 		 */
212df8bae1dSRodney W. Grimes 		if (next && (next->flags & PG_INACTIVE) == 0)
213df8bae1dSRodney W. Grimes 			next = vm_page_queue_inactive.tqh_first;
214df8bae1dSRodney W. Grimes 	}
215df8bae1dSRodney W. Grimes 
216df8bae1dSRodney W. Grimes 	/*
217df8bae1dSRodney W. Grimes 	 *	Compute the page shortage.  If we are still very low on memory
218df8bae1dSRodney W. Grimes 	 *	be sure that we will move a minimal amount of pages from active
219df8bae1dSRodney W. Grimes 	 *	to inactive.
220df8bae1dSRodney W. Grimes 	 */
221df8bae1dSRodney W. Grimes 
222df8bae1dSRodney W. Grimes 	page_shortage = cnt.v_inactive_target - cnt.v_inactive_count;
223df8bae1dSRodney W. Grimes 	if (page_shortage <= 0 && pages_freed == 0)
224df8bae1dSRodney W. Grimes 		page_shortage = 1;
225df8bae1dSRodney W. Grimes 
226df8bae1dSRodney W. Grimes 	while (page_shortage > 0) {
227df8bae1dSRodney W. Grimes 		/*
228df8bae1dSRodney W. Grimes 		 *	Move some more pages from active to inactive.
229df8bae1dSRodney W. Grimes 		 */
230df8bae1dSRodney W. Grimes 
231df8bae1dSRodney W. Grimes 		if ((m = vm_page_queue_active.tqh_first) == NULL)
232df8bae1dSRodney W. Grimes 			break;
233df8bae1dSRodney W. Grimes 		vm_page_deactivate(m);
234df8bae1dSRodney W. Grimes 		page_shortage--;
235df8bae1dSRodney W. Grimes 	}
236df8bae1dSRodney W. Grimes 
237df8bae1dSRodney W. Grimes 	vm_page_unlock_queues();
238df8bae1dSRodney W. Grimes }
239df8bae1dSRodney W. Grimes 
240df8bae1dSRodney W. Grimes /*
241df8bae1dSRodney W. Grimes  * Called with object and page queues locked.
242df8bae1dSRodney W. Grimes  * If reactivate is TRUE, a pager error causes the page to be
243df8bae1dSRodney W. Grimes  * put back on the active queue, ow it is left on the inactive queue.
244df8bae1dSRodney W. Grimes  */
245df8bae1dSRodney W. Grimes void
246df8bae1dSRodney W. Grimes vm_pageout_page(m, object)
247df8bae1dSRodney W. Grimes 	vm_page_t m;
248df8bae1dSRodney W. Grimes 	vm_object_t object;
249df8bae1dSRodney W. Grimes {
250df8bae1dSRodney W. Grimes 	vm_pager_t pager;
251df8bae1dSRodney W. Grimes 	int pageout_status;
252df8bae1dSRodney W. Grimes 
253df8bae1dSRodney W. Grimes 	/*
254df8bae1dSRodney W. Grimes 	 * We set the busy bit to cause potential page faults on
255df8bae1dSRodney W. Grimes 	 * this page to block.
256df8bae1dSRodney W. Grimes 	 *
257df8bae1dSRodney W. Grimes 	 * We also set pageout-in-progress to keep the object from
258df8bae1dSRodney W. Grimes 	 * disappearing during pageout.  This guarantees that the
259df8bae1dSRodney W. Grimes 	 * page won't move from the inactive queue.  (However, any
260df8bae1dSRodney W. Grimes 	 * other page on the inactive queue may move!)
261df8bae1dSRodney W. Grimes 	 */
262df8bae1dSRodney W. Grimes 	pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE);
263df8bae1dSRodney W. Grimes 	m->flags |= PG_BUSY;
264df8bae1dSRodney W. Grimes 
265df8bae1dSRodney W. Grimes 	/*
266df8bae1dSRodney W. Grimes 	 * Try to collapse the object before making a pager for it.
267df8bae1dSRodney W. Grimes 	 * We must unlock the page queues first.
268df8bae1dSRodney W. Grimes 	 */
269df8bae1dSRodney W. Grimes 	vm_page_unlock_queues();
270df8bae1dSRodney W. Grimes 	if (object->pager == NULL)
271df8bae1dSRodney W. Grimes 		vm_object_collapse(object);
272df8bae1dSRodney W. Grimes 
273df8bae1dSRodney W. Grimes 	object->paging_in_progress++;
274df8bae1dSRodney W. Grimes 	vm_object_unlock(object);
275df8bae1dSRodney W. Grimes 
276df8bae1dSRodney W. Grimes 	/*
277df8bae1dSRodney W. Grimes 	 * Do a wakeup here in case the following operations block.
278df8bae1dSRodney W. Grimes 	 */
279df8bae1dSRodney W. Grimes 	thread_wakeup((int) &cnt.v_free_count);
280df8bae1dSRodney W. Grimes 
281df8bae1dSRodney W. Grimes 	/*
282df8bae1dSRodney W. Grimes 	 * If there is no pager for the page, use the default pager.
283df8bae1dSRodney W. Grimes 	 * If there is no place to put the page at the moment,
284df8bae1dSRodney W. Grimes 	 * leave it in the laundry and hope that there will be
285df8bae1dSRodney W. Grimes 	 * paging space later.
286df8bae1dSRodney W. Grimes 	 */
287df8bae1dSRodney W. Grimes 	if ((pager = object->pager) == NULL) {
288df8bae1dSRodney W. Grimes 		pager = vm_pager_allocate(PG_DFLT, (caddr_t)0, object->size,
289df8bae1dSRodney W. Grimes 					  VM_PROT_ALL, (vm_offset_t)0);
290df8bae1dSRodney W. Grimes 		if (pager != NULL)
291df8bae1dSRodney W. Grimes 			vm_object_setpager(object, pager, 0, FALSE);
292df8bae1dSRodney W. Grimes 	}
293df8bae1dSRodney W. Grimes 	pageout_status = pager ? vm_pager_put(pager, m, FALSE) : VM_PAGER_FAIL;
294df8bae1dSRodney W. Grimes 	vm_object_lock(object);
295df8bae1dSRodney W. Grimes 	vm_page_lock_queues();
296df8bae1dSRodney W. Grimes 
297df8bae1dSRodney W. Grimes 	switch (pageout_status) {
298df8bae1dSRodney W. Grimes 	case VM_PAGER_OK:
299df8bae1dSRodney W. Grimes 	case VM_PAGER_PEND:
300df8bae1dSRodney W. Grimes 		cnt.v_pgpgout++;
301df8bae1dSRodney W. Grimes 		m->flags &= ~PG_LAUNDRY;
302df8bae1dSRodney W. Grimes 		break;
303df8bae1dSRodney W. Grimes 	case VM_PAGER_BAD:
304df8bae1dSRodney W. Grimes 		/*
305df8bae1dSRodney W. Grimes 		 * Page outside of range of object.  Right now we
306df8bae1dSRodney W. Grimes 		 * essentially lose the changes by pretending it
307df8bae1dSRodney W. Grimes 		 * worked.
308df8bae1dSRodney W. Grimes 		 *
309df8bae1dSRodney W. Grimes 		 * XXX dubious, what should we do?
310df8bae1dSRodney W. Grimes 		 */
311df8bae1dSRodney W. Grimes 		m->flags &= ~PG_LAUNDRY;
312df8bae1dSRodney W. Grimes 		m->flags |= PG_CLEAN;
313df8bae1dSRodney W. Grimes 		pmap_clear_modify(VM_PAGE_TO_PHYS(m));
314df8bae1dSRodney W. Grimes 		break;
315df8bae1dSRodney W. Grimes 	case VM_PAGER_AGAIN:
316df8bae1dSRodney W. Grimes 	{
317df8bae1dSRodney W. Grimes 		extern int lbolt;
318df8bae1dSRodney W. Grimes 
319df8bae1dSRodney W. Grimes 		/*
320df8bae1dSRodney W. Grimes 		 * FAIL on a write is interpreted to mean a resource
321df8bae1dSRodney W. Grimes 		 * shortage, so we put pause for awhile and try again.
322df8bae1dSRodney W. Grimes 		 * XXX could get stuck here.
323df8bae1dSRodney W. Grimes 		 */
324df8bae1dSRodney W. Grimes 		(void) tsleep((caddr_t)&lbolt, PZERO|PCATCH, "pageout", 0);
325df8bae1dSRodney W. Grimes 		break;
326df8bae1dSRodney W. Grimes 	}
327df8bae1dSRodney W. Grimes 	case VM_PAGER_FAIL:
328df8bae1dSRodney W. Grimes 	case VM_PAGER_ERROR:
329df8bae1dSRodney W. Grimes 		/*
330df8bae1dSRodney W. Grimes 		 * If page couldn't be paged out, then reactivate
331df8bae1dSRodney W. Grimes 		 * the page so it doesn't clog the inactive list.
332df8bae1dSRodney W. Grimes 		 * (We will try paging out it again later).
333df8bae1dSRodney W. Grimes 		 */
334df8bae1dSRodney W. Grimes 		vm_page_activate(m);
335df8bae1dSRodney W. Grimes 		cnt.v_reactivated++;
336df8bae1dSRodney W. Grimes 		break;
337df8bae1dSRodney W. Grimes 	}
338df8bae1dSRodney W. Grimes 
339df8bae1dSRodney W. Grimes 	pmap_clear_reference(VM_PAGE_TO_PHYS(m));
340df8bae1dSRodney W. Grimes 
341df8bae1dSRodney W. Grimes 	/*
342df8bae1dSRodney W. Grimes 	 * If the operation is still going, leave the page busy
343df8bae1dSRodney W. Grimes 	 * to block all other accesses.  Also, leave the paging
344df8bae1dSRodney W. Grimes 	 * in progress indicator set so that we don't attempt an
345df8bae1dSRodney W. Grimes 	 * object collapse.
346df8bae1dSRodney W. Grimes 	 */
347df8bae1dSRodney W. Grimes 	if (pageout_status != VM_PAGER_PEND) {
348df8bae1dSRodney W. Grimes 		m->flags &= ~PG_BUSY;
349df8bae1dSRodney W. Grimes 		PAGE_WAKEUP(m);
350df8bae1dSRodney W. Grimes 		object->paging_in_progress--;
351df8bae1dSRodney W. Grimes 	}
352df8bae1dSRodney W. Grimes }
353df8bae1dSRodney W. Grimes 
354df8bae1dSRodney W. Grimes #ifdef CLUSTERED_PAGEOUT
355df8bae1dSRodney W. Grimes #define PAGEOUTABLE(p) \
356df8bae1dSRodney W. Grimes 	((((p)->flags & (PG_INACTIVE|PG_CLEAN|PG_LAUNDRY)) == \
357df8bae1dSRodney W. Grimes 	  (PG_INACTIVE|PG_LAUNDRY)) && !pmap_is_referenced(VM_PAGE_TO_PHYS(p)))
358df8bae1dSRodney W. Grimes 
359df8bae1dSRodney W. Grimes /*
360df8bae1dSRodney W. Grimes  * Attempt to pageout as many contiguous (to ``m'') dirty pages as possible
361df8bae1dSRodney W. Grimes  * from ``object''.  Using information returned from the pager, we assemble
362df8bae1dSRodney W. Grimes  * a sorted list of contiguous dirty pages and feed them to the pager in one
363df8bae1dSRodney W. Grimes  * chunk.  Called with paging queues and object locked.  Also, object must
364df8bae1dSRodney W. Grimes  * already have a pager.
365df8bae1dSRodney W. Grimes  */
366df8bae1dSRodney W. Grimes void
367df8bae1dSRodney W. Grimes vm_pageout_cluster(m, object)
368df8bae1dSRodney W. Grimes 	vm_page_t m;
369df8bae1dSRodney W. Grimes 	vm_object_t object;
370df8bae1dSRodney W. Grimes {
371df8bae1dSRodney W. Grimes 	vm_offset_t offset, loff, hoff;
372df8bae1dSRodney W. Grimes 	vm_page_t plist[MAXPOCLUSTER], *plistp, p;
373df8bae1dSRodney W. Grimes 	int postatus, ix, count;
374df8bae1dSRodney W. Grimes 
375df8bae1dSRodney W. Grimes 	/*
376df8bae1dSRodney W. Grimes 	 * Determine the range of pages that can be part of a cluster
377df8bae1dSRodney W. Grimes 	 * for this object/offset.  If it is only our single page, just
378df8bae1dSRodney W. Grimes 	 * do it normally.
379df8bae1dSRodney W. Grimes 	 */
380df8bae1dSRodney W. Grimes 	vm_pager_cluster(object->pager, m->offset, &loff, &hoff);
381df8bae1dSRodney W. Grimes 	if (hoff - loff == PAGE_SIZE) {
382df8bae1dSRodney W. Grimes 		vm_pageout_page(m, object);
383df8bae1dSRodney W. Grimes 		return;
384df8bae1dSRodney W. Grimes 	}
385df8bae1dSRodney W. Grimes 
386df8bae1dSRodney W. Grimes 	plistp = plist;
387df8bae1dSRodney W. Grimes 
388df8bae1dSRodney W. Grimes 	/*
389df8bae1dSRodney W. Grimes 	 * Target page is always part of the cluster.
390df8bae1dSRodney W. Grimes 	 */
391df8bae1dSRodney W. Grimes 	pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE);
392df8bae1dSRodney W. Grimes 	m->flags |= PG_BUSY;
393df8bae1dSRodney W. Grimes 	plistp[atop(m->offset - loff)] = m;
394df8bae1dSRodney W. Grimes 	count = 1;
395df8bae1dSRodney W. Grimes 
396df8bae1dSRodney W. Grimes 	/*
397df8bae1dSRodney W. Grimes 	 * Backup from the given page til we find one not fulfilling
398df8bae1dSRodney W. Grimes 	 * the pageout criteria or we hit the lower bound for the
399df8bae1dSRodney W. Grimes 	 * cluster.  For each page determined to be part of the
400df8bae1dSRodney W. Grimes 	 * cluster, unmap it and busy it out so it won't change.
401df8bae1dSRodney W. Grimes 	 */
402df8bae1dSRodney W. Grimes 	ix = atop(m->offset - loff);
403df8bae1dSRodney W. Grimes 	offset = m->offset;
404df8bae1dSRodney W. Grimes 	while (offset > loff && count < MAXPOCLUSTER-1) {
405df8bae1dSRodney W. Grimes 		p = vm_page_lookup(object, offset - PAGE_SIZE);
406df8bae1dSRodney W. Grimes 		if (p == NULL || !PAGEOUTABLE(p))
407df8bae1dSRodney W. Grimes 			break;
408df8bae1dSRodney W. Grimes 		pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE);
409df8bae1dSRodney W. Grimes 		p->flags |= PG_BUSY;
410df8bae1dSRodney W. Grimes 		plistp[--ix] = p;
411df8bae1dSRodney W. Grimes 		offset -= PAGE_SIZE;
412df8bae1dSRodney W. Grimes 		count++;
413df8bae1dSRodney W. Grimes 	}
414df8bae1dSRodney W. Grimes 	plistp += atop(offset - loff);
415df8bae1dSRodney W. Grimes 	loff = offset;
416df8bae1dSRodney W. Grimes 
417df8bae1dSRodney W. Grimes 	/*
418df8bae1dSRodney W. Grimes 	 * Now do the same moving forward from the target.
419df8bae1dSRodney W. Grimes 	 */
420df8bae1dSRodney W. Grimes 	ix = atop(m->offset - loff) + 1;
421df8bae1dSRodney W. Grimes 	offset = m->offset + PAGE_SIZE;
422df8bae1dSRodney W. Grimes 	while (offset < hoff && count < MAXPOCLUSTER) {
423df8bae1dSRodney W. Grimes 		p = vm_page_lookup(object, offset);
424df8bae1dSRodney W. Grimes 		if (p == NULL || !PAGEOUTABLE(p))
425df8bae1dSRodney W. Grimes 			break;
426df8bae1dSRodney W. Grimes 		pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE);
427df8bae1dSRodney W. Grimes 		p->flags |= PG_BUSY;
428df8bae1dSRodney W. Grimes 		plistp[ix++] = p;
429df8bae1dSRodney W. Grimes 		offset += PAGE_SIZE;
430df8bae1dSRodney W. Grimes 		count++;
431df8bae1dSRodney W. Grimes 	}
432df8bae1dSRodney W. Grimes 	hoff = offset;
433df8bae1dSRodney W. Grimes 
434df8bae1dSRodney W. Grimes 	/*
435df8bae1dSRodney W. Grimes 	 * Pageout the page.
436df8bae1dSRodney W. Grimes 	 * Unlock everything and do a wakeup prior to the pager call
437df8bae1dSRodney W. Grimes 	 * in case it blocks.
438df8bae1dSRodney W. Grimes 	 */
439df8bae1dSRodney W. Grimes 	vm_page_unlock_queues();
440df8bae1dSRodney W. Grimes 	object->paging_in_progress++;
441df8bae1dSRodney W. Grimes 	vm_object_unlock(object);
442df8bae1dSRodney W. Grimes again:
443df8bae1dSRodney W. Grimes 	thread_wakeup((int) &cnt.v_free_count);
444df8bae1dSRodney W. Grimes 	postatus = vm_pager_put_pages(object->pager, plistp, count, FALSE);
445df8bae1dSRodney W. Grimes 	/*
446df8bae1dSRodney W. Grimes 	 * XXX rethink this
447df8bae1dSRodney W. Grimes 	 */
448df8bae1dSRodney W. Grimes 	if (postatus == VM_PAGER_AGAIN) {
449df8bae1dSRodney W. Grimes 		extern int lbolt;
450df8bae1dSRodney W. Grimes 
451df8bae1dSRodney W. Grimes 		(void) tsleep((caddr_t)&lbolt, PZERO|PCATCH, "pageout", 0);
452df8bae1dSRodney W. Grimes 		goto again;
453df8bae1dSRodney W. Grimes 	} else if (postatus == VM_PAGER_BAD)
454df8bae1dSRodney W. Grimes 		panic("vm_pageout_cluster: VM_PAGER_BAD");
455df8bae1dSRodney W. Grimes 	vm_object_lock(object);
456df8bae1dSRodney W. Grimes 	vm_page_lock_queues();
457df8bae1dSRodney W. Grimes 
458df8bae1dSRodney W. Grimes 	/*
459df8bae1dSRodney W. Grimes 	 * Loop through the affected pages, reflecting the outcome of
460df8bae1dSRodney W. Grimes 	 * the operation.
461df8bae1dSRodney W. Grimes 	 */
462df8bae1dSRodney W. Grimes 	for (ix = 0; ix < count; ix++) {
463df8bae1dSRodney W. Grimes 		p = *plistp++;
464df8bae1dSRodney W. Grimes 		switch (postatus) {
465df8bae1dSRodney W. Grimes 		case VM_PAGER_OK:
466df8bae1dSRodney W. Grimes 		case VM_PAGER_PEND:
467df8bae1dSRodney W. Grimes 			cnt.v_pgpgout++;
468df8bae1dSRodney W. Grimes 			p->flags &= ~PG_LAUNDRY;
469df8bae1dSRodney W. Grimes 			break;
470df8bae1dSRodney W. Grimes 		case VM_PAGER_FAIL:
471df8bae1dSRodney W. Grimes 		case VM_PAGER_ERROR:
472df8bae1dSRodney W. Grimes 			/*
473df8bae1dSRodney W. Grimes 			 * Pageout failed, reactivate the target page so it
474df8bae1dSRodney W. Grimes 			 * doesn't clog the inactive list.  Other pages are
475df8bae1dSRodney W. Grimes 			 * left as they are.
476df8bae1dSRodney W. Grimes 			 */
477df8bae1dSRodney W. Grimes 			if (p == m) {
478df8bae1dSRodney W. Grimes 				vm_page_activate(p);
479df8bae1dSRodney W. Grimes 				cnt.v_reactivated++;
480df8bae1dSRodney W. Grimes 			}
481df8bae1dSRodney W. Grimes 			break;
482df8bae1dSRodney W. Grimes 		}
483df8bae1dSRodney W. Grimes 		pmap_clear_reference(VM_PAGE_TO_PHYS(p));
484df8bae1dSRodney W. Grimes 		/*
485df8bae1dSRodney W. Grimes 		 * If the operation is still going, leave the page busy
486df8bae1dSRodney W. Grimes 		 * to block all other accesses.
487df8bae1dSRodney W. Grimes 		 */
488df8bae1dSRodney W. Grimes 		if (postatus != VM_PAGER_PEND) {
489df8bae1dSRodney W. Grimes 			p->flags &= ~PG_BUSY;
490df8bae1dSRodney W. Grimes 			PAGE_WAKEUP(p);
491df8bae1dSRodney W. Grimes 
492df8bae1dSRodney W. Grimes 		}
493df8bae1dSRodney W. Grimes 	}
494df8bae1dSRodney W. Grimes 	/*
495df8bae1dSRodney W. Grimes 	 * If the operation is still going, leave the paging in progress
496df8bae1dSRodney W. Grimes 	 * indicator set so that we don't attempt an object collapse.
497df8bae1dSRodney W. Grimes 	 */
498df8bae1dSRodney W. Grimes 	if (postatus != VM_PAGER_PEND)
499df8bae1dSRodney W. Grimes 		object->paging_in_progress--;
500df8bae1dSRodney W. Grimes 
501df8bae1dSRodney W. Grimes }
502df8bae1dSRodney W. Grimes #endif
503df8bae1dSRodney W. Grimes 
504df8bae1dSRodney W. Grimes /*
505df8bae1dSRodney W. Grimes  *	vm_pageout is the high level pageout daemon.
506df8bae1dSRodney W. Grimes  */
507df8bae1dSRodney W. Grimes 
508df8bae1dSRodney W. Grimes void vm_pageout()
509df8bae1dSRodney W. Grimes {
510df8bae1dSRodney W. Grimes 	(void) spl0();
511df8bae1dSRodney W. Grimes 
512df8bae1dSRodney W. Grimes 	/*
513df8bae1dSRodney W. Grimes 	 *	Initialize some paging parameters.
514df8bae1dSRodney W. Grimes 	 */
515df8bae1dSRodney W. Grimes 
516df8bae1dSRodney W. Grimes 	if (cnt.v_free_min == 0) {
517df8bae1dSRodney W. Grimes 		cnt.v_free_min = VM_PAGE_FREE_MIN;
518df8bae1dSRodney W. Grimes 		vm_page_free_min_min /= cnt.v_page_size;
519df8bae1dSRodney W. Grimes 		vm_page_free_min_max /= cnt.v_page_size;
520df8bae1dSRodney W. Grimes 		if (cnt.v_free_min < vm_page_free_min_min)
521df8bae1dSRodney W. Grimes 			cnt.v_free_min = vm_page_free_min_min;
522df8bae1dSRodney W. Grimes 		if (cnt.v_free_min > vm_page_free_min_max)
523df8bae1dSRodney W. Grimes 			cnt.v_free_min = vm_page_free_min_max;
524df8bae1dSRodney W. Grimes 	}
525df8bae1dSRodney W. Grimes 
526df8bae1dSRodney W. Grimes 	if (cnt.v_free_target == 0)
527df8bae1dSRodney W. Grimes 		cnt.v_free_target = VM_PAGE_FREE_TARGET;
528df8bae1dSRodney W. Grimes 
529df8bae1dSRodney W. Grimes 	if (cnt.v_free_target <= cnt.v_free_min)
530df8bae1dSRodney W. Grimes 		cnt.v_free_target = cnt.v_free_min + 1;
531df8bae1dSRodney W. Grimes 
532df8bae1dSRodney W. Grimes 	/* XXX does not really belong here */
533df8bae1dSRodney W. Grimes 	if (vm_page_max_wired == 0)
534df8bae1dSRodney W. Grimes 		vm_page_max_wired = cnt.v_free_count / 3;
535df8bae1dSRodney W. Grimes 
536df8bae1dSRodney W. Grimes 	/*
537df8bae1dSRodney W. Grimes 	 *	The pageout daemon is never done, so loop
538df8bae1dSRodney W. Grimes 	 *	forever.
539df8bae1dSRodney W. Grimes 	 */
540df8bae1dSRodney W. Grimes 
541df8bae1dSRodney W. Grimes 	simple_lock(&vm_pages_needed_lock);
542df8bae1dSRodney W. Grimes 	while (TRUE) {
543df8bae1dSRodney W. Grimes 		thread_sleep((int) &vm_pages_needed, &vm_pages_needed_lock,
544df8bae1dSRodney W. Grimes 			     FALSE);
545df8bae1dSRodney W. Grimes 		/*
546df8bae1dSRodney W. Grimes 		 * Compute the inactive target for this scan.
547df8bae1dSRodney W. Grimes 		 * We need to keep a reasonable amount of memory in the
548df8bae1dSRodney W. Grimes 		 * inactive list to better simulate LRU behavior.
549df8bae1dSRodney W. Grimes 		 */
550df8bae1dSRodney W. Grimes 		cnt.v_inactive_target =
551df8bae1dSRodney W. Grimes 			(cnt.v_active_count + cnt.v_inactive_count) / 3;
552df8bae1dSRodney W. Grimes 		if (cnt.v_inactive_target <= cnt.v_free_target)
553df8bae1dSRodney W. Grimes 			cnt.v_inactive_target = cnt.v_free_target + 1;
554df8bae1dSRodney W. Grimes 
555df8bae1dSRodney W. Grimes 		/*
556df8bae1dSRodney W. Grimes 		 * Only make a scan if we are likely to do something.
557df8bae1dSRodney W. Grimes 		 * Otherwise we might have been awakened by a pager
558df8bae1dSRodney W. Grimes 		 * to clean up async pageouts.
559df8bae1dSRodney W. Grimes 		 */
560df8bae1dSRodney W. Grimes 		if (cnt.v_free_count < cnt.v_free_target ||
561df8bae1dSRodney W. Grimes 		    cnt.v_inactive_count < cnt.v_inactive_target)
562df8bae1dSRodney W. Grimes 			vm_pageout_scan();
563df8bae1dSRodney W. Grimes 		vm_pager_sync();
564df8bae1dSRodney W. Grimes 		simple_lock(&vm_pages_needed_lock);
565df8bae1dSRodney W. Grimes 		thread_wakeup((int) &cnt.v_free_count);
566df8bae1dSRodney W. Grimes 	}
567df8bae1dSRodney W. Grimes }
568