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