Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1991 Regents of the University of California. | |
3 | * All rights reserved. | |
55768178 DG |
4 | * Copyright (c) 1994 John S. Dyson |
5 | * All rights reserved. | |
6 | * Copyright (c) 1994 David Greenman | |
7 | * All rights reserved. | |
15637ed4 RG |
8 | * |
9 | * This code is derived from software contributed to Berkeley by | |
10 | * The Mach Operating System project at Carnegie-Mellon University. | |
11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * 3. All advertising materials mentioning features or use of this software | |
21 | * must display the following acknowledgement: | |
22 | * This product includes software developed by the University of | |
23 | * California, Berkeley and its contributors. | |
24 | * 4. Neither the name of the University nor the names of its contributors | |
25 | * may be used to endorse or promote products derived from this software | |
26 | * without specific prior written permission. | |
27 | * | |
28 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
29 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
37 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
38 | * SUCH DAMAGE. | |
39 | * | |
55768178 DG |
40 | * @(#)vm_pageout.c 7.4 (Berkeley) 5/7/91 |
41 | * | |
42 | * | |
15637ed4 RG |
43 | * Copyright (c) 1987, 1990 Carnegie-Mellon University. |
44 | * All rights reserved. | |
45 | * | |
46 | * Authors: Avadis Tevanian, Jr., Michael Wayne Young | |
47 | * | |
48 | * Permission to use, copy, modify and distribute this software and | |
49 | * its documentation is hereby granted, provided that both the copyright | |
50 | * notice and this permission notice appear in all copies of the | |
51 | * software, derivative works or modified versions, and any portions | |
52 | * thereof, and that both notices appear in supporting documentation. | |
53 | * | |
54 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
55 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND | |
56 | * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
57 | * | |
58 | * Carnegie Mellon requests users of this software to return to | |
59 | * | |
60 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
61 | * School of Computer Science | |
62 | * Carnegie Mellon University | |
63 | * Pittsburgh PA 15213-3890 | |
64 | * | |
65 | * any improvements or extensions that they make and grant Carnegie the | |
66 | * rights to redistribute these changes. | |
55768178 | 67 | * |
b7ae9810 | 68 | * $Id: vm_pageout.c,v 1.12 1994/01/31 04:21:28 davidg Exp $ |
15637ed4 RG |
69 | */ |
70 | ||
71 | /* | |
72 | * The proverbial page-out daemon. | |
73 | */ | |
74 | ||
75 | #include "param.h" | |
76 | ||
77 | #include "vm.h" | |
78 | #include "vm_page.h" | |
79 | #include "vm_pageout.h" | |
55768178 DG |
80 | #include "malloc.h" |
81 | #include "proc.h" | |
82 | #include "resource.h" | |
83 | #include "resourcevar.h" | |
15637ed4 RG |
84 | #include "vmmeter.h" |
85 | ||
55768178 | 86 | extern vm_map_t kmem_map; |
15637ed4 RG |
87 | int vm_pages_needed; /* Event on which pageout daemon sleeps */ |
88 | int vm_pageout_free_min = 0; /* Stop pageout to wait for pagers at this free level */ | |
89 | ||
55768178 DG |
90 | int vm_pageout_pages_needed = 0; /* flag saying that the pageout daemon needs pages */ |
91 | int vm_page_pagesfreed; | |
92 | ||
93 | extern int npendingio; | |
94 | extern int hz; | |
95 | int vm_pageout_proc_limit; | |
96 | extern int nswiodone; | |
97 | ||
98 | #define MAXREF 32767 | |
a200ca2b DG |
99 | #define DEACT_MAX (DEACT_START * 4) |
100 | #define MINSCAN 512 /* minimum number of pages to scan in active queue */ | |
101 | /* set the "clock" hands to be (MINSCAN * 4096) Bytes */ | |
102 | static int minscan; | |
103 | void vm_pageout_deact_bump(vm_page_t m) ; | |
104 | ||
55768178 DG |
105 | |
106 | /* | |
107 | * vm_pageout_clean: | |
108 | * cleans a vm_page | |
109 | */ | |
110 | int | |
111 | vm_pageout_clean(m, wait) | |
112 | register vm_page_t m; | |
113 | int wait; | |
114 | { | |
115 | /* | |
116 | * Clean the page and remove it from the | |
117 | * laundry. | |
118 | * | |
119 | * We set the busy bit to cause | |
120 | * potential page faults on this page to | |
121 | * block. | |
122 | * | |
123 | * And we set pageout-in-progress to keep | |
124 | * the object from disappearing during | |
125 | * pageout. This guarantees that the | |
126 | * page won't move from the inactive | |
127 | * queue. (However, any other page on | |
128 | * the inactive queue may move!) | |
129 | */ | |
130 | ||
131 | register vm_object_t object; | |
132 | register vm_pager_t pager; | |
133 | int pageout_status; | |
134 | ||
135 | object = m->object; | |
136 | if (!object) { | |
137 | printf("pager: object missing\n"); | |
138 | return 0; | |
139 | } | |
140 | ||
141 | /* | |
142 | * Try to collapse the object before | |
143 | * making a pager for it. We must | |
144 | * unlock the page queues first. | |
145 | * We try to defer the creation of a pager | |
146 | * until all shadows are not paging. This | |
147 | * allows vm_object_collapse to work better and | |
148 | * helps control swap space size. | |
149 | * (J. Dyson 11 Nov 93) | |
150 | */ | |
151 | ||
152 | if (!object->pager && | |
153 | vm_page_free_count < vm_pageout_free_min) | |
154 | return 0; | |
155 | ||
a200ca2b | 156 | collapseagain: |
55768178 DG |
157 | if (!object->pager && |
158 | object->shadow && | |
159 | object->shadow->paging_in_progress) | |
160 | return 0; | |
161 | ||
162 | if (object->shadow) { | |
163 | vm_offset_t offset = m->offset; | |
164 | vm_object_collapse(object); | |
165 | if (!vm_page_lookup(object, offset)) | |
166 | return 0; | |
167 | } | |
168 | ||
169 | waitagain: | |
170 | if (!wait && (m->flags & PG_BUSY)) { | |
171 | return 0; | |
172 | } else if (m->flags & PG_BUSY) { | |
173 | int s = splhigh(); | |
174 | m->flags |= PG_WANTED; | |
175 | tsleep((caddr_t)m, PVM, "clnslp", 0); | |
176 | splx(s); | |
177 | goto waitagain; | |
178 | } | |
179 | ||
180 | m->flags |= PG_BUSY; | |
181 | ||
182 | pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_READ); | |
55768178 DG |
183 | |
184 | vm_stat.pageouts++; | |
185 | ||
186 | object->paging_in_progress++; | |
187 | ||
188 | /* | |
189 | * If there is no pager for the page, | |
190 | * use the default pager. If there's | |
191 | * no place to put the page at the | |
192 | * moment, leave it in the laundry and | |
193 | * hope that there will be paging space | |
194 | * later. | |
195 | */ | |
196 | ||
197 | if ((pager = object->pager) == NULL) { | |
198 | pager = vm_pager_allocate(PG_DFLT, (caddr_t)0, | |
199 | object->size, VM_PROT_ALL, 0); | |
200 | if (pager != NULL) { | |
201 | vm_object_setpager(object, pager, 0, FALSE); | |
202 | } | |
203 | } | |
204 | if ((pager && pager->pg_type == PG_SWAP) || | |
205 | vm_page_free_count >= vm_pageout_free_min) { | |
206 | pageout_status = pager ? | |
207 | vm_pager_put(pager, m, (((object == kernel_object) || wait) ? TRUE: FALSE)) : | |
208 | VM_PAGER_FAIL; | |
209 | } else | |
210 | pageout_status = VM_PAGER_FAIL; | |
211 | ||
212 | switch (pageout_status) { | |
213 | case VM_PAGER_OK: | |
214 | m->flags &= ~PG_LAUNDRY; | |
215 | break; | |
216 | case VM_PAGER_PEND: | |
217 | m->flags &= ~PG_LAUNDRY; | |
218 | break; | |
219 | case VM_PAGER_BAD: | |
220 | /* | |
221 | * Page outside of range of object. | |
222 | * Right now we essentially lose the | |
223 | * changes by pretending it worked. | |
224 | */ | |
225 | m->flags &= ~PG_LAUNDRY; | |
226 | m->flags |= PG_CLEAN; | |
227 | pmap_clear_modify(VM_PAGE_TO_PHYS(m)); | |
228 | break; | |
229 | case VM_PAGER_FAIL: | |
230 | /* | |
231 | * If page couldn't be paged out, then | |
232 | * reactivate the page so it doesn't | |
233 | * clog the inactive list. (We will | |
234 | * try paging out it again later). | |
235 | */ | |
a200ca2b DG |
236 | if ((m->flags & PG_ACTIVE) == 0) |
237 | vm_page_activate(m); | |
55768178 DG |
238 | break; |
239 | case VM_PAGER_TRYAGAIN: | |
240 | break; | |
241 | } | |
242 | ||
243 | ||
244 | /* | |
245 | * If the operation is still going, leave | |
246 | * the page busy to block all other accesses. | |
247 | * Also, leave the paging in progress | |
248 | * indicator set so that we don't attempt an | |
249 | * object collapse. | |
250 | */ | |
251 | if (pageout_status != VM_PAGER_PEND) { | |
a200ca2b DG |
252 | if ((m->flags & PG_ACTIVE) == 0 && |
253 | pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { | |
55768178 DG |
254 | vm_page_activate(m); |
255 | } | |
256 | PAGE_WAKEUP(m); | |
257 | if (--object->paging_in_progress == 0) | |
258 | wakeup((caddr_t) object); | |
259 | } | |
260 | return (pageout_status == VM_PAGER_PEND || | |
261 | pageout_status == VM_PAGER_OK) ? 1 : 0; | |
262 | } | |
263 | ||
a200ca2b DG |
264 | int |
265 | vm_fault_object_deactivate_pages(map, object, dummy) | |
266 | vm_map_t map; | |
267 | vm_object_t object; | |
268 | int dummy; | |
269 | { | |
270 | register vm_page_t p, next; | |
271 | int rcount; | |
272 | int s; | |
273 | int dcount; | |
274 | int count; | |
275 | ||
276 | dcount = 0; | |
277 | /* | |
278 | * deactivate the pages in the objects shadow | |
279 | */ | |
280 | ||
281 | if (object->shadow) | |
282 | dcount += vm_fault_object_deactivate_pages(map, object->shadow, 0); | |
283 | ||
284 | /* | |
285 | * scan the objects memory queue and remove 20% of the active pages | |
286 | */ | |
287 | rcount = object->resident_page_count; | |
288 | count = rcount; | |
289 | if (count == 0) | |
290 | return dcount; | |
291 | #define MINOBJWRITE 10 | |
292 | #define OBJDIVISOR 5 | |
293 | if (count > MINOBJWRITE) { | |
294 | count = MINOBJWRITE + ((count - MINOBJWRITE) / OBJDIVISOR); | |
295 | } | |
296 | p = (vm_page_t) queue_first(&object->memq); | |
297 | while ((rcount-- > 0) && !queue_end(&object->memq, (queue_entry_t) p) ) { | |
298 | next = (vm_page_t) queue_next(&p->listq); | |
299 | vm_page_lock_queues(); | |
300 | /* | |
301 | * if a page is active, not wired and is in the processes pmap, | |
302 | * then deactivate the page. | |
303 | */ | |
304 | if ((p->flags & (PG_ACTIVE|PG_BUSY)) == PG_ACTIVE && | |
305 | p->wire_count == 0 && | |
306 | pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) { | |
307 | if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p))) { | |
308 | vm_page_deactivate(p); | |
309 | if ((p->flags & PG_CLEAN) == 0) { | |
310 | vm_pageout_clean(p, 0); | |
311 | } | |
312 | ++dcount; | |
313 | if (--count <= 0) { | |
314 | vm_page_unlock_queues(); | |
315 | s = splbio(); | |
316 | while (object->paging_in_progress) { | |
317 | tsleep((caddr_t) object,PVM,"vmfobw",0); | |
318 | } | |
319 | splx(s); | |
320 | return dcount; | |
321 | } | |
322 | } else { | |
323 | vm_pageout_deact_bump(p); | |
324 | pmap_clear_reference(VM_PAGE_TO_PHYS(p)); | |
325 | queue_remove(&object->memq, p, vm_page_t, listq); | |
326 | queue_enter(&object->memq, p, vm_page_t, listq); | |
327 | queue_remove(&vm_page_queue_active, p, vm_page_t, pageq); | |
328 | queue_enter(&vm_page_queue_active, p, vm_page_t, pageq); | |
329 | } | |
330 | /* | |
331 | * if a page is inactive and has been modified, clean it now | |
332 | */ | |
333 | } else if ((p->flags & (PG_INACTIVE|PG_BUSY)) == PG_INACTIVE) { | |
334 | if ((p->flags & PG_CLEAN) && | |
335 | pmap_is_modified(VM_PAGE_TO_PHYS(p))) | |
336 | p->flags &= ~PG_CLEAN; | |
337 | ||
338 | if ((p->flags & PG_CLEAN) == 0) | |
339 | vm_pageout_clean(p, 0); | |
340 | } | |
341 | ||
342 | vm_page_unlock_queues(); | |
343 | p = next; | |
344 | } | |
345 | s = splbio(); | |
346 | while (object->paging_in_progress) { | |
347 | tsleep((caddr_t)object,PVM,"vmfobw",0); | |
348 | } | |
349 | splx(s); | |
350 | return dcount; | |
351 | } | |
352 | ||
55768178 DG |
353 | /* |
354 | * vm_pageout_object_deactivate_pages | |
355 | * | |
356 | * deactivate enough pages to satisfy the inactive target | |
357 | * requirements or if vm_page_proc_limit is set, then | |
358 | * deactivate all of the pages in the object and its | |
359 | * shadows. | |
360 | * | |
361 | * The object and map must be locked. | |
362 | */ | |
363 | int | |
364 | vm_pageout_object_deactivate_pages(map, object, count) | |
365 | vm_map_t map; | |
366 | vm_object_t object; | |
367 | int count; | |
368 | { | |
369 | register vm_page_t p, next; | |
370 | int rcount; | |
371 | int s; | |
372 | int dcount; | |
373 | ||
374 | dcount = 0; | |
55768178 DG |
375 | if (count == 0) |
376 | count = 1; | |
377 | ||
a200ca2b | 378 | if (object->shadow) { |
55768178 | 379 | dcount += vm_pageout_object_deactivate_pages(map, object->shadow, count); |
a200ca2b DG |
380 | } |
381 | ||
382 | if (object->paging_in_progress) | |
383 | return dcount; | |
55768178 DG |
384 | |
385 | /* | |
386 | * scan the objects entire memory queue | |
387 | */ | |
388 | rcount = object->resident_page_count; | |
389 | p = (vm_page_t) queue_first(&object->memq); | |
390 | while ((rcount-- > 0) && !queue_end(&object->memq, (queue_entry_t) p) ) { | |
391 | next = (vm_page_t) queue_next(&p->listq); | |
392 | vm_page_lock_queues(); | |
393 | /* | |
394 | * if a page is active, not wired and is in the processes pmap, | |
395 | * then deactivate the page. | |
396 | */ | |
397 | if ((p->flags & (PG_ACTIVE|PG_BUSY)) == PG_ACTIVE && | |
398 | p->wire_count == 0 && | |
55768178 DG |
399 | pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) { |
400 | if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p))) { | |
a200ca2b DG |
401 | if (object->ref_count <= 1) |
402 | vm_page_deactivate(p); | |
403 | else | |
404 | vm_page_pageout_deactivate(p); | |
405 | if (((p->flags & PG_INACTIVE)) && | |
406 | (p->flags & PG_CLEAN) == 0) | |
407 | vm_pageout_clean(p, 0); | |
55768178 DG |
408 | /* |
409 | * see if we are done yet | |
410 | */ | |
411 | if (p->flags & PG_INACTIVE) { | |
55768178 DG |
412 | --count; |
413 | ++dcount; | |
414 | if (count <= 0 && | |
415 | vm_page_inactive_count > vm_page_inactive_target) { | |
416 | vm_page_unlock_queues(); | |
417 | return dcount; | |
418 | } | |
419 | } | |
420 | ||
421 | } else { | |
a200ca2b | 422 | vm_pageout_deact_bump(p); |
55768178 DG |
423 | pmap_clear_reference(VM_PAGE_TO_PHYS(p)); |
424 | queue_remove(&object->memq, p, vm_page_t, listq); | |
425 | queue_enter(&object->memq, p, vm_page_t, listq); | |
426 | queue_remove(&vm_page_queue_active, p, vm_page_t, pageq); | |
427 | queue_enter(&vm_page_queue_active, p, vm_page_t, pageq); | |
428 | } | |
a200ca2b DG |
429 | /* |
430 | * if a page is inactive and has been modified, clean it now | |
431 | */ | |
432 | } else if ((p->flags & (PG_INACTIVE|PG_BUSY)) == PG_INACTIVE) { | |
433 | if ((p->flags & PG_CLEAN) && | |
434 | pmap_is_modified(VM_PAGE_TO_PHYS(p))) | |
435 | p->flags &= ~PG_CLEAN; | |
436 | ||
437 | if ((p->flags & PG_CLEAN) == 0) | |
438 | vm_pageout_clean(p, 0); | |
55768178 | 439 | } |
a200ca2b | 440 | |
55768178 DG |
441 | vm_page_unlock_queues(); |
442 | p = next; | |
443 | } | |
444 | return dcount; | |
445 | } | |
15637ed4 | 446 | |
55768178 DG |
447 | |
448 | /* | |
449 | * deactivate some number of pages in a map, try to do it fairly, but | |
450 | * that is really hard to do. | |
451 | */ | |
452 | ||
453 | void | |
a200ca2b | 454 | vm_pageout_map_deactivate_pages(map, entry, count, freeer) |
55768178 DG |
455 | vm_map_t map; |
456 | vm_map_entry_t entry; | |
457 | int *count; | |
a200ca2b | 458 | int (*freeer)(vm_map_t, vm_object_t, int); |
55768178 DG |
459 | { |
460 | vm_map_t tmpm; | |
461 | vm_map_entry_t tmpe; | |
462 | vm_object_t obj; | |
463 | if (*count <= 0) | |
464 | return; | |
465 | vm_map_reference(map); | |
466 | if (!lock_try_read(&map->lock)) { | |
467 | vm_map_deallocate(map); | |
468 | return; | |
469 | } | |
470 | if (entry == 0) { | |
471 | tmpe = map->header.next; | |
472 | while (tmpe != &map->header && *count > 0) { | |
a200ca2b | 473 | vm_pageout_map_deactivate_pages(map, tmpe, count, freeer); |
55768178 DG |
474 | tmpe = tmpe->next; |
475 | }; | |
476 | } else if (entry->is_sub_map || entry->is_a_map) { | |
477 | tmpm = entry->object.share_map; | |
478 | tmpe = tmpm->header.next; | |
479 | while (tmpe != &tmpm->header && *count > 0) { | |
a200ca2b | 480 | vm_pageout_map_deactivate_pages(tmpm, tmpe, count, freeer); |
55768178 DG |
481 | tmpe = tmpe->next; |
482 | }; | |
483 | } else if (obj = entry->object.vm_object) { | |
a200ca2b | 484 | *count -= (*freeer)(map, obj, *count); |
55768178 DG |
485 | } |
486 | lock_read_done(&map->lock); | |
487 | vm_map_deallocate(map); | |
488 | return; | |
489 | } | |
15637ed4 | 490 | |
a200ca2b DG |
491 | void |
492 | vm_fault_free_pages(p) | |
493 | struct proc *p; | |
494 | { | |
495 | int overage = 1; | |
496 | vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map, | |
497 | (vm_map_entry_t) 0, &overage, vm_fault_object_deactivate_pages); | |
498 | } | |
499 | ||
15637ed4 RG |
500 | /* |
501 | * vm_pageout_scan does the dirty work for the pageout daemon. | |
502 | */ | |
4c45483e | 503 | void |
15637ed4 RG |
504 | vm_pageout_scan() |
505 | { | |
55768178 DG |
506 | vm_page_t m; |
507 | int page_shortage, maxscan, maxlaunder; | |
a200ca2b | 508 | int pages_freed, free, nproc, nbusy; |
55768178 DG |
509 | vm_page_t next; |
510 | struct proc *p; | |
511 | vm_object_t object; | |
512 | int s; | |
513 | ||
15637ed4 | 514 | /* |
55768178 | 515 | * deactivate objects with ref_counts == 0 |
15637ed4 | 516 | */ |
55768178 DG |
517 | object = (vm_object_t) queue_first(&vm_object_list); |
518 | while (!queue_end(&vm_object_list, (queue_entry_t) object)) { | |
519 | if (object->ref_count == 0) | |
520 | vm_object_deactivate_pages(object); | |
521 | object = (vm_object_t) queue_next(&object->object_list); | |
522 | } | |
15637ed4 | 523 | |
55768178 DG |
524 | rerun: |
525 | #if 1 | |
15637ed4 | 526 | /* |
55768178 DG |
527 | * next scan the processes for exceeding their rlimits or if process |
528 | * is swapped out -- deactivate pages | |
15637ed4 | 529 | */ |
55768178 DG |
530 | |
531 | rescanproc1a: | |
532 | for (p = allproc; p != NULL; p = p->p_nxt) | |
533 | p->p_flag &= ~SPAGEDAEMON; | |
534 | ||
535 | rescanproc1: | |
536 | for (p = allproc; p != NULL; p = p->p_nxt) { | |
537 | vm_offset_t size; | |
538 | int overage; | |
539 | vm_offset_t limit; | |
540 | ||
541 | /* | |
542 | * if this is a system process or if we have already | |
543 | * looked at this process, skip it. | |
544 | */ | |
545 | if (p->p_flag & (SSYS|SPAGEDAEMON|SWEXIT)) { | |
546 | continue; | |
547 | } | |
548 | ||
549 | /* | |
550 | * if the process is in a non-running type state, | |
551 | * don't touch it. | |
552 | */ | |
553 | if (p->p_stat != SRUN && p->p_stat != SSLEEP) { | |
554 | continue; | |
555 | } | |
556 | ||
557 | /* | |
558 | * get a limit | |
559 | */ | |
a200ca2b DG |
560 | limit = min(p->p_rlimit[RLIMIT_RSS].rlim_cur, |
561 | p->p_rlimit[RLIMIT_RSS].rlim_max); | |
55768178 DG |
562 | |
563 | /* | |
564 | * let processes that are swapped out really be swapped out | |
565 | * set the limit to nothing (will force a swap-out.) | |
566 | */ | |
567 | if ((p->p_flag & SLOAD) == 0) | |
568 | limit = 0; | |
569 | ||
570 | size = p->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG; | |
571 | if (size >= limit) { | |
572 | overage = (size - limit) / NBPG; | |
573 | vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map, | |
a200ca2b | 574 | (vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages); |
55768178 DG |
575 | p->p_flag |= SPAGEDAEMON; |
576 | goto rescanproc1; | |
577 | } | |
578 | p->p_flag |= SPAGEDAEMON; | |
579 | } | |
a200ca2b DG |
580 | |
581 | #if 0 | |
582 | if (((vm_page_free_count + vm_page_inactive_count) >= | |
583 | (vm_page_inactive_target + vm_page_free_target)) && | |
584 | (vm_page_free_count >= vm_page_free_target)) | |
585 | return; | |
586 | #endif | |
587 | ||
55768178 | 588 | #endif |
15637ed4 | 589 | |
a200ca2b DG |
590 | pages_freed = 0; |
591 | ||
15637ed4 RG |
592 | /* |
593 | * Start scanning the inactive queue for pages we can free. | |
594 | * We keep scanning until we have enough free pages or | |
595 | * we have scanned through the entire queue. If we | |
596 | * encounter dirty pages, we start cleaning them. | |
597 | */ | |
598 | ||
a200ca2b | 599 | maxlaunder = (vm_page_free_target - vm_page_free_count); |
55768178 | 600 | rescan: |
a200ca2b DG |
601 | m = (vm_page_t) queue_first(&vm_page_queue_inactive); |
602 | maxscan = vm_page_inactive_count; | |
55768178 | 603 | while (maxscan-- > 0) { |
15637ed4 RG |
604 | vm_page_t next; |
605 | ||
ce619eaa DG |
606 | |
607 | if (queue_end(&vm_page_queue_inactive, (queue_entry_t) m) | |
608 | || (vm_page_free_count >= vm_page_free_target)) { | |
55768178 DG |
609 | break; |
610 | } | |
15637ed4 | 611 | |
ce619eaa DG |
612 | next = (vm_page_t) queue_next(&m->pageq); |
613 | ||
55768178 DG |
614 | /* |
615 | * dont mess with busy pages | |
616 | */ | |
617 | if (m->flags & PG_BUSY) { | |
618 | queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq); | |
619 | queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq); | |
ce619eaa | 620 | m = next; |
55768178 DG |
621 | continue; |
622 | } | |
15637ed4 | 623 | |
55768178 DG |
624 | /* |
625 | * if page is clean and but the page has been referenced, | |
626 | * then reactivate the page, but if we are very low on memory | |
627 | * or the page has not been referenced, then we free it to the | |
628 | * vm system. | |
629 | */ | |
fd76afd7 | 630 | if (m->flags & PG_CLEAN) { |
55768178 DG |
631 | if ((vm_page_free_count > vm_pageout_free_min) |
632 | && pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { | |
15637ed4 | 633 | vm_page_activate(m); |
55768178 | 634 | ++vm_stat.reactivations; |
ce619eaa | 635 | m = next; |
55768178 | 636 | continue; |
15637ed4 RG |
637 | } |
638 | else { | |
15637ed4 RG |
639 | pmap_page_protect(VM_PAGE_TO_PHYS(m), |
640 | VM_PROT_NONE); | |
55768178 DG |
641 | vm_page_free(m); |
642 | ++pages_freed; | |
ce619eaa | 643 | m = next; |
55768178 | 644 | continue; |
15637ed4 | 645 | } |
55768178 | 646 | } else if ((m->flags & PG_LAUNDRY) && maxlaunder > 0) { |
ce619eaa DG |
647 | /* |
648 | * if a page has been used even if it is in the laundry, | |
649 | * activate it. | |
650 | */ | |
651 | ||
652 | if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { | |
653 | vm_page_activate(m); | |
a200ca2b | 654 | m->flags &= ~PG_LAUNDRY; |
ce619eaa DG |
655 | m = next; |
656 | continue; | |
657 | } | |
658 | ||
15637ed4 RG |
659 | /* |
660 | * If a page is dirty, then it is either | |
661 | * being washed (but not yet cleaned) | |
662 | * or it is still in the laundry. If it is | |
663 | * still in the laundry, then we start the | |
664 | * cleaning operation. | |
665 | */ | |
666 | ||
55768178 DG |
667 | if (vm_pageout_clean(m,0)) { |
668 | --maxlaunder; | |
ce619eaa | 669 | /* |
a200ca2b | 670 | * if the next page has been re-activated, start scanning again |
ce619eaa DG |
671 | */ |
672 | if ((next->flags & PG_INACTIVE) == 0) | |
673 | goto rescan; | |
55768178 | 674 | } |
ce619eaa DG |
675 | } else if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { |
676 | vm_page_activate(m); | |
55768178 | 677 | } |
ce619eaa | 678 | m = next; |
55768178 | 679 | } |
15637ed4 | 680 | |
a200ca2b DG |
681 | /* |
682 | * now check malloc area or swap processes out if we are in low | |
683 | * memory conditions | |
684 | */ | |
685 | free = vm_page_free_count; | |
686 | if (free <= vm_page_free_min) { | |
687 | /* | |
688 | * Be sure the pmap system is updated so | |
689 | * we can scan the inactive queue. | |
690 | */ | |
691 | pmap_update(); | |
692 | ||
693 | /* | |
694 | * swap out inactive processes | |
695 | */ | |
696 | swapout_threads(); | |
697 | ||
698 | #if 0 | |
699 | /* | |
700 | * see if malloc has anything for us | |
701 | */ | |
702 | if (free <= vm_page_free_reserved) | |
703 | malloc_gc(); | |
704 | #endif | |
705 | } | |
706 | ||
707 | skipfree: | |
55768178 DG |
708 | /* |
709 | * If we did not free any pages, but we need to do so, we grow the | |
710 | * inactive target. But as we successfully free pages, then we | |
a200ca2b | 711 | * shrink the inactive target. |
55768178 | 712 | */ |
a200ca2b DG |
713 | if (pages_freed == 0 && vm_page_free_count < vm_page_free_min) { |
714 | vm_page_inactive_target += (vm_page_free_min - vm_page_free_count); | |
715 | if (vm_page_inactive_target > vm_page_free_target*5) | |
716 | vm_page_inactive_target = vm_page_free_target*5; | |
717 | } else if (pages_freed > 0) { | |
718 | vm_page_inactive_target -= vm_page_free_min/2; | |
719 | if (vm_page_inactive_target < vm_page_free_target*2) | |
720 | vm_page_inactive_target = vm_page_free_target*2; | |
55768178 | 721 | } |
15637ed4 | 722 | |
55768178 DG |
723 | /* |
724 | * Compute the page shortage. If we are still very low on memory | |
725 | * be sure that we will move a minimal amount of pages from active | |
726 | * to inactive. | |
727 | */ | |
15637ed4 | 728 | |
55768178 | 729 | restart_inactivate_all: |
15637ed4 | 730 | |
55768178 DG |
731 | page_shortage = vm_page_inactive_target - vm_page_inactive_count; |
732 | page_shortage -= vm_page_free_count; | |
733 | ||
734 | if (page_shortage <= 0) { | |
ce619eaa | 735 | if (pages_freed == 0 && |
55768178 | 736 | ((vm_page_free_count + vm_page_inactive_count) < |
ce619eaa | 737 | (vm_page_free_min + vm_page_inactive_target))) { |
55768178 DG |
738 | page_shortage = 1; |
739 | } else { | |
740 | page_shortage = 0; | |
741 | } | |
742 | } | |
736d20f2 | 743 | |
55768178 | 744 | maxscan = vm_page_active_count; |
45852188 | 745 | |
55768178 DG |
746 | /* |
747 | * deactivate pages that are active, but have not been used | |
748 | * for a while. | |
749 | */ | |
750 | restart_inactivate: | |
751 | m = (vm_page_t) queue_first(&vm_page_queue_active); | |
a200ca2b | 752 | while (maxscan-- > 0) { |
736d20f2 | 753 | |
a200ca2b DG |
754 | if (page_shortage <= 0 && |
755 | maxscan < (vm_page_active_count - minscan) ) | |
756 | break; | |
757 | ||
55768178 DG |
758 | if (queue_end(&vm_page_queue_active, (queue_entry_t) m)) { |
759 | break; | |
760 | } | |
736d20f2 | 761 | |
55768178 | 762 | next = (vm_page_t) queue_next(&m->pageq); |
15637ed4 | 763 | |
55768178 DG |
764 | /* |
765 | * dont mess with pages that are busy | |
766 | */ | |
767 | if (m->flags & PG_BUSY) { | |
768 | m = next; | |
769 | continue; | |
770 | } | |
15637ed4 | 771 | |
55768178 DG |
772 | /* |
773 | * Move some more pages from active to inactive. | |
774 | */ | |
15637ed4 | 775 | |
55768178 DG |
776 | /* |
777 | * see if there are any pages that are able to be deactivated | |
778 | */ | |
ce619eaa DG |
779 | /* |
780 | * the referenced bit is the one that say that the page | |
781 | * has been used. | |
782 | */ | |
783 | if (!pmap_is_referenced(VM_PAGE_TO_PHYS(m))) { | |
55768178 | 784 | /* |
ce619eaa DG |
785 | * if the page has not been referenced, call the |
786 | * vm_page_pageout_deactivate routine. It might | |
787 | * not deactivate the page every time. There is | |
788 | * a policy associated with it. | |
55768178 | 789 | */ |
a200ca2b DG |
790 | if (page_shortage > 0) { |
791 | if (vm_page_pageout_deactivate(m)) { | |
792 | /* | |
793 | * if the page was really deactivated, then | |
794 | * decrement the page_shortage | |
795 | */ | |
796 | if ((m->flags & PG_ACTIVE) == 0) { | |
797 | --page_shortage; | |
798 | } | |
15637ed4 | 799 | } |
15637ed4 | 800 | } |
ce619eaa DG |
801 | } else { |
802 | /* | |
803 | * if the page was recently referenced, set our | |
804 | * deactivate count and clear reference for a future | |
805 | * check for deactivation. | |
806 | */ | |
a200ca2b DG |
807 | vm_pageout_deact_bump(m); |
808 | if (page_shortage > 0 || m->deact >= (DEACT_MAX/2)) | |
809 | pmap_clear_reference(VM_PAGE_TO_PHYS(m)); | |
ce619eaa DG |
810 | queue_remove(&m->object->memq, m, vm_page_t, listq); |
811 | queue_enter(&m->object->memq, m, vm_page_t, listq); | |
812 | queue_remove(&vm_page_queue_active, m, vm_page_t, pageq); | |
813 | queue_enter(&vm_page_queue_active, m, vm_page_t, pageq); | |
814 | } | |
55768178 | 815 | m = next; |
15637ed4 | 816 | } |
15637ed4 | 817 | |
55768178 DG |
818 | vm_page_pagesfreed += pages_freed; |
819 | } | |
15637ed4 | 820 | |
a200ca2b DG |
821 | /* |
822 | * this code maintains a dynamic reference count per page | |
823 | */ | |
824 | void | |
825 | vm_pageout_deact_bump(vm_page_t m) { | |
826 | if( m->deact >= DEACT_START) { | |
827 | m->deact += 1; | |
828 | if( m->deact > DEACT_MAX) | |
829 | m->deact = DEACT_MAX; | |
830 | } else { | |
831 | m->deact += DEACT_START; | |
832 | } | |
833 | } | |
834 | ||
55768178 DG |
835 | /* |
836 | * optionally do a deactivate if the deactivate has been done | |
837 | * enough to justify it. | |
838 | */ | |
839 | int | |
840 | vm_page_pageout_deactivate(m) | |
841 | vm_page_t m; | |
842 | { | |
a200ca2b DG |
843 | |
844 | switch (m->deact) { | |
845 | case DEACT_FREE: | |
15637ed4 | 846 | vm_page_deactivate(m); |
55768178 | 847 | return 1; |
a200ca2b DG |
848 | case DEACT_CLEAN: |
849 | break; | |
850 | case DEACT_DELAY: | |
55768178 | 851 | vm_page_makefault(m); |
a200ca2b DG |
852 | case DEACT_START: |
853 | break; | |
15637ed4 | 854 | } |
a200ca2b DG |
855 | --m->deact; |
856 | return 0; | |
15637ed4 RG |
857 | } |
858 | ||
859 | /* | |
860 | * vm_pageout is the high level pageout daemon. | |
861 | */ | |
862 | ||
55768178 DG |
863 | void |
864 | vm_pageout() | |
15637ed4 | 865 | { |
55768178 | 866 | extern npendingio, swiopend; |
a200ca2b | 867 | extern int vm_page_count; |
15637ed4 RG |
868 | (void) spl0(); |
869 | ||
870 | /* | |
871 | * Initialize some paging parameters. | |
872 | */ | |
873 | ||
55768178 DG |
874 | vmretry: |
875 | vm_page_free_min = npendingio/3; | |
876 | #ifdef VSMALL | |
877 | vm_page_free_min = 8; | |
878 | #endif | |
ce619eaa | 879 | vm_page_free_reserved = 8; |
55768178 DG |
880 | if (vm_page_free_min < 8) |
881 | vm_page_free_min = 8; | |
882 | if (vm_page_free_min > 32) | |
883 | vm_page_free_min = 32; | |
884 | vm_pageout_free_min = 3; | |
885 | vm_page_free_target = 2*vm_page_free_min + vm_page_free_reserved; | |
886 | vm_page_inactive_target = 3*vm_page_free_min + vm_page_free_reserved; | |
887 | vm_page_free_min += vm_page_free_reserved; | |
a200ca2b DG |
888 | minscan = MINSCAN; |
889 | if (minscan > vm_page_count/3) | |
890 | minscan = vm_page_count/3; | |
15637ed4 RG |
891 | |
892 | /* | |
893 | * The pageout daemon is never done, so loop | |
894 | * forever. | |
895 | */ | |
896 | ||
55768178 | 897 | |
15637ed4 | 898 | while (TRUE) { |
55768178 DG |
899 | |
900 | splhigh(); | |
901 | if (vm_page_free_count > vm_page_free_min) { | |
902 | wakeup((caddr_t) &vm_page_free_count); | |
a200ca2b | 903 | tsleep((caddr_t) &vm_pages_needed, PVM, "psleep", 0); |
55768178 DG |
904 | } else { |
905 | if (nswiodone) { | |
906 | spl0(); | |
907 | goto dosync; | |
908 | } | |
a200ca2b | 909 | tsleep((caddr_t) &vm_pages_needed, PVM, "pslp1", 5); |
55768178 | 910 | } |
55768178 DG |
911 | spl0(); |
912 | ||
913 | vm_pager_sync(); | |
15637ed4 | 914 | vm_pageout_scan(); |
55768178 | 915 | dosync: |
15637ed4 | 916 | vm_pager_sync(); |
55768178 DG |
917 | cnt.v_scan++; |
918 | wakeup((caddr_t) kmem_map); | |
15637ed4 RG |
919 | } |
920 | } |