xref: /original-bsd/sys/vm/vm_pageout.c (revision 4d0a8d44)
1 /*
2  * Copyright (c) 1991 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * The Mach Operating System project at Carnegie-Mellon University.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)vm_pageout.c	7.5 (Berkeley) 07/25/91
11  *
12  *
13  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
14  * All rights reserved.
15  *
16  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
17  *
18  * Permission to use, copy, modify and distribute this software and
19  * its documentation is hereby granted, provided that both the copyright
20  * notice and this permission notice appear in all copies of the
21  * software, derivative works or modified versions, and any portions
22  * thereof, and that both notices appear in supporting documentation.
23  *
24  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
25  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
26  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27  *
28  * Carnegie Mellon requests users of this software to return to
29  *
30  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
31  *  School of Computer Science
32  *  Carnegie Mellon University
33  *  Pittsburgh PA 15213-3890
34  *
35  * any improvements or extensions that they make and grant Carnegie the
36  * rights to redistribute these changes.
37  */
38 
39 /*
40  *	The proverbial page-out daemon.
41  */
42 
43 #include "param.h"
44 
45 #include "vm.h"
46 #include "vm_page.h"
47 #include "vm_pageout.h"
48 
49 int	vm_pages_needed;	/* Event on which pageout daemon sleeps */
50 
51 int	vm_page_free_min_sanity = 40;
52 
53 /*
54  *	vm_pageout_scan does the dirty work for the pageout daemon.
55  */
56 vm_pageout_scan()
57 {
58 	register vm_page_t	m;
59 	register int		page_shortage;
60 	register int		s;
61 	register int		pages_freed;
62 	int			free;
63 
64 	/*
65 	 *	Only continue when we want more pages to be "free"
66 	 */
67 
68 	s = splimp();
69 	simple_lock(&vm_page_queue_free_lock);
70 	free = vm_stat.free_count;
71 	simple_unlock(&vm_page_queue_free_lock);
72 	splx(s);
73 
74 	if (free < vm_stat.free_target) {
75 		swapout_threads();
76 
77 		/*
78 		 *	Be sure the pmap system is updated so
79 		 *	we can scan the inactive queue.
80 		 */
81 
82 		pmap_update();
83 	}
84 
85 	/*
86 	 *	Acquire the resident page system lock,
87 	 *	as we may be changing what's resident quite a bit.
88 	 */
89 	vm_page_lock_queues();
90 
91 	/*
92 	 *	Start scanning the inactive queue for pages we can free.
93 	 *	We keep scanning until we have enough free pages or
94 	 *	we have scanned through the entire queue.  If we
95 	 *	encounter dirty pages, we start cleaning them.
96 	 */
97 
98 	pages_freed = 0;
99 	m = (vm_page_t) queue_first(&vm_page_queue_inactive);
100 	while (!queue_end(&vm_page_queue_inactive, (queue_entry_t) m)) {
101 		vm_page_t	next;
102 
103 		s = splimp();
104 		simple_lock(&vm_page_queue_free_lock);
105 		free = vm_stat.free_count;
106 		simple_unlock(&vm_page_queue_free_lock);
107 		splx(s);
108 
109 		if (free >= vm_stat.free_target)
110 			break;
111 
112 		if (m->clean) {
113 			next = (vm_page_t) queue_next(&m->pageq);
114 			if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
115 				vm_page_activate(m);
116 				vm_stat.reactivations++;
117 			}
118 			else {
119 				register vm_object_t	object;
120 				object = m->object;
121 				if (!vm_object_lock_try(object)) {
122 					/*
123 					 *	Can't lock object -
124 					 *	skip page.
125 					 */
126 					m = next;
127 					continue;
128 				}
129 				pmap_page_protect(VM_PAGE_TO_PHYS(m),
130 						  VM_PROT_NONE);
131 				vm_page_free(m);	/* will dequeue */
132 				pages_freed++;
133 				vm_object_unlock(object);
134 			}
135 			m = next;
136 		}
137 		else {
138 			/*
139 			 *	If a page is dirty, then it is either
140 			 *	being washed (but not yet cleaned)
141 			 *	or it is still in the laundry.  If it is
142 			 *	still in the laundry, then we start the
143 			 *	cleaning operation.
144 			 */
145 
146 			if (m->laundry) {
147 				/*
148 				 *	Clean the page and remove it from the
149 				 *	laundry.
150 				 *
151 				 *	We set the busy bit to cause
152 				 *	potential page faults on this page to
153 				 *	block.
154 				 *
155 				 *	And we set pageout-in-progress to keep
156 				 *	the object from disappearing during
157 				 *	pageout.  This guarantees that the
158 				 *	page won't move from the inactive
159 				 *	queue.  (However, any other page on
160 				 *	the inactive queue may move!)
161 				 */
162 
163 				register vm_object_t	object;
164 				register vm_pager_t	pager;
165 				int			pageout_status;
166 
167 				object = m->object;
168 				if (!vm_object_lock_try(object)) {
169 					/*
170 					 *	Skip page if we can't lock
171 					 *	its object
172 					 */
173 					m = (vm_page_t) queue_next(&m->pageq);
174 					continue;
175 				}
176 
177 				pmap_page_protect(VM_PAGE_TO_PHYS(m),
178 						  VM_PROT_NONE);
179 				m->busy = TRUE;
180 				vm_stat.pageouts++;
181 
182 				/*
183 				 *	Try to collapse the object before
184 				 *	making a pager for it.  We must
185 				 *	unlock the page queues first.
186 				 */
187 				vm_page_unlock_queues();
188 
189 				vm_object_collapse(object);
190 
191 				object->paging_in_progress++;
192 				vm_object_unlock(object);
193 
194 				/*
195 				 *	Do a wakeup here in case the following
196 				 *	operations block.
197 				 */
198 				thread_wakeup((int) &vm_stat.free_count);
199 
200 				/*
201 				 *	If there is no pager for the page,
202 				 *	use the default pager.  If there's
203 				 *	no place to put the page at the
204 				 *	moment, leave it in the laundry and
205 				 *	hope that there will be paging space
206 				 *	later.
207 				 */
208 
209 				if ((pager = object->pager) == NULL) {
210 					pager = vm_pager_allocate(PG_DFLT,
211 								  (caddr_t)0,
212 								  object->size,
213 								  VM_PROT_ALL);
214 					if (pager != NULL) {
215 						vm_object_setpager(object,
216 							pager, 0, FALSE);
217 					}
218 				}
219 				pageout_status = pager ?
220 					vm_pager_put(pager, m, FALSE) :
221 					VM_PAGER_FAIL;
222 				vm_object_lock(object);
223 				vm_page_lock_queues();
224 				next = (vm_page_t) queue_next(&m->pageq);
225 
226 				switch (pageout_status) {
227 				case VM_PAGER_OK:
228 				case VM_PAGER_PEND:
229 					m->laundry = FALSE;
230 					break;
231 				case VM_PAGER_BAD:
232 					/*
233 					 * Page outside of range of object.
234 					 * Right now we essentially lose the
235 					 * changes by pretending it worked.
236 					 * XXX dubious, what should we do?
237 					 */
238 					m->laundry = FALSE;
239 					m->clean = TRUE;
240 					pmap_clear_modify(VM_PAGE_TO_PHYS(m));
241 					break;
242 				case VM_PAGER_FAIL:
243 					/*
244 					 * If page couldn't be paged out, then
245 					 * reactivate the page so it doesn't
246 					 * clog the inactive list.  (We will
247 					 * try paging out it again later).
248 					 */
249 					vm_page_activate(m);
250 					break;
251 				}
252 
253 				pmap_clear_reference(VM_PAGE_TO_PHYS(m));
254 
255 				/*
256 				 * If the operation is still going, leave
257 				 * the page busy to block all other accesses.
258 				 * Also, leave the paging in progress
259 				 * indicator set so that we don't attempt an
260 				 * object collapse.
261 				 */
262 				if (pageout_status != VM_PAGER_PEND) {
263 					m->busy = FALSE;
264 					PAGE_WAKEUP(m);
265 					object->paging_in_progress--;
266 				}
267 				thread_wakeup((int) object);
268 				vm_object_unlock(object);
269 				m = next;
270 			}
271 			else
272 				m = (vm_page_t) queue_next(&m->pageq);
273 		}
274 	}
275 
276 	/*
277 	 *	Compute the page shortage.  If we are still very low on memory
278 	 *	be sure that we will move a minimal amount of pages from active
279 	 *	to inactive.
280 	 */
281 
282 	page_shortage = vm_stat.inactive_target - vm_stat.inactive_count;
283 	page_shortage -= vm_stat.free_count;
284 
285 	if ((page_shortage <= 0) && (pages_freed == 0))
286 		page_shortage = 1;
287 
288 	while (page_shortage > 0) {
289 		/*
290 		 *	Move some more pages from active to inactive.
291 		 */
292 
293 		if (queue_empty(&vm_page_queue_active)) {
294 			break;
295 		}
296 		m = (vm_page_t) queue_first(&vm_page_queue_active);
297 		vm_page_deactivate(m);
298 		page_shortage--;
299 	}
300 
301 	vm_page_unlock_queues();
302 }
303 
304 /*
305  *	vm_pageout is the high level pageout daemon.
306  */
307 
308 void vm_pageout()
309 {
310 	(void) spl0();
311 
312 	/*
313 	 *	Initialize some paging parameters.
314 	 */
315 
316 	if (vm_stat.free_min == 0) {
317 		vm_stat.free_min = vm_stat.free_count / 20;
318 		if (vm_stat.free_min < 3)
319 			vm_stat.free_min = 3;
320 
321 		if (vm_stat.free_min > vm_page_free_min_sanity)
322 			vm_stat.free_min = vm_page_free_min_sanity;
323 	}
324 
325 	if (vm_stat.free_target == 0)
326 		vm_stat.free_target = (vm_stat.free_min * 4) / 3;
327 
328 	if (vm_stat.inactive_target == 0)
329 		vm_stat.inactive_target = vm_stat.free_min * 2;
330 
331 	if (vm_stat.free_target <= vm_stat.free_min)
332 		vm_stat.free_target = vm_stat.free_min + 1;
333 
334 	if (vm_stat.inactive_target <= vm_stat.free_target)
335 		vm_stat.inactive_target = vm_stat.free_target + 1;
336 
337 	/*
338 	 *	The pageout daemon is never done, so loop
339 	 *	forever.
340 	 */
341 
342 	simple_lock(&vm_pages_needed_lock);
343 	while (TRUE) {
344 		thread_sleep((int) &vm_pages_needed, &vm_pages_needed_lock,
345 			     FALSE);
346 		vm_pageout_scan();
347 		vm_pager_sync();
348 		simple_lock(&vm_pages_needed_lock);
349 		thread_wakeup((int) &vm_stat.free_count);
350 	}
351 }
352