xref: /386bsd/usr/src/kernel/kern/vm/pageout.c (revision dc8b130e)
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  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	$Id: pageout.c,v 1.1 94/10/19 17:37:21 bill Exp $
37  *
38  *
39  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
40  * All rights reserved.
41  *
42  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
43  *
44  * Permission to use, copy, modify and distribute this software and
45  * its documentation is hereby granted, provided that both the copyright
46  * notice and this permission notice appear in all copies of the
47  * software, derivative works or modified versions, and any portions
48  * thereof, and that both notices appear in supporting documentation.
49  *
50  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53  *
54  * Carnegie Mellon requests users of this software to return to
55  *
56  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57  *  School of Computer Science
58  *  Carnegie Mellon University
59  *  Pittsburgh PA 15213-3890
60  *
61  * any improvements or extensions that they make and grant Carnegie the
62  * rights to redistribute these changes.
63  */
64 
65 /* Page replacement mechnism of the virtul memory subsystem. */
66 
67 #include "sys/param.h"
68 #include "proc.h"
69 #include "kernel.h"	/* hz */
70 #include "resourcevar.h"
71 #include "vmmeter.h"
72 #include "vm.h"
73 #include "vm_pageout.h"
74 
75 int vm_pages_needed;		/* event on which pageout daemon sleeps */
76 int vm_page_free_min_sanity = 40;
77 int vm_scan_min, vm_scan_max;	/* thresholds for pageout scan */
78 vm_page_t lastscan;		/* last inactive page scanned */
79 
80 /* make a scan of the page queues to reclaim pages for the free page queue. */
81 static void
vm_pageout_scan(void)82 vm_pageout_scan(void)
83 {
84 	vm_page_t m, next;
85 	int deficit, pending = 0, freed = 0;
86 
87 	/*
88 	 * Inactive pages will be scanned. force inactive page status
89          * (modify,reference) to be valid.
90 	 */
91 	cnt.v_scan++;
92 	pmap_update();
93 
94 	/*
95 	 * Check if the page we were last at is still inactive. If it
96 	 * is, continue from that point, otherwise, start at the last
97 	 * inactive page.
98 	 */
99 	if (lastscan && lastscan->inactive && lastscan->active == 0)
100 		m = lastscan;
101 	else
102 		m = (vm_page_t) queue_first(&vm_page_queue_inactive);
103 	lastscan = 0;
104 
105 	/* scan inactive page queue backwards and reclaim pages */
106 	for (;!queue_end(&vm_page_queue_inactive, (queue_entry_t) m); m = next) {
107 
108 		/* XXX if queue cross threaded, start over */
109 		if (m->active || m->inactive == 0) {
110 			next = (vm_page_t) queue_first(&vm_page_queue_inactive);
111 			continue;
112 		}
113 
114 		/* check following page after */
115 		next = (vm_page_t) queue_next(&m->pageq);
116 
117 		/* pageout in progress, bypass */
118 		if (m->busy)
119 			continue;
120 
121 		/* if page is clean, reactivate if referenced, otherwise free */
122 		if (m->clean && m->laundry == 0)  {
123 			if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
124 				vm_page_activate(m);
125 				cnt.v_pgfrec++;
126 			} else {
127 			freepage:
128 				pmap_page_protect(VM_PAGE_TO_PHYS(m),
129 						  VM_PROT_NONE);
130 				vm_page_free(m);
131 				cnt.v_dfree++;
132 				freed++;
133 			}
134 
135 			/* if queue exhausted, end scan */
136 			if (queue_empty(&vm_page_queue_inactive))
137 				break;
138 
139 			/* if goal reached, end scan, ready to restart */
140 			if (vm_page_free_count + pending > vm_scan_max) {
141 				lastscan = next;
142 				break;
143 			}
144 
145 			/* otherwise, continue scan */
146 			continue;
147 		}
148 
149 		/*
150 		 * If page was dirtied when deactivated, it must be laundered
151 		 * before it can be reused.
152 		 */
153 		if (m->laundry) {
154 			vm_object_t object = m->object;
155 			vm_pager_t pager;
156 			int pageout_status;
157 
158 			/* remove any adr. trans. mappings to page */
159 			pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE);
160 
161 			/* gain exclusive access to page */
162 			m->busy = TRUE;
163 
164 			/* attempt to consolidate object with shadow(s) */
165 			vm_object_collapse(object);
166 
167 			/* anonymous memory needs to allocate pager? */
168 			if ((pager = object->pager) == NULL) {
169 				pager = vm_pager_allocate(PG_DFLT,
170 				    (caddr_t)0, object->size, VM_PROT_ALL);
171 				object->pager = pager;
172 				object->paging_offset = 0;
173 			}
174 
175 			/* if pager, output, else retry later */
176 			if (pager) {
177 				object->paging_in_progress++;
178 				cnt.v_pgout++;
179 				cnt.v_pgpgout++;
180 				pageout_status = vm_pager_put(pager, m, FALSE);
181 			} else
182 				pageout_status = VM_PAGER_FAIL;
183 
184 			switch (pageout_status) {
185 
186 			case VM_PAGER_OK:
187 			case VM_PAGER_PEND:
188 				/* will eventually be clean and reusable */
189 				m->laundry = FALSE;
190 				break;
191 
192 			case VM_PAGER_BAD:
193 				/* free truncated page of object. */
194 				pmap_clear_modify(VM_PAGE_TO_PHYS(m));
195 				object->paging_in_progress--;
196 				goto freepage;
197 
198 			case VM_PAGER_FAIL:
199 				/* postpone pageout retry */
200 				vm_page_activate(m);
201 				break;
202 			}
203 
204 			/* if referenced after being cleaned, will reactivate */
205 			pmap_clear_reference(VM_PAGE_TO_PHYS(m));
206 
207 			/* if pageout not pending, release page */
208 			if (pageout_status != VM_PAGER_PEND) {
209 				m->busy = FALSE;
210 				PAGE_WAKEUP(m);
211 				if (pager)
212 					object->paging_in_progress--;
213 			} else
214 				pending++;
215 
216 			/* alert object of the absence of pageout operations */
217 			if (pager && object->paging_in_progress == 0)
218 				wakeup((caddr_t) object);
219 		}
220 	}
221 
222 	/* have we made a complete pass through the page queue? */
223 	if (queue_end(&vm_page_queue_inactive, (queue_entry_t) m))
224 		cnt.v_rev++;
225 
226 	/* always deactivate at least one active page per scan */
227 	deficit = max(vm_pages_needed - freed, 1);
228 
229 	/* if memory resource still insufficent determine deficit */
230 	if (vm_page_free_count < vm_page_free_min)
231 		deficit = max(vm_page_free_min - vm_page_free_count, deficit);
232 	if (vm_page_free_count + pending < vm_page_free_target)
233 		deficit = max(vm_page_free_target -
234 		    (vm_page_free_count + pending), deficit);
235     	if (vm_page_inactive_count - pending < vm_page_inactive_target)
236 		deficit = max(vm_page_inactive_target -
237 		    (vm_page_inactive_count - pending), deficit);
238 
239 	/* scan active queue deactivating unreferenced pages since last scan */
240 	for (m = (vm_page_t) queue_first(&vm_page_queue_active);
241 	    !queue_end(&vm_page_queue_active, (queue_entry_t) m); m = next) {
242 
243 		/* checking from oldest to youngest */
244 		next = (vm_page_t) queue_next(&m->pageq);
245 
246 		/* if page was not referenced since last scan, deactivate */
247 		if (pmap_is_referenced(VM_PAGE_TO_PHYS(m)) == 0 &&
248 		    deficit-- > 0) {
249 			vm_page_deactivate(m);
250 
251 			if (queue_empty(&vm_page_queue_active))
252 				break;
253 		} else
254 			pmap_clear_reference(VM_PAGE_TO_PHYS(m));
255 	}
256 
257 	/* deactivate active pages unconditionally to remedy deficit */
258 	while (deficit-- > 0)
259 	{
260 		if (queue_empty(&vm_page_queue_active))
261 			break;
262 		m = (vm_page_t) queue_first(&vm_page_queue_active);
263 		vm_page_deactivate(m);
264 	}
265 }
266 
267 /* vm_pageout is the high level pageout daemon. */
268 volatile void
vm_pageout(void)269 vm_pageout(void)
270 {
271 
272 	/* set absolute minimum free pages to avoid deadlock */
273 	if (vm_page_free_min == 0) {
274 		vm_scan_min = vm_page_free_min = vm_page_free_count / 20;
275 		vm_scan_max = vm_scan_min / 2;
276 		if (vm_page_free_min > vm_page_free_min_sanity)
277 			vm_page_free_min = vm_page_free_min_sanity;
278 	}
279 
280 	/* set desired number of free pages */
281 	if (vm_page_free_target == 0)
282 		vm_page_free_target = (vm_page_free_min * 4) / 3;
283 
284 	/* set desired number of inactive pages */
285 	if (vm_page_inactive_target == 0)
286 		vm_page_inactive_target = vm_page_free_min * 2;
287 
288 	if (vm_page_free_target <= vm_page_free_min)
289 		vm_page_free_target = vm_page_free_min + 1;
290 
291 	if (vm_page_inactive_target <= vm_page_free_target)
292 		vm_page_inactive_target = vm_page_free_target + 1;
293 
294 	/* scan for pages to reclaim when awoken */
295 	for (;;) {
296 		int rate;
297 
298 		if (vm_page_free_count <= vm_page_free_target) {
299 
300 		/* reclaim any outstanding pageouts from previous scan */
301 		vm_pager_sync();
302 
303 		/* scan pages */
304 		vm_pageout_scan();
305 
306 		/* immediate reclaim from this scan operation */
307 		vm_pager_sync();
308 
309 		/* broadcast wakeup */
310 		wakeup((caddr_t) &vm_page_free_count);
311 
312 		/* if target not reached, reschedule ourselves */
313 		if (vm_page_free_count < vm_scan_min) {
314 
315 			/* determine rate to run based on linear ramp */
316 			if (vm_page_free_count < vm_scan_max)
317 				rate = max(hz/100, 1);
318 			else
319 				rate = hz * (vm_page_free_count - vm_scan_max)
320 					/ (vm_scan_min - vm_scan_max);
321 		}
322 		else
323 			rate = 0;
324 		} else
325 			rate = 0;
326 
327 		(void) tsleep((caddr_t)&proc0, PVM, "pageout", rate);
328 	}
329 }
330 
331 /*
332  * Gross check for swap space and memory.
333  */
334 extern int swap_empty;
335 
336 int
chk4space(int pages)337 chk4space(int pages) {
338 
339 	if (swap_empty && vm_page_free_count < vm_page_free_target
340 	    && vm_page_inactive_count < vm_page_inactive_target
341 	    && vm_page_free_count + vm_page_inactive_count - pages
342 		- vm_pages_needed < vm_page_free_min)
343 		return (0);
344 	return (1);
345 }
346 
347 /*
348  * Set default limits for VM system.
349  * Called for proc 0, and then inherited by all others.
350  */
351 void
vm_init_limits(struct proc * p)352 vm_init_limits(struct proc *p)
353 {
354 
355 	/*
356 	 * Set up the initial limits on process VM.
357 	 * Set the maximum resident set size to be all
358 	 * of (reasonably) available memory.  This causes
359 	 * any single, large process to start random page
360 	 * replacement once it fills memory.
361 	 */
362         p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
363         p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
364         p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
365         p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
366 	p->p_rlimit[RLIMIT_RSS].rlim_cur = p->p_rlimit[RLIMIT_RSS].rlim_max =
367 		(ptoa(vm_page_free_count) * 80)/100;
368 	p->p_stats->p_ru.ru_maxrss = p->p_rlimit[RLIMIT_RSS].rlim_cur;
369 }
370 
371 /*
372  * Wait for free pages, jabbing the pageout process.
373  */
374 void
vm_page_wait(char * s,int npages)375 vm_page_wait(char *s, int npages) {
376 
377 	vm_pages_needed += npages;
378 	wakeup((caddr_t)&proc0);
379 	(void) tsleep((caddr_t)&vm_page_free_count, PVM, s, 0);
380 	vm_pages_needed -= npages;
381 }
382