xref: /freebsd/sys/vm/vm_pageout.c (revision 2fe6e4d71ea7f0d66df66887364d1a0561b921d3)
1df8bae1dSRodney W. Grimes /*
226f9a767SRodney W. Grimes  * Copyright (c) 1991 Regents of the University of California.
326f9a767SRodney W. Grimes  * All rights reserved.
426f9a767SRodney W. Grimes  * Copyright (c) 1994 John S. Dyson
526f9a767SRodney W. Grimes  * All rights reserved.
626f9a767SRodney W. Grimes  * Copyright (c) 1994 David Greenman
726f9a767SRodney W. Grimes  * All rights reserved.
8df8bae1dSRodney W. Grimes  *
9df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
10df8bae1dSRodney W. Grimes  * The Mach Operating System project at Carnegie-Mellon University.
11df8bae1dSRodney W. Grimes  *
12df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
13df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
14df8bae1dSRodney W. Grimes  * are met:
15df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
16df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
17df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
18df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
19df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
20df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
21df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
22df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
23df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
24df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
25df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
26df8bae1dSRodney W. Grimes  *    without specific prior written permission.
27df8bae1dSRodney W. Grimes  *
28df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
39df8bae1dSRodney W. Grimes  *
403c4dd356SDavid Greenman  *	from: @(#)vm_pageout.c	7.4 (Berkeley) 5/7/91
41df8bae1dSRodney W. Grimes  *
42df8bae1dSRodney W. Grimes  *
43df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
44df8bae1dSRodney W. Grimes  * All rights reserved.
45df8bae1dSRodney W. Grimes  *
46df8bae1dSRodney W. Grimes  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
47df8bae1dSRodney W. Grimes  *
48df8bae1dSRodney W. Grimes  * Permission to use, copy, modify and distribute this software and
49df8bae1dSRodney W. Grimes  * its documentation is hereby granted, provided that both the copyright
50df8bae1dSRodney W. Grimes  * notice and this permission notice appear in all copies of the
51df8bae1dSRodney W. Grimes  * software, derivative works or modified versions, and any portions
52df8bae1dSRodney W. Grimes  * thereof, and that both notices appear in supporting documentation.
53df8bae1dSRodney W. Grimes  *
54df8bae1dSRodney W. Grimes  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
55df8bae1dSRodney W. Grimes  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
56df8bae1dSRodney W. Grimes  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
57df8bae1dSRodney W. Grimes  *
58df8bae1dSRodney W. Grimes  * Carnegie Mellon requests users of this software to return to
59df8bae1dSRodney W. Grimes  *
60df8bae1dSRodney W. Grimes  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
61df8bae1dSRodney W. Grimes  *  School of Computer Science
62df8bae1dSRodney W. Grimes  *  Carnegie Mellon University
63df8bae1dSRodney W. Grimes  *  Pittsburgh PA 15213-3890
64df8bae1dSRodney W. Grimes  *
65df8bae1dSRodney W. Grimes  * any improvements or extensions that they make and grant Carnegie the
66df8bae1dSRodney W. Grimes  * rights to redistribute these changes.
6726f9a767SRodney W. Grimes  *
682fe6e4d7SDavid Greenman  * $Id: vm_pageout.c,v 1.23 1994/10/25 05:35:44 davidg Exp $
69df8bae1dSRodney W. Grimes  */
70df8bae1dSRodney W. Grimes 
71df8bae1dSRodney W. Grimes /*
72df8bae1dSRodney W. Grimes  *	The proverbial page-out daemon.
73df8bae1dSRodney W. Grimes  */
74df8bae1dSRodney W. Grimes 
75df8bae1dSRodney W. Grimes #include <sys/param.h>
7626f9a767SRodney W. Grimes #include <sys/systm.h>
7726f9a767SRodney W. Grimes #include <sys/proc.h>
7826f9a767SRodney W. Grimes #include <sys/resourcevar.h>
7926f9a767SRodney W. Grimes #include <sys/malloc.h>
80df8bae1dSRodney W. Grimes 
81df8bae1dSRodney W. Grimes #include <vm/vm.h>
82df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
83df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h>
8405f0fdd2SPoul-Henning Kamp #include <vm/swap_pager.h>
85df8bae1dSRodney W. Grimes 
8626f9a767SRodney W. Grimes extern vm_map_t kmem_map;
87df8bae1dSRodney W. Grimes int	vm_pages_needed;		/* Event on which pageout daemon sleeps */
8826f9a767SRodney W. Grimes int	vm_pagescanner;			/* Event on which pagescanner sleeps */
8926f9a767SRodney W. Grimes int	vm_pageout_free_min = 0;	/* Stop pageout to wait for pagers at this free level */
9026f9a767SRodney W. Grimes 
9126f9a767SRodney W. Grimes int	vm_pageout_pages_needed = 0;	/* flag saying that the pageout daemon needs pages */
9226f9a767SRodney W. Grimes int	vm_page_pagesfreed;
93a647a309SDavid Greenman int	vm_desired_cache_size;
9426f9a767SRodney W. Grimes 
9526f9a767SRodney W. Grimes extern int npendingio;
9626f9a767SRodney W. Grimes extern int hz;
9726f9a767SRodney W. Grimes int	vm_pageout_proc_limit;
982fe6e4d7SDavid Greenman int	vm_pageout_req_swapout;
992fe6e4d7SDavid Greenman int vm_daemon_needed;
10026f9a767SRodney W. Grimes extern int nswiodone;
10126f9a767SRodney W. Grimes extern int swap_pager_full;
1025663e6deSDavid Greenman extern int vm_swap_size;
10326f9a767SRodney W. Grimes extern int swap_pager_ready();
10426f9a767SRodney W. Grimes 
10526f9a767SRodney W. Grimes #define MAXREF 32767
10626f9a767SRodney W. Grimes 
10726f9a767SRodney W. Grimes #define MAXSCAN 512	/* maximum number of pages to scan in active queue */
10826f9a767SRodney W. Grimes 			/* set the "clock" hands to be (MAXSCAN * 4096) Bytes */
10926f9a767SRodney W. Grimes #define ACT_DECLINE	1
11003e6c253SDavid Greenman #define ACT_ADVANCE	3
111a6ca859eSDavid Greenman #define ACT_MAX		100
11226f9a767SRodney W. Grimes 
11326f9a767SRodney W. Grimes #define LOWATER ((2048*1024)/NBPG)
11426f9a767SRodney W. Grimes 
11526f9a767SRodney W. Grimes #define VM_PAGEOUT_PAGE_COUNT 8
116bbc0ec52SDavid Greenman int vm_pageout_page_count = VM_PAGEOUT_PAGE_COUNT;
11726f9a767SRodney W. Grimes int vm_pageout_req_do_stats;
118df8bae1dSRodney W. Grimes 
119df8bae1dSRodney W. Grimes int	vm_page_max_wired = 0;	/* XXX max # of wired pages system-wide */
120df8bae1dSRodney W. Grimes 
12126f9a767SRodney W. Grimes 
12226f9a767SRodney W. Grimes /*
12326f9a767SRodney W. Grimes  * vm_pageout_clean:
12426f9a767SRodney W. Grimes  * 	cleans a vm_page
12526f9a767SRodney W. Grimes  */
12626f9a767SRodney W. Grimes int
12726f9a767SRodney W. Grimes vm_pageout_clean(m, sync)
12826f9a767SRodney W. Grimes 	register vm_page_t m;
12926f9a767SRodney W. Grimes 	int sync;
13026f9a767SRodney W. Grimes {
13126f9a767SRodney W. Grimes 	/*
13226f9a767SRodney W. Grimes 	 *	Clean the page and remove it from the
13326f9a767SRodney W. Grimes 	 *	laundry.
13426f9a767SRodney W. Grimes 	 *
13526f9a767SRodney W. Grimes 	 *	We set the busy bit to cause
13626f9a767SRodney W. Grimes 	 *	potential page faults on this page to
13726f9a767SRodney W. Grimes 	 *	block.
13826f9a767SRodney W. Grimes 	 *
13926f9a767SRodney W. Grimes 	 *	And we set pageout-in-progress to keep
14026f9a767SRodney W. Grimes 	 *	the object from disappearing during
14126f9a767SRodney W. Grimes 	 *	pageout.  This guarantees that the
14226f9a767SRodney W. Grimes 	 *	page won't move from the inactive
14326f9a767SRodney W. Grimes 	 *	queue.  (However, any other page on
14426f9a767SRodney W. Grimes 	 *	the inactive queue may move!)
14526f9a767SRodney W. Grimes 	 */
14626f9a767SRodney W. Grimes 
14726f9a767SRodney W. Grimes 	register vm_object_t	object;
14826f9a767SRodney W. Grimes 	register vm_pager_t	pager;
14926f9a767SRodney W. Grimes 	int			pageout_status[VM_PAGEOUT_PAGE_COUNT];
15026f9a767SRodney W. Grimes 	vm_page_t		ms[VM_PAGEOUT_PAGE_COUNT];
15126f9a767SRodney W. Grimes 	int			pageout_count;
15226f9a767SRodney W. Grimes 	int			anyok=0;
15326f9a767SRodney W. Grimes 	int			i;
15426f9a767SRodney W. Grimes 	vm_offset_t offset = m->offset;
15526f9a767SRodney W. Grimes 
15626f9a767SRodney W. Grimes 	object = m->object;
15726f9a767SRodney W. Grimes 	if (!object) {
15826f9a767SRodney W. Grimes 		printf("pager: object missing\n");
15926f9a767SRodney W. Grimes 		return 0;
16026f9a767SRodney W. Grimes 	}
16126f9a767SRodney W. Grimes 
16226f9a767SRodney W. Grimes 	/*
16326f9a767SRodney W. Grimes 	 *	Try to collapse the object before
16426f9a767SRodney W. Grimes 	 *	making a pager for it.  We must
16526f9a767SRodney W. Grimes 	 *	unlock the page queues first.
16626f9a767SRodney W. Grimes 	 *	We try to defer the creation of a pager
16726f9a767SRodney W. Grimes 	 *	until all shadows are not paging.  This
16826f9a767SRodney W. Grimes 	 *	allows vm_object_collapse to work better and
16926f9a767SRodney W. Grimes 	 *	helps control swap space size.
17026f9a767SRodney W. Grimes 	 *	(J. Dyson 11 Nov 93)
17126f9a767SRodney W. Grimes 	 */
17226f9a767SRodney W. Grimes 
17326f9a767SRodney W. Grimes 	if (!object->pager &&
17426f9a767SRodney W. Grimes 		cnt.v_free_count < vm_pageout_free_min)
17526f9a767SRodney W. Grimes 		return 0;
17626f9a767SRodney W. Grimes 
17726f9a767SRodney W. Grimes 	if( !sync) {
17826f9a767SRodney W. Grimes 		if (object->shadow) {
17926f9a767SRodney W. Grimes 			vm_object_collapse(object);
18026f9a767SRodney W. Grimes 		}
18126f9a767SRodney W. Grimes 
182a647a309SDavid Greenman 		if ((m->busy != 0) ||
183a647a309SDavid Greenman 			(m->flags & PG_BUSY) || (m->hold_count != 0)) {
18426f9a767SRodney W. Grimes 			return 0;
18526f9a767SRodney W. Grimes 		}
18626f9a767SRodney W. Grimes 	}
18726f9a767SRodney W. Grimes 
18826f9a767SRodney W. Grimes 	pageout_count = 1;
18926f9a767SRodney W. Grimes 	ms[0] = m;
19026f9a767SRodney W. Grimes 
1914e39a515SPoul-Henning Kamp 	pager = object->pager;
1924e39a515SPoul-Henning Kamp 	if (pager) {
193bbc0ec52SDavid Greenman 		for (i = 1; i < vm_pageout_page_count; i++) {
1944e39a515SPoul-Henning Kamp 			ms[i] = vm_page_lookup(object, offset+i*NBPG);
1954e39a515SPoul-Henning Kamp 			if (ms[i]) {
1962fe6e4d7SDavid Greenman 				if (((ms[i]->flags & PG_CLEAN) != 0) &&
1972fe6e4d7SDavid Greenman 				    pmap_is_modified(VM_PAGE_TO_PHYS(ms[i]))) {
1982fe6e4d7SDavid Greenman 					ms[i]->flags &= ~PG_CLEAN;
1992fe6e4d7SDavid Greenman 				}
20026f9a767SRodney W. Grimes 				if (( ((ms[i]->flags & (PG_CLEAN|PG_INACTIVE|PG_BUSY)) == PG_INACTIVE)
2015cedf680SDavid Greenman 					|| ( (ms[i]->flags & (PG_CLEAN|PG_BUSY)) == 0 && sync == VM_PAGEOUT_FORCE))
20226f9a767SRodney W. Grimes 					&& (ms[i]->wire_count == 0)
203a647a309SDavid Greenman 					&& (ms[i]->busy == 0)
20426f9a767SRodney W. Grimes 					&& (ms[i]->hold_count == 0))
20526f9a767SRodney W. Grimes 					pageout_count++;
20626f9a767SRodney W. Grimes 				else
20726f9a767SRodney W. Grimes 					break;
20826f9a767SRodney W. Grimes 			} else
20926f9a767SRodney W. Grimes 				break;
21026f9a767SRodney W. Grimes 		}
21126f9a767SRodney W. Grimes 		for(i=0;i<pageout_count;i++) {
21226f9a767SRodney W. Grimes 			ms[i]->flags |= PG_BUSY;
21326f9a767SRodney W. Grimes 			pmap_page_protect(VM_PAGE_TO_PHYS(ms[i]), VM_PROT_READ);
21426f9a767SRodney W. Grimes 		}
21526f9a767SRodney W. Grimes 		object->paging_in_progress += pageout_count;
21626f9a767SRodney W. Grimes 	} else {
21726f9a767SRodney W. Grimes 
21826f9a767SRodney W. Grimes 		m->flags |= PG_BUSY;
21926f9a767SRodney W. Grimes 
22026f9a767SRodney W. Grimes 		pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_READ);
22126f9a767SRodney W. Grimes 
22226f9a767SRodney W. Grimes 		object->paging_in_progress++;
22326f9a767SRodney W. Grimes 
22426f9a767SRodney W. Grimes 		pager = vm_pager_allocate(PG_DFLT, (caddr_t)0,
22526f9a767SRodney W. Grimes 			object->size, VM_PROT_ALL, 0);
22626f9a767SRodney W. Grimes 		if (pager != NULL) {
22726f9a767SRodney W. Grimes 			vm_object_setpager(object, pager, 0, FALSE);
22826f9a767SRodney W. Grimes 		}
22926f9a767SRodney W. Grimes 	}
23026f9a767SRodney W. Grimes 
23126f9a767SRodney W. Grimes 	/*
23226f9a767SRodney W. Grimes 	 *	If there is no pager for the page,
23326f9a767SRodney W. Grimes 	 *	use the default pager.  If there's
23426f9a767SRodney W. Grimes 	 *	no place to put the page at the
23526f9a767SRodney W. Grimes 	 *	moment, leave it in the laundry and
23626f9a767SRodney W. Grimes 	 *	hope that there will be paging space
23726f9a767SRodney W. Grimes 	 *	later.
23826f9a767SRodney W. Grimes 	 */
23926f9a767SRodney W. Grimes 
24026f9a767SRodney W. Grimes 	if ((pager && pager->pg_type == PG_SWAP) ||
24126f9a767SRodney W. Grimes 		cnt.v_free_count >= vm_pageout_free_min) {
24226f9a767SRodney W. Grimes 		if( pageout_count == 1) {
24326f9a767SRodney W. Grimes 			pageout_status[0] = pager ?
24426f9a767SRodney W. Grimes 				vm_pager_put(pager, m,
24526f9a767SRodney W. Grimes 				    ((sync || (object == kernel_object)) ? TRUE: FALSE)) :
24626f9a767SRodney W. Grimes 				VM_PAGER_FAIL;
24726f9a767SRodney W. Grimes 		} else {
24826f9a767SRodney W. Grimes 			if( !pager) {
24926f9a767SRodney W. Grimes 				for(i=0;i<pageout_count;i++)
25026f9a767SRodney W. Grimes 					pageout_status[i] = VM_PAGER_FAIL;
25126f9a767SRodney W. Grimes 			} else {
25226f9a767SRodney W. Grimes 				vm_pager_put_pages(pager, ms, pageout_count,
25326f9a767SRodney W. Grimes 				    ((sync || (object == kernel_object)) ? TRUE : FALSE),
25426f9a767SRodney W. Grimes 				    pageout_status);
25526f9a767SRodney W. Grimes 			}
25626f9a767SRodney W. Grimes 		}
25726f9a767SRodney W. Grimes 
25826f9a767SRodney W. Grimes 	} else {
25926f9a767SRodney W. Grimes 		for(i=0;i<pageout_count;i++)
26026f9a767SRodney W. Grimes 			pageout_status[i] = VM_PAGER_FAIL;
26126f9a767SRodney W. Grimes 	}
26226f9a767SRodney W. Grimes 
26326f9a767SRodney W. Grimes 	for(i=0;i<pageout_count;i++) {
26426f9a767SRodney W. Grimes 		switch (pageout_status[i]) {
26526f9a767SRodney W. Grimes 		case VM_PAGER_OK:
26626f9a767SRodney W. Grimes 			ms[i]->flags &= ~PG_LAUNDRY;
26726f9a767SRodney W. Grimes 			++anyok;
26826f9a767SRodney W. Grimes 			break;
26926f9a767SRodney W. Grimes 		case VM_PAGER_PEND:
27026f9a767SRodney W. Grimes 			ms[i]->flags &= ~PG_LAUNDRY;
27126f9a767SRodney W. Grimes 			++anyok;
27226f9a767SRodney W. Grimes 			break;
27326f9a767SRodney W. Grimes 		case VM_PAGER_BAD:
27426f9a767SRodney W. Grimes 			/*
27526f9a767SRodney W. Grimes 			 * Page outside of range of object.
27626f9a767SRodney W. Grimes 			 * Right now we essentially lose the
27726f9a767SRodney W. Grimes 			 * changes by pretending it worked.
27826f9a767SRodney W. Grimes 			 */
27926f9a767SRodney W. Grimes 			ms[i]->flags &= ~PG_LAUNDRY;
28026f9a767SRodney W. Grimes 			ms[i]->flags |= PG_CLEAN;
28126f9a767SRodney W. Grimes 			pmap_clear_modify(VM_PAGE_TO_PHYS(ms[i]));
28226f9a767SRodney W. Grimes 			break;
28326f9a767SRodney W. Grimes 		case VM_PAGER_ERROR:
28426f9a767SRodney W. Grimes 		case VM_PAGER_FAIL:
28526f9a767SRodney W. Grimes 			/*
28626f9a767SRodney W. Grimes 			 * If page couldn't be paged out, then
28726f9a767SRodney W. Grimes 			 * reactivate the page so it doesn't
28826f9a767SRodney W. Grimes 			 * clog the inactive list.  (We will
28926f9a767SRodney W. Grimes 			 * try paging out it again later).
29026f9a767SRodney W. Grimes 			 */
29126f9a767SRodney W. Grimes 			if (ms[i]->flags & PG_INACTIVE)
29226f9a767SRodney W. Grimes 				vm_page_activate(ms[i]);
29326f9a767SRodney W. Grimes 			break;
29426f9a767SRodney W. Grimes 		case VM_PAGER_AGAIN:
29526f9a767SRodney W. Grimes 			break;
29626f9a767SRodney W. Grimes 		}
29726f9a767SRodney W. Grimes 
29826f9a767SRodney W. Grimes 
29926f9a767SRodney W. Grimes 		/*
30026f9a767SRodney W. Grimes 		 * If the operation is still going, leave
30126f9a767SRodney W. Grimes 		 * the page busy to block all other accesses.
30226f9a767SRodney W. Grimes 		 * Also, leave the paging in progress
30326f9a767SRodney W. Grimes 		 * indicator set so that we don't attempt an
30426f9a767SRodney W. Grimes 		 * object collapse.
30526f9a767SRodney W. Grimes 		 */
30626f9a767SRodney W. Grimes 		if (pageout_status[i] != VM_PAGER_PEND) {
30726f9a767SRodney W. Grimes 			PAGE_WAKEUP(ms[i]);
30826f9a767SRodney W. Grimes 			if (--object->paging_in_progress == 0)
30926f9a767SRodney W. Grimes 				wakeup((caddr_t) object);
310a647a309SDavid Greenman 			if ((ms[i]->flags & PG_REFERENCED) ||
311a647a309SDavid Greenman 				pmap_is_referenced(VM_PAGE_TO_PHYS(ms[i]))) {
31226f9a767SRodney W. Grimes 				pmap_clear_reference(VM_PAGE_TO_PHYS(ms[i]));
313a647a309SDavid Greenman 				ms[i]->flags &= ~PG_REFERENCED;
31426f9a767SRodney W. Grimes 				if( ms[i]->flags & PG_INACTIVE)
31526f9a767SRodney W. Grimes 					vm_page_activate(ms[i]);
31626f9a767SRodney W. Grimes 			}
31726f9a767SRodney W. Grimes 		}
31826f9a767SRodney W. Grimes 	}
31926f9a767SRodney W. Grimes 	return anyok;
32026f9a767SRodney W. Grimes }
32126f9a767SRodney W. Grimes 
32226f9a767SRodney W. Grimes /*
32326f9a767SRodney W. Grimes  *	vm_pageout_object_deactivate_pages
32426f9a767SRodney W. Grimes  *
32526f9a767SRodney W. Grimes  *	deactivate enough pages to satisfy the inactive target
32626f9a767SRodney W. Grimes  *	requirements or if vm_page_proc_limit is set, then
32726f9a767SRodney W. Grimes  *	deactivate all of the pages in the object and its
32826f9a767SRodney W. Grimes  *	shadows.
32926f9a767SRodney W. Grimes  *
33026f9a767SRodney W. Grimes  *	The object and map must be locked.
33126f9a767SRodney W. Grimes  */
33226f9a767SRodney W. Grimes int
33326f9a767SRodney W. Grimes vm_pageout_object_deactivate_pages(map, object, count)
33426f9a767SRodney W. Grimes 	vm_map_t map;
33526f9a767SRodney W. Grimes 	vm_object_t object;
33626f9a767SRodney W. Grimes 	int count;
33726f9a767SRodney W. Grimes {
33826f9a767SRodney W. Grimes 	register vm_page_t	p, next;
33926f9a767SRodney W. Grimes 	int rcount;
34026f9a767SRodney W. Grimes 	int dcount;
34126f9a767SRodney W. Grimes 
34226f9a767SRodney W. Grimes 	dcount = 0;
34326f9a767SRodney W. Grimes 	if (count == 0)
34426f9a767SRodney W. Grimes 		count = 1;
34526f9a767SRodney W. Grimes 
3462fe6e4d7SDavid Greenman #ifndef REL2_1
34726f9a767SRodney W. Grimes 	if (object->shadow) {
34826f9a767SRodney W. Grimes 		int scount = count;
34926f9a767SRodney W. Grimes 		if( object->shadow->ref_count > 1)
35026f9a767SRodney W. Grimes 			scount /= object->shadow->ref_count;
35126f9a767SRodney W. Grimes 		if( scount)
35226f9a767SRodney W. Grimes 			dcount += vm_pageout_object_deactivate_pages(map, object->shadow, scount);
35326f9a767SRodney W. Grimes 	}
3542fe6e4d7SDavid Greenman #else
3552fe6e4d7SDavid Greenman 	if (object->shadow) {
3562fe6e4d7SDavid Greenman 		if( object->shadow->ref_count == 1)
3572fe6e4d7SDavid Greenman 			dcount += vm_pageout_object_deactivate_pages(map, object->shadow, count/2);
3582fe6e4d7SDavid Greenman 	}
3592fe6e4d7SDavid Greenman #endif
36026f9a767SRodney W. Grimes 
36126f9a767SRodney W. Grimes 	if (object->paging_in_progress)
36226f9a767SRodney W. Grimes 		return dcount;
36326f9a767SRodney W. Grimes 
36426f9a767SRodney W. Grimes 	/*
36526f9a767SRodney W. Grimes 	 * scan the objects entire memory queue
36626f9a767SRodney W. Grimes 	 */
36726f9a767SRodney W. Grimes 	rcount = object->resident_page_count;
36826f9a767SRodney W. Grimes 	p = object->memq.tqh_first;
36926f9a767SRodney W. Grimes 	while (p && (rcount-- > 0)) {
37026f9a767SRodney W. Grimes 		next = p->listq.tqe_next;
371a58d1fa1SDavid Greenman 		cnt.v_pdpages++;
37226f9a767SRodney W. Grimes 		vm_page_lock_queues();
37326f9a767SRodney W. Grimes 		/*
37426f9a767SRodney W. Grimes 		 * if a page is active, not wired and is in the processes pmap,
37526f9a767SRodney W. Grimes 		 * then deactivate the page.
37626f9a767SRodney W. Grimes 		 */
37726f9a767SRodney W. Grimes 		if ((p->flags & (PG_ACTIVE|PG_BUSY)) == PG_ACTIVE &&
37826f9a767SRodney W. Grimes 			p->wire_count == 0 &&
37926f9a767SRodney W. Grimes 			p->hold_count == 0 &&
380a647a309SDavid Greenman 			p->busy == 0 &&
38126f9a767SRodney W. Grimes 			pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) {
382a647a309SDavid Greenman 			if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p)) &&
383a647a309SDavid Greenman 				(p->flags & PG_REFERENCED) == 0) {
38426f9a767SRodney W. Grimes 				p->act_count -= min(p->act_count, ACT_DECLINE);
38526f9a767SRodney W. Grimes 				/*
38626f9a767SRodney W. Grimes 				 * if the page act_count is zero -- then we deactivate
38726f9a767SRodney W. Grimes 				 */
38826f9a767SRodney W. Grimes 				if (!p->act_count) {
38926f9a767SRodney W. Grimes 					vm_page_deactivate(p);
39026f9a767SRodney W. Grimes 					pmap_page_protect(VM_PAGE_TO_PHYS(p),
39126f9a767SRodney W. Grimes 						VM_PROT_NONE);
39226f9a767SRodney W. Grimes 				/*
39326f9a767SRodney W. Grimes 				 * else if on the next go-around we will deactivate the page
39426f9a767SRodney W. Grimes 				 * we need to place the page on the end of the queue to age
39526f9a767SRodney W. Grimes 				 * the other pages in memory.
39626f9a767SRodney W. Grimes 				 */
39726f9a767SRodney W. Grimes 				} else {
39826f9a767SRodney W. Grimes 					TAILQ_REMOVE(&vm_page_queue_active, p, pageq);
39926f9a767SRodney W. Grimes 					TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq);
40026f9a767SRodney W. Grimes 					TAILQ_REMOVE(&object->memq, p, listq);
40126f9a767SRodney W. Grimes 					TAILQ_INSERT_TAIL(&object->memq, p, listq);
40226f9a767SRodney W. Grimes 				}
40326f9a767SRodney W. Grimes 				/*
40426f9a767SRodney W. Grimes 				 * see if we are done yet
40526f9a767SRodney W. Grimes 				 */
40626f9a767SRodney W. Grimes 				if (p->flags & PG_INACTIVE) {
40726f9a767SRodney W. Grimes 					--count;
40826f9a767SRodney W. Grimes 					++dcount;
40926f9a767SRodney W. Grimes 					if (count <= 0 &&
41026f9a767SRodney W. Grimes 						cnt.v_inactive_count > cnt.v_inactive_target) {
41126f9a767SRodney W. Grimes 							vm_page_unlock_queues();
41226f9a767SRodney W. Grimes 							return dcount;
41326f9a767SRodney W. Grimes 					}
41426f9a767SRodney W. Grimes 				}
41526f9a767SRodney W. Grimes 
41626f9a767SRodney W. Grimes 			} else {
41726f9a767SRodney W. Grimes 				/*
41826f9a767SRodney W. Grimes 				 * Move the page to the bottom of the queue.
41926f9a767SRodney W. Grimes 				 */
42026f9a767SRodney W. Grimes 				pmap_clear_reference(VM_PAGE_TO_PHYS(p));
421a647a309SDavid Greenman 				p->flags &= ~PG_REFERENCED;
42226f9a767SRodney W. Grimes 				if (p->act_count < ACT_MAX)
42326f9a767SRodney W. Grimes 					p->act_count += ACT_ADVANCE;
42426f9a767SRodney W. Grimes 
42526f9a767SRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_active, p, pageq);
42626f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq);
42726f9a767SRodney W. Grimes 				TAILQ_REMOVE(&object->memq, p, listq);
42826f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&object->memq, p, listq);
42926f9a767SRodney W. Grimes 			}
43026f9a767SRodney W. Grimes 		}
43126f9a767SRodney W. Grimes 
43226f9a767SRodney W. Grimes 		vm_page_unlock_queues();
43326f9a767SRodney W. Grimes 		p = next;
43426f9a767SRodney W. Grimes 	}
43526f9a767SRodney W. Grimes 	return dcount;
43626f9a767SRodney W. Grimes }
43726f9a767SRodney W. Grimes 
43826f9a767SRodney W. Grimes 
43926f9a767SRodney W. Grimes /*
44026f9a767SRodney W. Grimes  * deactivate some number of pages in a map, try to do it fairly, but
44126f9a767SRodney W. Grimes  * that is really hard to do.
44226f9a767SRodney W. Grimes  */
44326f9a767SRodney W. Grimes 
44426f9a767SRodney W. Grimes void
44526f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(map, entry, count, freeer)
44626f9a767SRodney W. Grimes 	vm_map_t map;
44726f9a767SRodney W. Grimes 	vm_map_entry_t entry;
44826f9a767SRodney W. Grimes 	int *count;
44926f9a767SRodney W. Grimes 	int (*freeer)(vm_map_t, vm_object_t, int);
45026f9a767SRodney W. Grimes {
45126f9a767SRodney W. Grimes 	vm_map_t tmpm;
45226f9a767SRodney W. Grimes 	vm_map_entry_t tmpe;
45326f9a767SRodney W. Grimes 	vm_object_t obj;
45426f9a767SRodney W. Grimes 	if (*count <= 0)
45526f9a767SRodney W. Grimes 		return;
45626f9a767SRodney W. Grimes 	vm_map_reference(map);
45726f9a767SRodney W. Grimes 	if (!lock_try_read(&map->lock)) {
45826f9a767SRodney W. Grimes 		vm_map_deallocate(map);
45926f9a767SRodney W. Grimes 		return;
46026f9a767SRodney W. Grimes 	}
46126f9a767SRodney W. Grimes 	if (entry == 0) {
46226f9a767SRodney W. Grimes 		tmpe = map->header.next;
46326f9a767SRodney W. Grimes 		while (tmpe != &map->header && *count > 0) {
46426f9a767SRodney W. Grimes 			vm_pageout_map_deactivate_pages(map, tmpe, count, freeer);
46526f9a767SRodney W. Grimes 			tmpe = tmpe->next;
46626f9a767SRodney W. Grimes 		};
46726f9a767SRodney W. Grimes 	} else if (entry->is_sub_map || entry->is_a_map) {
46826f9a767SRodney W. Grimes 		tmpm = entry->object.share_map;
46926f9a767SRodney W. Grimes 		tmpe = tmpm->header.next;
47026f9a767SRodney W. Grimes 		while (tmpe != &tmpm->header && *count > 0) {
47126f9a767SRodney W. Grimes 			vm_pageout_map_deactivate_pages(tmpm, tmpe, count, freeer);
47226f9a767SRodney W. Grimes 			tmpe = tmpe->next;
47326f9a767SRodney W. Grimes 		};
4744e39a515SPoul-Henning Kamp 	} else if ((obj = entry->object.vm_object) != 0) {
47526f9a767SRodney W. Grimes 		*count -= (*freeer)(map, obj, *count);
47626f9a767SRodney W. Grimes 	}
47726f9a767SRodney W. Grimes 	lock_read_done(&map->lock);
47826f9a767SRodney W. Grimes 	vm_map_deallocate(map);
47926f9a767SRodney W. Grimes 	return;
48026f9a767SRodney W. Grimes }
481df8bae1dSRodney W. Grimes 
4822fe6e4d7SDavid Greenman #ifdef REL2_1
4832fe6e4d7SDavid Greenman void
4842fe6e4d7SDavid Greenman vm_req_vmdaemon() {
4852fe6e4d7SDavid Greenman 	extern	int ticks;
4862fe6e4d7SDavid Greenman 	static lastrun = 0;
4872fe6e4d7SDavid Greenman 	if( (ticks > (lastrun + hz/10)) || (ticks < lastrun)) {
4882fe6e4d7SDavid Greenman 		wakeup((caddr_t) &vm_daemon_needed);
4892fe6e4d7SDavid Greenman 		lastrun = ticks;
4902fe6e4d7SDavid Greenman 	}
4912fe6e4d7SDavid Greenman }
4922fe6e4d7SDavid Greenman #endif
4932fe6e4d7SDavid Greenman 
494df8bae1dSRodney W. Grimes /*
495df8bae1dSRodney W. Grimes  *	vm_pageout_scan does the dirty work for the pageout daemon.
496df8bae1dSRodney W. Grimes  */
49726f9a767SRodney W. Grimes int
498df8bae1dSRodney W. Grimes vm_pageout_scan()
499df8bae1dSRodney W. Grimes {
50026f9a767SRodney W. Grimes 	vm_page_t	m;
50126f9a767SRodney W. Grimes 	int		page_shortage, maxscan, maxlaunder;
5024e39a515SPoul-Henning Kamp 	int		pages_freed;
50326f9a767SRodney W. Grimes 	int		desired_free;
50426f9a767SRodney W. Grimes 	vm_page_t	next;
5055663e6deSDavid Greenman 	struct proc	*p, *bigproc;
5065663e6deSDavid Greenman 	vm_offset_t size, bigsize;
507df8bae1dSRodney W. Grimes 	vm_object_t	object;
50826f9a767SRodney W. Grimes 	int		force_wakeup = 0;
509a647a309SDavid Greenman 	int		cache_size, orig_cache_size;
510a647a309SDavid Greenman 
5112fe6e4d7SDavid Greenman #ifndef REL2_1
51226f9a767SRodney W. Grimes morefree:
513df8bae1dSRodney W. Grimes 	/*
51411b224dcSDavid Greenman 	 * now swap processes out if we are in low memory conditions
515a647a309SDavid Greenman 	 */
5165663e6deSDavid Greenman 	if ((cnt.v_free_count <= cnt.v_free_min) && !swap_pager_full && vm_swap_size) {
517a647a309SDavid Greenman 		/*
518a647a309SDavid Greenman 		 * swap out inactive processes
519a647a309SDavid Greenman 		 */
520a647a309SDavid Greenman 		swapout_threads();
521a647a309SDavid Greenman 	}
52211b224dcSDavid Greenman 
523a647a309SDavid Greenman 	/*
52426f9a767SRodney W. Grimes 	 * scan the processes for exceeding their rlimits or if process
52526f9a767SRodney W. Grimes 	 * is swapped out -- deactivate pages
526df8bae1dSRodney W. Grimes 	 */
527df8bae1dSRodney W. Grimes 
52826f9a767SRodney W. Grimes 	for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
52926f9a767SRodney W. Grimes 		int overage;
530a6ca859eSDavid Greenman 		quad_t limit;
531df8bae1dSRodney W. Grimes 
532df8bae1dSRodney W. Grimes 		/*
53326f9a767SRodney W. Grimes 		 * if this is a system process or if we have already
53426f9a767SRodney W. Grimes 		 * looked at this process, skip it.
535df8bae1dSRodney W. Grimes 		 */
53626f9a767SRodney W. Grimes 		if (p->p_flag & (P_SYSTEM|P_WEXIT)) {
53726f9a767SRodney W. Grimes 			continue;
538df8bae1dSRodney W. Grimes 		}
539df8bae1dSRodney W. Grimes 
540df8bae1dSRodney W. Grimes 		/*
54126f9a767SRodney W. Grimes 		 * if the process is in a non-running type state,
54226f9a767SRodney W. Grimes 		 * don't touch it.
543df8bae1dSRodney W. Grimes 		 */
54426f9a767SRodney W. Grimes 		if (p->p_stat != SRUN && p->p_stat != SSLEEP) {
54526f9a767SRodney W. Grimes 			continue;
54626f9a767SRodney W. Grimes 		}
54726f9a767SRodney W. Grimes 
54826f9a767SRodney W. Grimes 		/*
54926f9a767SRodney W. Grimes 		 * get a limit
55026f9a767SRodney W. Grimes 		 */
551a6ca859eSDavid Greenman 		limit = qmin(p->p_rlimit[RLIMIT_RSS].rlim_cur,
55226f9a767SRodney W. Grimes 			    p->p_rlimit[RLIMIT_RSS].rlim_max);
55326f9a767SRodney W. Grimes 
55426f9a767SRodney W. Grimes 		/*
55526f9a767SRodney W. Grimes 		 * let processes that are swapped out really be swapped out
55626f9a767SRodney W. Grimes 		 * set the limit to nothing (will force a swap-out.)
55726f9a767SRodney W. Grimes 		 */
55826f9a767SRodney W. Grimes 		if ((p->p_flag & P_INMEM) == 0)
55926f9a767SRodney W. Grimes 			limit = 0;
56026f9a767SRodney W. Grimes 
56126f9a767SRodney W. Grimes 		size = p->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG;
56211b224dcSDavid Greenman 		if (limit >= 0 && size >= limit) {
56326f9a767SRodney W. Grimes 			overage = (size - limit) / NBPG;
56426f9a767SRodney W. Grimes 			vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map,
56526f9a767SRodney W. Grimes 				(vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages);
56626f9a767SRodney W. Grimes 		}
56726f9a767SRodney W. Grimes 	}
56826f9a767SRodney W. Grimes 
56926f9a767SRodney W. Grimes 	if (((cnt.v_free_count + cnt.v_inactive_count) >=
57026f9a767SRodney W. Grimes 		(cnt.v_inactive_target + cnt.v_free_target)) &&
57126f9a767SRodney W. Grimes 		(cnt.v_free_count >= cnt.v_free_target))
57226f9a767SRodney W. Grimes 		return force_wakeup;
5732fe6e4d7SDavid Greenman #else
5742fe6e4d7SDavid Greenman 	/* calculate the total cached size */
5752fe6e4d7SDavid Greenman 
5762fe6e4d7SDavid Greenman 	if( cnt.v_inactive_count < cnt.v_inactive_target) {
5772fe6e4d7SDavid Greenman 		vm_req_vmdaemon();
5782fe6e4d7SDavid Greenman 	}
5792fe6e4d7SDavid Greenman 
5802fe6e4d7SDavid Greenman morefree:
5812fe6e4d7SDavid Greenman 	/*
5822fe6e4d7SDavid Greenman 	 * now swap processes out if we are in low memory conditions
5832fe6e4d7SDavid Greenman 	 */
5842fe6e4d7SDavid Greenman 	if ((cnt.v_free_count <= cnt.v_free_min) && !swap_pager_full && vm_swap_size&& vm_pageout_req_swapout == 0) {
5852fe6e4d7SDavid Greenman 		vm_pageout_req_swapout = 1;
5862fe6e4d7SDavid Greenman 		vm_req_vmdaemon();
5872fe6e4d7SDavid Greenman 	}
5882fe6e4d7SDavid Greenman 
5892fe6e4d7SDavid Greenman #endif
59026f9a767SRodney W. Grimes 
59126f9a767SRodney W. Grimes 	pages_freed = 0;
59226f9a767SRodney W. Grimes 	desired_free = cnt.v_free_target;
593df8bae1dSRodney W. Grimes 
594df8bae1dSRodney W. Grimes 	/*
595df8bae1dSRodney W. Grimes 	 *	Start scanning the inactive queue for pages we can free.
596df8bae1dSRodney W. Grimes 	 *	We keep scanning until we have enough free pages or
597df8bae1dSRodney W. Grimes 	 *	we have scanned through the entire queue.  If we
598df8bae1dSRodney W. Grimes 	 *	encounter dirty pages, we start cleaning them.
599df8bae1dSRodney W. Grimes 	 */
600df8bae1dSRodney W. Grimes 
60126f9a767SRodney W. Grimes 	maxlaunder = (cnt.v_free_target - cnt.v_free_count);
60226f9a767SRodney W. Grimes 	maxscan = cnt.v_inactive_count;
60326f9a767SRodney W. Grimes rescan1:
60426f9a767SRodney W. Grimes 	m = vm_page_queue_inactive.tqh_first;
60526f9a767SRodney W. Grimes 	while (m && (maxscan-- > 0) &&
60626f9a767SRodney W. Grimes 		(cnt.v_free_count < desired_free) ) {
60726f9a767SRodney W. Grimes 		vm_page_t	next;
608df8bae1dSRodney W. Grimes 
609a58d1fa1SDavid Greenman 		cnt.v_pdpages++;
610df8bae1dSRodney W. Grimes 		next = m->pageq.tqe_next;
611df8bae1dSRodney W. Grimes 
61226f9a767SRodney W. Grimes 		if( (m->flags & PG_INACTIVE) == 0) {
61326f9a767SRodney W. Grimes 			printf("vm_pageout_scan: page not inactive?");
614df8bae1dSRodney W. Grimes 			continue;
615df8bae1dSRodney W. Grimes 		}
616df8bae1dSRodney W. Grimes 
617df8bae1dSRodney W. Grimes 		/*
61826f9a767SRodney W. Grimes 		 * activate held pages
61926f9a767SRodney W. Grimes 		 */
62026f9a767SRodney W. Grimes 		if (m->hold_count != 0) {
62126f9a767SRodney W. Grimes 			vm_page_activate(m);
62226f9a767SRodney W. Grimes 			m = next;
62326f9a767SRodney W. Grimes 			continue;
62426f9a767SRodney W. Grimes 		}
62526f9a767SRodney W. Grimes 
62626f9a767SRodney W. Grimes 		/*
62726f9a767SRodney W. Grimes 		 * dont mess with busy pages
62826f9a767SRodney W. Grimes 		 */
629a647a309SDavid Greenman 		if (m->busy || (m->flags & PG_BUSY)) {
63026f9a767SRodney W. Grimes 			m = next;
63126f9a767SRodney W. Grimes 			continue;
63226f9a767SRodney W. Grimes 		}
63326f9a767SRodney W. Grimes 
6342fe6e4d7SDavid Greenman 		if (((m->flags & PG_CLEAN) != 0) && pmap_is_modified(VM_PAGE_TO_PHYS(m)))
6352fe6e4d7SDavid Greenman 			m->flags &= ~PG_CLEAN;
6362fe6e4d7SDavid Greenman 
6372fe6e4d7SDavid Greenman 		if (((m->flags & PG_REFERENCED) == 0) && pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
6382fe6e4d7SDavid Greenman 			m->flags |= PG_REFERENCED;
6392fe6e4d7SDavid Greenman 			pmap_clear_reference(VM_PAGE_TO_PHYS(m));
6402fe6e4d7SDavid Greenman 		}
6412fe6e4d7SDavid Greenman 
642df8bae1dSRodney W. Grimes 		if (m->flags & PG_CLEAN) {
643edaaafdbSDavid Greenman 			/*
644edaaafdbSDavid Greenman 			 * If we're not low on memory and the page has been reference,
6452fe6e4d7SDavid Greenman 			 * then reactivate the page.
646edaaafdbSDavid Greenman 			 */
6472fe6e4d7SDavid Greenman 			if ((cnt.v_free_count > vm_pageout_free_min) &&
6482fe6e4d7SDavid Greenman 			    ((m->flags & PG_REFERENCED) != 0)) {
649a647a309SDavid Greenman 				m->flags &= ~PG_REFERENCED;
65026f9a767SRodney W. Grimes 				vm_page_activate(m);
6512fe6e4d7SDavid Greenman 			} else if (m->act_count == 0) {
652df8bae1dSRodney W. Grimes 				pmap_page_protect(VM_PAGE_TO_PHYS(m),
653df8bae1dSRodney W. Grimes 						  VM_PROT_NONE);
654df8bae1dSRodney W. Grimes 				vm_page_free(m);
655ed74321bSDavid Greenman 				++cnt.v_dfree;
65626f9a767SRodney W. Grimes 				++pages_freed;
65726f9a767SRodney W. Grimes 			} else {
65826f9a767SRodney W. Grimes 				m->act_count -= min(m->act_count, ACT_DECLINE);
65926f9a767SRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq);
66026f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&vm_page_queue_inactive, m, pageq);
661df8bae1dSRodney W. Grimes 			}
66226f9a767SRodney W. Grimes 		} else if ((m->flags & PG_LAUNDRY) && maxlaunder > 0) {
66326f9a767SRodney W. Grimes 			int written;
6642fe6e4d7SDavid Greenman 			if ((m->flags & PG_REFERENCED) != 0) {
665a647a309SDavid Greenman 				m->flags &= ~PG_REFERENCED;
6662fe6e4d7SDavid Greenman 				vm_page_activate(m);
66726f9a767SRodney W. Grimes 				m = next;
668df8bae1dSRodney W. Grimes 				continue;
669df8bae1dSRodney W. Grimes 			}
6702fe6e4d7SDavid Greenman 
671df8bae1dSRodney W. Grimes 			/*
67226f9a767SRodney W. Grimes 			 *	If a page is dirty, then it is either
67326f9a767SRodney W. Grimes 			 *	being washed (but not yet cleaned)
67426f9a767SRodney W. Grimes 			 *	or it is still in the laundry.  If it is
67526f9a767SRodney W. Grimes 			 *	still in the laundry, then we start the
67626f9a767SRodney W. Grimes 			 *	cleaning operation.
677df8bae1dSRodney W. Grimes 			 */
6784e39a515SPoul-Henning Kamp 			written = vm_pageout_clean(m,0);
6794e39a515SPoul-Henning Kamp 			if (written)
68026f9a767SRodney W. Grimes 				maxlaunder -= written;
6814e39a515SPoul-Henning Kamp 
68216f62314SDavid Greenman 			if (!next)
68316f62314SDavid Greenman 				break;
684df8bae1dSRodney W. Grimes 			/*
68526f9a767SRodney W. Grimes 			 * if the next page has been re-activated, start scanning again
686df8bae1dSRodney W. Grimes 			 */
6872fe6e4d7SDavid Greenman 			if ((written != 0) || ((next->flags & PG_INACTIVE) == 0))
68826f9a767SRodney W. Grimes 				goto rescan1;
6892fe6e4d7SDavid Greenman 		} else if ((m->flags & PG_REFERENCED) != 0) {
690a647a309SDavid Greenman 			m->flags &= ~PG_REFERENCED;
69126f9a767SRodney W. Grimes 			vm_page_activate(m);
69226f9a767SRodney W. Grimes 		}
69326f9a767SRodney W. Grimes 		m = next;
69426f9a767SRodney W. Grimes 	}
69526f9a767SRodney W. Grimes 
696df8bae1dSRodney W. Grimes 	/*
697df8bae1dSRodney W. Grimes 	 *	Compute the page shortage.  If we are still very low on memory
698df8bae1dSRodney W. Grimes 	 *	be sure that we will move a minimal amount of pages from active
699df8bae1dSRodney W. Grimes 	 *	to inactive.
700df8bae1dSRodney W. Grimes 	 */
701df8bae1dSRodney W. Grimes 
70226f9a767SRodney W. Grimes 	page_shortage = cnt.v_inactive_target -
70326f9a767SRodney W. Grimes 	    (cnt.v_free_count + cnt.v_inactive_count);
70426f9a767SRodney W. Grimes 
70526f9a767SRodney W. Grimes 	if (page_shortage <= 0) {
70626f9a767SRodney W. Grimes 		if (pages_freed == 0) {
70726f9a767SRodney W. Grimes 			if( cnt.v_free_count < cnt.v_free_min) {
7085663e6deSDavid Greenman 				page_shortage = cnt.v_free_min - cnt.v_free_count + 1;
70926f9a767SRodney W. Grimes 			} else if(((cnt.v_free_count + cnt.v_inactive_count) <
71026f9a767SRodney W. Grimes 				(cnt.v_free_min + cnt.v_inactive_target))) {
711df8bae1dSRodney W. Grimes 				page_shortage = 1;
71226f9a767SRodney W. Grimes 			} else {
71326f9a767SRodney W. Grimes 				page_shortage = 0;
71426f9a767SRodney W. Grimes 			}
715df8bae1dSRodney W. Grimes 		}
716df8bae1dSRodney W. Grimes 
717df8bae1dSRodney W. Grimes 	}
718df8bae1dSRodney W. Grimes 
71926f9a767SRodney W. Grimes 	maxscan = cnt.v_active_count;
72026f9a767SRodney W. Grimes 	m = vm_page_queue_active.tqh_first;
72126f9a767SRodney W. Grimes 	while (m && maxscan-- && (page_shortage > 0)) {
72226f9a767SRodney W. Grimes 
723a58d1fa1SDavid Greenman 		cnt.v_pdpages++;
72426f9a767SRodney W. Grimes 		next = m->pageq.tqe_next;
725df8bae1dSRodney W. Grimes 
726df8bae1dSRodney W. Grimes 		/*
72726f9a767SRodney W. Grimes  		 * Don't deactivate pages that are busy.
728df8bae1dSRodney W. Grimes 		 */
729a647a309SDavid Greenman 		if ((m->busy != 0) ||
730a647a309SDavid Greenman 			(m->flags & PG_BUSY) || (m->hold_count != 0)) {
73126f9a767SRodney W. Grimes 			m = next;
73226f9a767SRodney W. Grimes 			continue;
733df8bae1dSRodney W. Grimes 		}
734df8bae1dSRodney W. Grimes 
735a647a309SDavid Greenman 		if ((m->flags & PG_REFERENCED) ||
736a647a309SDavid Greenman 			pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
737df8bae1dSRodney W. Grimes 			pmap_clear_reference(VM_PAGE_TO_PHYS(m));
738a647a309SDavid Greenman 			m->flags &= ~PG_REFERENCED;
73926f9a767SRodney W. Grimes 			if (m->act_count < ACT_MAX)
74026f9a767SRodney W. Grimes 				m->act_count += ACT_ADVANCE;
74126f9a767SRodney W. Grimes 			TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
74226f9a767SRodney W. Grimes 			TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq);
74326f9a767SRodney W. Grimes 			TAILQ_REMOVE(&m->object->memq, m, listq);
74426f9a767SRodney W. Grimes 			TAILQ_INSERT_TAIL(&m->object->memq, m, listq);
74526f9a767SRodney W. Grimes 		} else {
74626f9a767SRodney W. Grimes 			m->act_count -= min(m->act_count, ACT_DECLINE);
747df8bae1dSRodney W. Grimes 
748df8bae1dSRodney W. Grimes 			/*
74926f9a767SRodney W. Grimes 			 * if the page act_count is zero -- then we deactivate
750df8bae1dSRodney W. Grimes 			 */
75126f9a767SRodney W. Grimes 			if (!m->act_count) {
75226f9a767SRodney W. Grimes 				vm_page_deactivate(m);
75326f9a767SRodney W. Grimes 				--page_shortage;
75426f9a767SRodney W. Grimes 			/*
75526f9a767SRodney W. Grimes 			 * else if on the next go-around we will deactivate the page
75626f9a767SRodney W. Grimes 			 * we need to place the page on the end of the queue to age
75726f9a767SRodney W. Grimes 			 * the other pages in memory.
75826f9a767SRodney W. Grimes 			 */
75926f9a767SRodney W. Grimes 			} else {
76026f9a767SRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
76126f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq);
76226f9a767SRodney W. Grimes 				TAILQ_REMOVE(&m->object->memq, m, listq);
76326f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&m->object->memq, m, listq);
764df8bae1dSRodney W. Grimes 			}
765df8bae1dSRodney W. Grimes 		}
76626f9a767SRodney W. Grimes 		m = next;
76726f9a767SRodney W. Grimes 	}
768df8bae1dSRodney W. Grimes 
769df8bae1dSRodney W. Grimes 	/*
77026f9a767SRodney W. Grimes 	 * if we have not freed any pages and we are desparate for memory
77126f9a767SRodney W. Grimes 	 * then we keep trying until we get some (any) memory.
772df8bae1dSRodney W. Grimes 	 */
77326f9a767SRodney W. Grimes 
77426f9a767SRodney W. Grimes 	if (!force_wakeup && (swap_pager_full || !force_wakeup ||
77526f9a767SRodney W. Grimes 	    (pages_freed == 0 && (cnt.v_free_count < cnt.v_free_min)))){
77626f9a767SRodney W. Grimes 		vm_pager_sync();
77726f9a767SRodney W. Grimes 		force_wakeup = 1;
77826f9a767SRodney W. Grimes 		goto morefree;
77926f9a767SRodney W. Grimes 	}
7805663e6deSDavid Greenman 
7815663e6deSDavid Greenman 	/*
7825663e6deSDavid Greenman 	 * make sure that we have swap space -- if we are low on
7835663e6deSDavid Greenman 	 * memory and swap -- then kill the biggest process.
7845663e6deSDavid Greenman 	 */
7855663e6deSDavid Greenman 	if ((vm_swap_size == 0 || swap_pager_full) &&
7865663e6deSDavid Greenman 	    (cnt.v_free_count < cnt.v_free_min)) {
7875663e6deSDavid Greenman 		bigproc = NULL;
7885663e6deSDavid Greenman 		bigsize = 0;
7895663e6deSDavid Greenman 		for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
7905663e6deSDavid Greenman 			/*
7915663e6deSDavid Greenman 			 * if this is a system process, skip it
7925663e6deSDavid Greenman 			 */
7935663e6deSDavid Greenman 			if ((p->p_flag & P_SYSTEM) || ((p->p_pid < 48) && (vm_swap_size != 0))) {
7945663e6deSDavid Greenman 				continue;
7955663e6deSDavid Greenman 			}
7965663e6deSDavid Greenman 
7975663e6deSDavid Greenman 			/*
7985663e6deSDavid Greenman 			 * if the process is in a non-running type state,
7995663e6deSDavid Greenman 			 * don't touch it.
8005663e6deSDavid Greenman 			 */
8015663e6deSDavid Greenman 			if (p->p_stat != SRUN && p->p_stat != SSLEEP) {
8025663e6deSDavid Greenman 				continue;
8035663e6deSDavid Greenman 			}
8045663e6deSDavid Greenman 			/*
8055663e6deSDavid Greenman 			 * get the process size
8065663e6deSDavid Greenman 			 */
8075663e6deSDavid Greenman 			size = p->p_vmspace->vm_pmap.pm_stats.resident_count;
8085663e6deSDavid Greenman 			/*
8095663e6deSDavid Greenman 			 * if the this process is bigger than the biggest one
8105663e6deSDavid Greenman 			 * remember it.
8115663e6deSDavid Greenman 			 */
8125663e6deSDavid Greenman 			if (size > bigsize) {
8135663e6deSDavid Greenman 				bigproc = p;
8145663e6deSDavid Greenman 				bigsize = size;
8155663e6deSDavid Greenman 			}
8165663e6deSDavid Greenman 		}
8175663e6deSDavid Greenman 		if (bigproc != NULL) {
8185663e6deSDavid Greenman 			printf("Process %lu killed by vm_pageout -- out of swap\n", (u_long)bigproc->p_pid);
8195663e6deSDavid Greenman 			psignal(bigproc, SIGKILL);
8205663e6deSDavid Greenman 			bigproc->p_estcpu = 0;
8215663e6deSDavid Greenman 			bigproc->p_nice = PRIO_MIN;
8225663e6deSDavid Greenman 			resetpriority(bigproc);
8235663e6deSDavid Greenman 			wakeup( (caddr_t) &cnt.v_free_count);
8245663e6deSDavid Greenman 		}
8255663e6deSDavid Greenman 	}
82626f9a767SRodney W. Grimes 	vm_page_pagesfreed += pages_freed;
82726f9a767SRodney W. Grimes 	return force_wakeup;
82826f9a767SRodney W. Grimes }
82926f9a767SRodney W. Grimes 
830df8bae1dSRodney W. Grimes /*
831df8bae1dSRodney W. Grimes  *	vm_pageout is the high level pageout daemon.
832df8bae1dSRodney W. Grimes  */
83326f9a767SRodney W. Grimes void
83426f9a767SRodney W. Grimes vm_pageout()
835df8bae1dSRodney W. Grimes {
836df8bae1dSRodney W. Grimes 	(void) spl0();
837df8bae1dSRodney W. Grimes 
838df8bae1dSRodney W. Grimes 	/*
839df8bae1dSRodney W. Grimes 	 *	Initialize some paging parameters.
840df8bae1dSRodney W. Grimes 	 */
841df8bae1dSRodney W. Grimes 
84226f9a767SRodney W. Grimes 	cnt.v_free_min = 12;
843ed74321bSDavid Greenman 	/*
844ed74321bSDavid Greenman 	 * free_reserved needs to include enough for the largest
845ed74321bSDavid Greenman 	 * swap pager structures plus enough for any pv_entry
846ed74321bSDavid Greenman 	 * structs when paging.
847ed74321bSDavid Greenman 	 */
848389918eeSDavid Greenman 	vm_pageout_free_min = 4 + cnt.v_page_count / 1024;
849389918eeSDavid Greenman 	cnt.v_free_reserved = vm_pageout_free_min + 2;
85026f9a767SRodney W. Grimes 	if (cnt.v_free_min < 8)
85126f9a767SRodney W. Grimes 		cnt.v_free_min = 8;
85226f9a767SRodney W. Grimes 	if (cnt.v_free_min > 32)
85326f9a767SRodney W. Grimes 		cnt.v_free_min = 32;
85426f9a767SRodney W. Grimes 	cnt.v_free_target = 2*cnt.v_free_min + cnt.v_free_reserved;
85526f9a767SRodney W. Grimes 	cnt.v_inactive_target = cnt.v_free_count / 12;
85626f9a767SRodney W. Grimes 	cnt.v_free_min += cnt.v_free_reserved;
857a647a309SDavid Greenman 	vm_desired_cache_size = cnt.v_page_count / 3;
858df8bae1dSRodney W. Grimes 
859df8bae1dSRodney W. Grimes         /* XXX does not really belong here */
860df8bae1dSRodney W. Grimes 	if (vm_page_max_wired == 0)
861df8bae1dSRodney W. Grimes 		vm_page_max_wired = cnt.v_free_count / 3;
862df8bae1dSRodney W. Grimes 
86326f9a767SRodney W. Grimes 
86426f9a767SRodney W. Grimes 	(void) swap_pager_alloc(0, 0, 0, 0);
86526f9a767SRodney W. Grimes 
866df8bae1dSRodney W. Grimes 	/*
867df8bae1dSRodney W. Grimes 	 *	The pageout daemon is never done, so loop
868df8bae1dSRodney W. Grimes 	 *	forever.
869df8bae1dSRodney W. Grimes 	 */
870df8bae1dSRodney W. Grimes 	while (TRUE) {
87126f9a767SRodney W. Grimes 		int force_wakeup;
872df8bae1dSRodney W. Grimes 
87326f9a767SRodney W. Grimes 		tsleep((caddr_t) &vm_pages_needed, PVM, "psleep", 0);
874a58d1fa1SDavid Greenman 		cnt.v_pdwakeups++;
87526f9a767SRodney W. Grimes 
876df8bae1dSRodney W. Grimes 		vm_pager_sync();
87726f9a767SRodney W. Grimes 		/*
87826f9a767SRodney W. Grimes 		 * The force wakeup hack added to eliminate delays and potiential
87926f9a767SRodney W. Grimes 		 * deadlock.  It was possible for the page daemon to indefintely
88026f9a767SRodney W. Grimes 		 * postpone waking up a process that it might be waiting for memory
88126f9a767SRodney W. Grimes 		 * on.  The putmulti stuff seems to have aggravated the situation.
88226f9a767SRodney W. Grimes 		 */
88326f9a767SRodney W. Grimes 		force_wakeup = vm_pageout_scan();
88426f9a767SRodney W. Grimes 		vm_pager_sync();
88526f9a767SRodney W. Grimes 		if( force_wakeup)
88626f9a767SRodney W. Grimes 			wakeup( (caddr_t) &cnt.v_free_count);
88726f9a767SRodney W. Grimes 		wakeup((caddr_t) kmem_map);
888df8bae1dSRodney W. Grimes 	}
889df8bae1dSRodney W. Grimes }
89026f9a767SRodney W. Grimes 
8912fe6e4d7SDavid Greenman #ifdef REL2_1
8922fe6e4d7SDavid Greenman void
8932fe6e4d7SDavid Greenman vm_daemon() {
8942fe6e4d7SDavid Greenman 	int cache_size;
8952fe6e4d7SDavid Greenman 	vm_object_t object;
8962fe6e4d7SDavid Greenman 	struct proc *p;
8972fe6e4d7SDavid Greenman 	while(TRUE) {
8982fe6e4d7SDavid Greenman 		tsleep((caddr_t) &vm_daemon_needed, PUSER, "psleep", 0);
8992fe6e4d7SDavid Greenman 		if( vm_pageout_req_swapout) {
9002fe6e4d7SDavid Greenman 		/*
9012fe6e4d7SDavid Greenman 		 * swap out inactive processes
9022fe6e4d7SDavid Greenman 		 */
9032fe6e4d7SDavid Greenman 			swapout_threads();
9042fe6e4d7SDavid Greenman 			vm_pageout_req_swapout = 0;
9052fe6e4d7SDavid Greenman 		}
9062fe6e4d7SDavid Greenman 	/*
9072fe6e4d7SDavid Greenman 	 * scan the processes for exceeding their rlimits or if process
9082fe6e4d7SDavid Greenman 	 * is swapped out -- deactivate pages
9092fe6e4d7SDavid Greenman 	 */
9102fe6e4d7SDavid Greenman 
9112fe6e4d7SDavid Greenman 		for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
9122fe6e4d7SDavid Greenman 			int overage;
9132fe6e4d7SDavid Greenman 			quad_t limit;
9142fe6e4d7SDavid Greenman 			vm_offset_t size;
9152fe6e4d7SDavid Greenman 
9162fe6e4d7SDavid Greenman 			/*
9172fe6e4d7SDavid Greenman 			 * if this is a system process or if we have already
9182fe6e4d7SDavid Greenman 			 * looked at this process, skip it.
9192fe6e4d7SDavid Greenman 			 */
9202fe6e4d7SDavid Greenman 			if (p->p_flag & (P_SYSTEM|P_WEXIT)) {
9212fe6e4d7SDavid Greenman 				continue;
9222fe6e4d7SDavid Greenman 			}
9232fe6e4d7SDavid Greenman 
9242fe6e4d7SDavid Greenman 		/*
9252fe6e4d7SDavid Greenman 		 * if the process is in a non-running type state,
9262fe6e4d7SDavid Greenman 		 * don't touch it.
9272fe6e4d7SDavid Greenman 		 */
9282fe6e4d7SDavid Greenman 			if (p->p_stat != SRUN && p->p_stat != SSLEEP) {
9292fe6e4d7SDavid Greenman 				continue;
9302fe6e4d7SDavid Greenman 			}
9312fe6e4d7SDavid Greenman 
9322fe6e4d7SDavid Greenman 		/*
9332fe6e4d7SDavid Greenman 		 * get a limit
9342fe6e4d7SDavid Greenman 		 */
9352fe6e4d7SDavid Greenman 			limit = qmin(p->p_rlimit[RLIMIT_RSS].rlim_cur,
9362fe6e4d7SDavid Greenman 				    p->p_rlimit[RLIMIT_RSS].rlim_max);
9372fe6e4d7SDavid Greenman 
9382fe6e4d7SDavid Greenman 		/*
9392fe6e4d7SDavid Greenman 		 * let processes that are swapped out really be swapped out
9402fe6e4d7SDavid Greenman 		 * set the limit to nothing (will force a swap-out.)
9412fe6e4d7SDavid Greenman 		 */
9422fe6e4d7SDavid Greenman 			if ((p->p_flag & P_INMEM) == 0)
9432fe6e4d7SDavid Greenman 				limit = 0;
9442fe6e4d7SDavid Greenman 
9452fe6e4d7SDavid Greenman 			size = p->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG;
9462fe6e4d7SDavid Greenman 			if (limit >= 0 && size >= limit) {
9472fe6e4d7SDavid Greenman 				overage = (size - limit) / NBPG;
9482fe6e4d7SDavid Greenman 				vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map,
9492fe6e4d7SDavid Greenman 					(vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages);
9502fe6e4d7SDavid Greenman 			}
9512fe6e4d7SDavid Greenman 		}
9522fe6e4d7SDavid Greenman 
9532fe6e4d7SDavid Greenman 	/*
9542fe6e4d7SDavid Greenman 	 * We manage the cached memory by attempting to keep it
9552fe6e4d7SDavid Greenman 	 * at about the desired level.
9562fe6e4d7SDavid Greenman 	 * We deactivate the pages for the oldest cached objects
9572fe6e4d7SDavid Greenman 	 * first.  This keeps pages that are "cached" from hogging
9582fe6e4d7SDavid Greenman 	 * physical memory.
9592fe6e4d7SDavid Greenman 	 */
9602fe6e4d7SDavid Greenman restart:
9612fe6e4d7SDavid Greenman 		cache_size = 0;
9622fe6e4d7SDavid Greenman 		object = vm_object_cached_list.tqh_first;
9632fe6e4d7SDavid Greenman 	/* calculate the total cached size */
9642fe6e4d7SDavid Greenman 		while( object) {
9652fe6e4d7SDavid Greenman 			cache_size += object->resident_page_count;
9662fe6e4d7SDavid Greenman 			object = object->cached_list.tqe_next;
9672fe6e4d7SDavid Greenman 		}
9682fe6e4d7SDavid Greenman 
9692fe6e4d7SDavid Greenman 		vm_object_cache_lock();
9702fe6e4d7SDavid Greenman 		object = vm_object_cached_list.tqh_first;
9712fe6e4d7SDavid Greenman 		while ( object) {
9722fe6e4d7SDavid Greenman 			vm_object_cache_unlock();
9732fe6e4d7SDavid Greenman 		/*
9742fe6e4d7SDavid Greenman 		 * if there are no resident pages -- get rid of the object
9752fe6e4d7SDavid Greenman 		 */
9762fe6e4d7SDavid Greenman 			if( object->resident_page_count == 0) {
9772fe6e4d7SDavid Greenman 				if (object != vm_object_lookup(object->pager))
9782fe6e4d7SDavid Greenman 					panic("vm_object_cache_trim: I'm sooo confused.");
9792fe6e4d7SDavid Greenman 				pager_cache(object, FALSE);
9802fe6e4d7SDavid Greenman 				goto restart;
9812fe6e4d7SDavid Greenman 			} else if( cache_size >= (vm_swap_size?vm_desired_cache_size:0)) {
9822fe6e4d7SDavid Greenman 		/*
9832fe6e4d7SDavid Greenman 		 * if there are resident pages -- deactivate them
9842fe6e4d7SDavid Greenman 		 */
9852fe6e4d7SDavid Greenman 				vm_object_deactivate_pages(object);
9862fe6e4d7SDavid Greenman 				cache_size -= object->resident_page_count;
9872fe6e4d7SDavid Greenman 			}
9882fe6e4d7SDavid Greenman 			object = object->cached_list.tqe_next;
9892fe6e4d7SDavid Greenman 			vm_object_cache_lock();
9902fe6e4d7SDavid Greenman 		}
9912fe6e4d7SDavid Greenman 		vm_object_cache_unlock();
9922fe6e4d7SDavid Greenman 	}
9932fe6e4d7SDavid Greenman }
9942fe6e4d7SDavid Greenman #endif
995