xref: /freebsd/sys/vm/vm_pageout.c (revision 26f9a76710a312a951848542b9ca1f44100450e2)
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  *
4026f9a767SRodney W. Grimes  *	@(#)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  *
6826f9a767SRodney W. Grimes  * $Id: vm_pageout.c,v 1.20 1994/04/20 07:07:15 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>
84df8bae1dSRodney W. Grimes 
8526f9a767SRodney W. Grimes extern vm_map_t kmem_map;
86df8bae1dSRodney W. Grimes int	vm_pages_needed;		/* Event on which pageout daemon sleeps */
8726f9a767SRodney W. Grimes int	vm_pagescanner;			/* Event on which pagescanner sleeps */
8826f9a767SRodney W. Grimes int	vm_pageout_free_min = 0;	/* Stop pageout to wait for pagers at this free level */
8926f9a767SRodney W. Grimes 
9026f9a767SRodney W. Grimes int	vm_pageout_pages_needed = 0;	/* flag saying that the pageout daemon needs pages */
9126f9a767SRodney W. Grimes int	vm_page_pagesfreed;
9226f9a767SRodney W. Grimes 
9326f9a767SRodney W. Grimes extern int npendingio;
9426f9a767SRodney W. Grimes extern int hz;
9526f9a767SRodney W. Grimes int	vm_pageout_proc_limit;
9626f9a767SRodney W. Grimes extern int nswiodone;
9726f9a767SRodney W. Grimes extern int swap_pager_full;
9826f9a767SRodney W. Grimes extern int swap_pager_ready();
9926f9a767SRodney W. Grimes 
10026f9a767SRodney W. Grimes #define MAXREF 32767
10126f9a767SRodney W. Grimes 
10226f9a767SRodney W. Grimes #define MAXSCAN 512	/* maximum number of pages to scan in active queue */
10326f9a767SRodney W. Grimes 			/* set the "clock" hands to be (MAXSCAN * 4096) Bytes */
10426f9a767SRodney W. Grimes #define ACT_DECLINE	1
10526f9a767SRodney W. Grimes #define ACT_ADVANCE	6
10626f9a767SRodney W. Grimes #define ACT_MAX		300
10726f9a767SRodney W. Grimes 
10826f9a767SRodney W. Grimes #define LOWATER ((2048*1024)/NBPG)
10926f9a767SRodney W. Grimes 
11026f9a767SRodney W. Grimes #define VM_PAGEOUT_PAGE_COUNT 8
11126f9a767SRodney W. Grimes static vm_offset_t vm_space_needed;
11226f9a767SRodney W. Grimes int vm_pageout_req_do_stats;
113df8bae1dSRodney W. Grimes 
114df8bae1dSRodney W. Grimes int	vm_page_max_wired = 0;	/* XXX max # of wired pages system-wide */
115df8bae1dSRodney W. Grimes 
11626f9a767SRodney W. Grimes 
11726f9a767SRodney W. Grimes /*
11826f9a767SRodney W. Grimes  * vm_pageout_clean:
11926f9a767SRodney W. Grimes  * 	cleans a vm_page
12026f9a767SRodney W. Grimes  */
12126f9a767SRodney W. Grimes int
12226f9a767SRodney W. Grimes vm_pageout_clean(m, sync)
12326f9a767SRodney W. Grimes 	register vm_page_t m;
12426f9a767SRodney W. Grimes 	int sync;
12526f9a767SRodney W. Grimes {
12626f9a767SRodney W. Grimes 	/*
12726f9a767SRodney W. Grimes 	 *	Clean the page and remove it from the
12826f9a767SRodney W. Grimes 	 *	laundry.
12926f9a767SRodney W. Grimes 	 *
13026f9a767SRodney W. Grimes 	 *	We set the busy bit to cause
13126f9a767SRodney W. Grimes 	 *	potential page faults on this page to
13226f9a767SRodney W. Grimes 	 *	block.
13326f9a767SRodney W. Grimes 	 *
13426f9a767SRodney W. Grimes 	 *	And we set pageout-in-progress to keep
13526f9a767SRodney W. Grimes 	 *	the object from disappearing during
13626f9a767SRodney W. Grimes 	 *	pageout.  This guarantees that the
13726f9a767SRodney W. Grimes 	 *	page won't move from the inactive
13826f9a767SRodney W. Grimes 	 *	queue.  (However, any other page on
13926f9a767SRodney W. Grimes 	 *	the inactive queue may move!)
14026f9a767SRodney W. Grimes 	 */
14126f9a767SRodney W. Grimes 
14226f9a767SRodney W. Grimes 	register vm_object_t	object;
14326f9a767SRodney W. Grimes 	register vm_pager_t	pager;
14426f9a767SRodney W. Grimes 	int			pageout_status[VM_PAGEOUT_PAGE_COUNT];
14526f9a767SRodney W. Grimes 	vm_page_t		ms[VM_PAGEOUT_PAGE_COUNT];
14626f9a767SRodney W. Grimes 	int			pageout_count;
14726f9a767SRodney W. Grimes 	int			anyok=0;
14826f9a767SRodney W. Grimes 	int			i;
14926f9a767SRodney W. Grimes 	vm_offset_t offset = m->offset;
15026f9a767SRodney W. Grimes 
15126f9a767SRodney W. Grimes 	object = m->object;
15226f9a767SRodney W. Grimes 	if (!object) {
15326f9a767SRodney W. Grimes 		printf("pager: object missing\n");
15426f9a767SRodney W. Grimes 		return 0;
15526f9a767SRodney W. Grimes 	}
15626f9a767SRodney W. Grimes 
15726f9a767SRodney W. Grimes 	/*
15826f9a767SRodney W. Grimes 	 *	Try to collapse the object before
15926f9a767SRodney W. Grimes 	 *	making a pager for it.  We must
16026f9a767SRodney W. Grimes 	 *	unlock the page queues first.
16126f9a767SRodney W. Grimes 	 *	We try to defer the creation of a pager
16226f9a767SRodney W. Grimes 	 *	until all shadows are not paging.  This
16326f9a767SRodney W. Grimes 	 *	allows vm_object_collapse to work better and
16426f9a767SRodney W. Grimes 	 *	helps control swap space size.
16526f9a767SRodney W. Grimes 	 *	(J. Dyson 11 Nov 93)
16626f9a767SRodney W. Grimes 	 */
16726f9a767SRodney W. Grimes 
16826f9a767SRodney W. Grimes 	if (!object->pager &&
16926f9a767SRodney W. Grimes 		cnt.v_free_count < vm_pageout_free_min)
17026f9a767SRodney W. Grimes 		return 0;
17126f9a767SRodney W. Grimes 
17226f9a767SRodney W. Grimes 	if (!object->pager &&
17326f9a767SRodney W. Grimes 		object->shadow &&
17426f9a767SRodney W. Grimes 		object->shadow->paging_in_progress)
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 			if (!vm_page_lookup(object, offset))
18126f9a767SRodney W. Grimes 				return 0;
18226f9a767SRodney W. Grimes 		}
18326f9a767SRodney W. Grimes 
18426f9a767SRodney W. Grimes 		if ((m->flags & PG_BUSY) || (m->hold_count != 0)) {
18526f9a767SRodney W. Grimes 			return 0;
18626f9a767SRodney W. Grimes 		}
18726f9a767SRodney W. Grimes 	}
18826f9a767SRodney W. Grimes 
18926f9a767SRodney W. Grimes 	pageout_count = 1;
19026f9a767SRodney W. Grimes 	ms[0] = m;
19126f9a767SRodney W. Grimes 
19226f9a767SRodney W. Grimes 	if( pager = object->pager) {
19326f9a767SRodney W. Grimes 		for(i=1;i<VM_PAGEOUT_PAGE_COUNT;i++) {
19426f9a767SRodney W. Grimes 			if( ms[i] = vm_page_lookup( object, offset+i*NBPG)) {
19526f9a767SRodney W. Grimes 				if((((ms[i]->flags & (PG_CLEAN|PG_INACTIVE|PG_BUSY)) == PG_INACTIVE)
19626f9a767SRodney W. Grimes 					|| (( ms[i]->flags & PG_CLEAN) == 0 && sync == VM_PAGEOUT_FORCE))
19726f9a767SRodney W. Grimes 					&& (ms[i]->wire_count == 0)
19826f9a767SRodney W. Grimes 					&& (ms[i]->hold_count == 0))
19926f9a767SRodney W. Grimes 					pageout_count++;
20026f9a767SRodney W. Grimes 				else
20126f9a767SRodney W. Grimes 					break;
20226f9a767SRodney W. Grimes 			} else
20326f9a767SRodney W. Grimes 				break;
20426f9a767SRodney W. Grimes 		}
20526f9a767SRodney W. Grimes 		for(i=0;i<pageout_count;i++) {
20626f9a767SRodney W. Grimes 			ms[i]->flags |= PG_BUSY;
20726f9a767SRodney W. Grimes 			pmap_page_protect(VM_PAGE_TO_PHYS(ms[i]), VM_PROT_READ);
20826f9a767SRodney W. Grimes 		}
20926f9a767SRodney W. Grimes 		object->paging_in_progress += pageout_count;
21026f9a767SRodney W. Grimes 		cnt.v_pageouts += pageout_count;
21126f9a767SRodney W. Grimes 	} else {
21226f9a767SRodney W. Grimes 
21326f9a767SRodney W. Grimes 		m->flags |= PG_BUSY;
21426f9a767SRodney W. Grimes 
21526f9a767SRodney W. Grimes 		pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_READ);
21626f9a767SRodney W. Grimes 
21726f9a767SRodney W. Grimes 		cnt.v_pageouts++;
21826f9a767SRodney W. Grimes 
21926f9a767SRodney W. Grimes 		object->paging_in_progress++;
22026f9a767SRodney W. Grimes 
22126f9a767SRodney W. Grimes 		pager = vm_pager_allocate(PG_DFLT, (caddr_t)0,
22226f9a767SRodney W. Grimes 			object->size, VM_PROT_ALL, 0);
22326f9a767SRodney W. Grimes 		if (pager != NULL) {
22426f9a767SRodney W. Grimes 			vm_object_setpager(object, pager, 0, FALSE);
22526f9a767SRodney W. Grimes 		}
22626f9a767SRodney W. Grimes 	}
22726f9a767SRodney W. Grimes 
22826f9a767SRodney W. Grimes 	/*
22926f9a767SRodney W. Grimes 	 *	If there is no pager for the page,
23026f9a767SRodney W. Grimes 	 *	use the default pager.  If there's
23126f9a767SRodney W. Grimes 	 *	no place to put the page at the
23226f9a767SRodney W. Grimes 	 *	moment, leave it in the laundry and
23326f9a767SRodney W. Grimes 	 *	hope that there will be paging space
23426f9a767SRodney W. Grimes 	 *	later.
23526f9a767SRodney W. Grimes 	 */
23626f9a767SRodney W. Grimes 
23726f9a767SRodney W. Grimes 	if ((pager && pager->pg_type == PG_SWAP) ||
23826f9a767SRodney W. Grimes 		cnt.v_free_count >= vm_pageout_free_min) {
23926f9a767SRodney W. Grimes 		if( pageout_count == 1) {
24026f9a767SRodney W. Grimes 			pageout_status[0] = pager ?
24126f9a767SRodney W. Grimes 				vm_pager_put(pager, m,
24226f9a767SRodney W. Grimes 				    ((sync || (object == kernel_object)) ? TRUE: FALSE)) :
24326f9a767SRodney W. Grimes 				VM_PAGER_FAIL;
24426f9a767SRodney W. Grimes 		} else {
24526f9a767SRodney W. Grimes 			if( !pager) {
24626f9a767SRodney W. Grimes 				for(i=0;i<pageout_count;i++)
24726f9a767SRodney W. Grimes 					pageout_status[i] = VM_PAGER_FAIL;
24826f9a767SRodney W. Grimes 			} else {
24926f9a767SRodney W. Grimes 				vm_pager_put_pages(pager, ms, pageout_count,
25026f9a767SRodney W. Grimes 				    ((sync || (object == kernel_object)) ? TRUE : FALSE),
25126f9a767SRodney W. Grimes 				    pageout_status);
25226f9a767SRodney W. Grimes 			}
25326f9a767SRodney W. Grimes 		}
25426f9a767SRodney W. Grimes 
25526f9a767SRodney W. Grimes 	} else {
25626f9a767SRodney W. Grimes 		for(i=0;i<pageout_count;i++)
25726f9a767SRodney W. Grimes 			pageout_status[i] = VM_PAGER_FAIL;
25826f9a767SRodney W. Grimes 	}
25926f9a767SRodney W. Grimes 
26026f9a767SRodney W. Grimes 	for(i=0;i<pageout_count;i++) {
26126f9a767SRodney W. Grimes 		switch (pageout_status[i]) {
26226f9a767SRodney W. Grimes 		case VM_PAGER_OK:
26326f9a767SRodney W. Grimes 			ms[i]->flags &= ~PG_LAUNDRY;
26426f9a767SRodney W. Grimes 			++anyok;
26526f9a767SRodney W. Grimes 			break;
26626f9a767SRodney W. Grimes 		case VM_PAGER_PEND:
26726f9a767SRodney W. Grimes 			ms[i]->flags &= ~PG_LAUNDRY;
26826f9a767SRodney W. Grimes 			++anyok;
26926f9a767SRodney W. Grimes 			break;
27026f9a767SRodney W. Grimes 		case VM_PAGER_BAD:
27126f9a767SRodney W. Grimes 			/*
27226f9a767SRodney W. Grimes 			 * Page outside of range of object.
27326f9a767SRodney W. Grimes 			 * Right now we essentially lose the
27426f9a767SRodney W. Grimes 			 * changes by pretending it worked.
27526f9a767SRodney W. Grimes 			 */
27626f9a767SRodney W. Grimes 			ms[i]->flags &= ~PG_LAUNDRY;
27726f9a767SRodney W. Grimes 			ms[i]->flags |= PG_CLEAN;
27826f9a767SRodney W. Grimes 			pmap_clear_modify(VM_PAGE_TO_PHYS(ms[i]));
27926f9a767SRodney W. Grimes 			break;
28026f9a767SRodney W. Grimes 		case VM_PAGER_ERROR:
28126f9a767SRodney W. Grimes 		case VM_PAGER_FAIL:
28226f9a767SRodney W. Grimes 			/*
28326f9a767SRodney W. Grimes 			 * If page couldn't be paged out, then
28426f9a767SRodney W. Grimes 			 * reactivate the page so it doesn't
28526f9a767SRodney W. Grimes 			 * clog the inactive list.  (We will
28626f9a767SRodney W. Grimes 			 * try paging out it again later).
28726f9a767SRodney W. Grimes 			 */
28826f9a767SRodney W. Grimes 			if (ms[i]->flags & PG_INACTIVE)
28926f9a767SRodney W. Grimes 				vm_page_activate(ms[i]);
29026f9a767SRodney W. Grimes 			break;
29126f9a767SRodney W. Grimes 		case VM_PAGER_AGAIN:
29226f9a767SRodney W. Grimes 			break;
29326f9a767SRodney W. Grimes 		}
29426f9a767SRodney W. Grimes 
29526f9a767SRodney W. Grimes 
29626f9a767SRodney W. Grimes 		/*
29726f9a767SRodney W. Grimes 		 * If the operation is still going, leave
29826f9a767SRodney W. Grimes 		 * the page busy to block all other accesses.
29926f9a767SRodney W. Grimes 		 * Also, leave the paging in progress
30026f9a767SRodney W. Grimes 		 * indicator set so that we don't attempt an
30126f9a767SRodney W. Grimes 		 * object collapse.
30226f9a767SRodney W. Grimes 		 */
30326f9a767SRodney W. Grimes 		if (pageout_status[i] != VM_PAGER_PEND) {
30426f9a767SRodney W. Grimes 			PAGE_WAKEUP(ms[i]);
30526f9a767SRodney W. Grimes 			if (--object->paging_in_progress == 0)
30626f9a767SRodney W. Grimes 				wakeup((caddr_t) object);
30726f9a767SRodney W. Grimes 			if (pmap_is_referenced(VM_PAGE_TO_PHYS(ms[i]))) {
30826f9a767SRodney W. Grimes 				pmap_clear_reference(VM_PAGE_TO_PHYS(ms[i]));
30926f9a767SRodney W. Grimes 				if( ms[i]->flags & PG_INACTIVE)
31026f9a767SRodney W. Grimes 					vm_page_activate(ms[i]);
31126f9a767SRodney W. Grimes 			}
31226f9a767SRodney W. Grimes 		}
31326f9a767SRodney W. Grimes 	}
31426f9a767SRodney W. Grimes 	return anyok;
31526f9a767SRodney W. Grimes }
31626f9a767SRodney W. Grimes 
31726f9a767SRodney W. Grimes /*
31826f9a767SRodney W. Grimes  *	vm_pageout_object_deactivate_pages
31926f9a767SRodney W. Grimes  *
32026f9a767SRodney W. Grimes  *	deactivate enough pages to satisfy the inactive target
32126f9a767SRodney W. Grimes  *	requirements or if vm_page_proc_limit is set, then
32226f9a767SRodney W. Grimes  *	deactivate all of the pages in the object and its
32326f9a767SRodney W. Grimes  *	shadows.
32426f9a767SRodney W. Grimes  *
32526f9a767SRodney W. Grimes  *	The object and map must be locked.
32626f9a767SRodney W. Grimes  */
32726f9a767SRodney W. Grimes int
32826f9a767SRodney W. Grimes vm_pageout_object_deactivate_pages(map, object, count)
32926f9a767SRodney W. Grimes 	vm_map_t map;
33026f9a767SRodney W. Grimes 	vm_object_t object;
33126f9a767SRodney W. Grimes 	int count;
33226f9a767SRodney W. Grimes {
33326f9a767SRodney W. Grimes 	register vm_page_t	p, next;
33426f9a767SRodney W. Grimes 	int rcount;
33526f9a767SRodney W. Grimes 	int s;
33626f9a767SRodney W. Grimes 	int dcount;
33726f9a767SRodney W. Grimes 
33826f9a767SRodney W. Grimes 	dcount = 0;
33926f9a767SRodney W. Grimes 	if (count == 0)
34026f9a767SRodney W. Grimes 		count = 1;
34126f9a767SRodney W. Grimes 
34226f9a767SRodney W. Grimes 	if (object->shadow) {
34326f9a767SRodney W. Grimes 		int scount = count;
34426f9a767SRodney W. Grimes 		if( object->shadow->ref_count > 1)
34526f9a767SRodney W. Grimes 			scount /= object->shadow->ref_count;
34626f9a767SRodney W. Grimes 		if( scount)
34726f9a767SRodney W. Grimes 			dcount += vm_pageout_object_deactivate_pages(map, object->shadow, scount);
34826f9a767SRodney W. Grimes 	}
34926f9a767SRodney W. Grimes 
35026f9a767SRodney W. Grimes 	if (object->paging_in_progress)
35126f9a767SRodney W. Grimes 		return dcount;
35226f9a767SRodney W. Grimes 
35326f9a767SRodney W. Grimes 	/*
35426f9a767SRodney W. Grimes 	 * scan the objects entire memory queue
35526f9a767SRodney W. Grimes 	 */
35626f9a767SRodney W. Grimes 	rcount = object->resident_page_count;
35726f9a767SRodney W. Grimes 	p = object->memq.tqh_first;
35826f9a767SRodney W. Grimes 	while (p && (rcount-- > 0)) {
35926f9a767SRodney W. Grimes 		next = p->listq.tqe_next;
36026f9a767SRodney W. Grimes 		vm_page_lock_queues();
36126f9a767SRodney W. Grimes 		/*
36226f9a767SRodney W. Grimes 		 * if a page is active, not wired and is in the processes pmap,
36326f9a767SRodney W. Grimes 		 * then deactivate the page.
36426f9a767SRodney W. Grimes 		 */
36526f9a767SRodney W. Grimes 		if ((p->flags & (PG_ACTIVE|PG_BUSY)) == PG_ACTIVE &&
36626f9a767SRodney W. Grimes 			p->wire_count == 0 &&
36726f9a767SRodney W. Grimes 			p->hold_count == 0 &&
36826f9a767SRodney W. Grimes 			pmap_page_exists(vm_map_pmap(map), VM_PAGE_TO_PHYS(p))) {
36926f9a767SRodney W. Grimes 			if (!pmap_is_referenced(VM_PAGE_TO_PHYS(p))) {
37026f9a767SRodney W. Grimes 				p->act_count -= min(p->act_count, ACT_DECLINE);
37126f9a767SRodney W. Grimes 				/*
37226f9a767SRodney W. Grimes 				 * if the page act_count is zero -- then we deactivate
37326f9a767SRodney W. Grimes 				 */
37426f9a767SRodney W. Grimes 				if (!p->act_count) {
37526f9a767SRodney W. Grimes 					vm_page_deactivate(p);
37626f9a767SRodney W. Grimes 					pmap_page_protect(VM_PAGE_TO_PHYS(p),
37726f9a767SRodney W. Grimes 						VM_PROT_NONE);
37826f9a767SRodney W. Grimes 				/*
37926f9a767SRodney W. Grimes 				 * else if on the next go-around we will deactivate the page
38026f9a767SRodney W. Grimes 				 * we need to place the page on the end of the queue to age
38126f9a767SRodney W. Grimes 				 * the other pages in memory.
38226f9a767SRodney W. Grimes 				 */
38326f9a767SRodney W. Grimes 				} else {
38426f9a767SRodney W. Grimes 					TAILQ_REMOVE(&vm_page_queue_active, p, pageq);
38526f9a767SRodney W. Grimes 					TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq);
38626f9a767SRodney W. Grimes 					TAILQ_REMOVE(&object->memq, p, listq);
38726f9a767SRodney W. Grimes 					TAILQ_INSERT_TAIL(&object->memq, p, listq);
38826f9a767SRodney W. Grimes 				}
38926f9a767SRodney W. Grimes 				/*
39026f9a767SRodney W. Grimes 				 * see if we are done yet
39126f9a767SRodney W. Grimes 				 */
39226f9a767SRodney W. Grimes 				if (p->flags & PG_INACTIVE) {
39326f9a767SRodney W. Grimes 					--count;
39426f9a767SRodney W. Grimes 					++dcount;
39526f9a767SRodney W. Grimes 					if (count <= 0 &&
39626f9a767SRodney W. Grimes 						cnt.v_inactive_count > cnt.v_inactive_target) {
39726f9a767SRodney W. Grimes 							vm_page_unlock_queues();
39826f9a767SRodney W. Grimes 							return dcount;
39926f9a767SRodney W. Grimes 					}
40026f9a767SRodney W. Grimes 				}
40126f9a767SRodney W. Grimes 
40226f9a767SRodney W. Grimes 			} else {
40326f9a767SRodney W. Grimes 				/*
40426f9a767SRodney W. Grimes 				 * Move the page to the bottom of the queue.
40526f9a767SRodney W. Grimes 				 */
40626f9a767SRodney W. Grimes 				pmap_clear_reference(VM_PAGE_TO_PHYS(p));
40726f9a767SRodney W. Grimes 				if (p->act_count < ACT_MAX)
40826f9a767SRodney W. Grimes 					p->act_count += ACT_ADVANCE;
40926f9a767SRodney W. Grimes 
41026f9a767SRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_active, p, pageq);
41126f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&vm_page_queue_active, p, pageq);
41226f9a767SRodney W. Grimes 				TAILQ_REMOVE(&object->memq, p, listq);
41326f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&object->memq, p, listq);
41426f9a767SRodney W. Grimes 			}
41526f9a767SRodney W. Grimes 		}
41626f9a767SRodney W. Grimes 
41726f9a767SRodney W. Grimes 		vm_page_unlock_queues();
41826f9a767SRodney W. Grimes 		p = next;
41926f9a767SRodney W. Grimes 	}
42026f9a767SRodney W. Grimes 	return dcount;
42126f9a767SRodney W. Grimes }
42226f9a767SRodney W. Grimes 
42326f9a767SRodney W. Grimes 
42426f9a767SRodney W. Grimes /*
42526f9a767SRodney W. Grimes  * deactivate some number of pages in a map, try to do it fairly, but
42626f9a767SRodney W. Grimes  * that is really hard to do.
42726f9a767SRodney W. Grimes  */
42826f9a767SRodney W. Grimes 
42926f9a767SRodney W. Grimes void
43026f9a767SRodney W. Grimes vm_pageout_map_deactivate_pages(map, entry, count, freeer)
43126f9a767SRodney W. Grimes 	vm_map_t map;
43226f9a767SRodney W. Grimes 	vm_map_entry_t entry;
43326f9a767SRodney W. Grimes 	int *count;
43426f9a767SRodney W. Grimes 	int (*freeer)(vm_map_t, vm_object_t, int);
43526f9a767SRodney W. Grimes {
43626f9a767SRodney W. Grimes 	vm_map_t tmpm;
43726f9a767SRodney W. Grimes 	vm_map_entry_t tmpe;
43826f9a767SRodney W. Grimes 	vm_object_t obj;
43926f9a767SRodney W. Grimes 	if (*count <= 0)
44026f9a767SRodney W. Grimes 		return;
44126f9a767SRodney W. Grimes 	vm_map_reference(map);
44226f9a767SRodney W. Grimes 	if (!lock_try_read(&map->lock)) {
44326f9a767SRodney W. Grimes 		vm_map_deallocate(map);
44426f9a767SRodney W. Grimes 		return;
44526f9a767SRodney W. Grimes 	}
44626f9a767SRodney W. Grimes 	if (entry == 0) {
44726f9a767SRodney W. Grimes 		tmpe = map->header.next;
44826f9a767SRodney W. Grimes 		while (tmpe != &map->header && *count > 0) {
44926f9a767SRodney W. Grimes 			vm_pageout_map_deactivate_pages(map, tmpe, count, freeer);
45026f9a767SRodney W. Grimes 			tmpe = tmpe->next;
45126f9a767SRodney W. Grimes 		};
45226f9a767SRodney W. Grimes 	} else if (entry->is_sub_map || entry->is_a_map) {
45326f9a767SRodney W. Grimes 		tmpm = entry->object.share_map;
45426f9a767SRodney W. Grimes 		tmpe = tmpm->header.next;
45526f9a767SRodney W. Grimes 		while (tmpe != &tmpm->header && *count > 0) {
45626f9a767SRodney W. Grimes 			vm_pageout_map_deactivate_pages(tmpm, tmpe, count, freeer);
45726f9a767SRodney W. Grimes 			tmpe = tmpe->next;
45826f9a767SRodney W. Grimes 		};
45926f9a767SRodney W. Grimes 	} else if (obj = entry->object.vm_object) {
46026f9a767SRodney W. Grimes 		*count -= (*freeer)(map, obj, *count);
46126f9a767SRodney W. Grimes 	}
46226f9a767SRodney W. Grimes 	lock_read_done(&map->lock);
46326f9a767SRodney W. Grimes 	vm_map_deallocate(map);
46426f9a767SRodney W. Grimes 	return;
46526f9a767SRodney W. Grimes }
466df8bae1dSRodney W. Grimes 
467df8bae1dSRodney W. Grimes /*
468df8bae1dSRodney W. Grimes  *	vm_pageout_scan does the dirty work for the pageout daemon.
469df8bae1dSRodney W. Grimes  */
47026f9a767SRodney W. Grimes int
471df8bae1dSRodney W. Grimes vm_pageout_scan()
472df8bae1dSRodney W. Grimes {
47326f9a767SRodney W. Grimes 	vm_page_t	m;
47426f9a767SRodney W. Grimes 	int		page_shortage, maxscan, maxlaunder;
47526f9a767SRodney W. Grimes 	int		pages_freed, free, nproc;
47626f9a767SRodney W. Grimes 	int		desired_free;
47726f9a767SRodney W. Grimes 	vm_page_t	next;
47826f9a767SRodney W. Grimes 	struct proc	*p;
479df8bae1dSRodney W. Grimes 	vm_object_t	object;
48026f9a767SRodney W. Grimes 	int		s;
48126f9a767SRodney W. Grimes 	int		force_wakeup = 0;
482df8bae1dSRodney W. Grimes 
48326f9a767SRodney W. Grimes morefree:
484df8bae1dSRodney W. Grimes 	/*
48526f9a767SRodney W. Grimes 	 * scan the processes for exceeding their rlimits or if process
48626f9a767SRodney W. Grimes 	 * is swapped out -- deactivate pages
487df8bae1dSRodney W. Grimes 	 */
488df8bae1dSRodney W. Grimes 
48926f9a767SRodney W. Grimes rescanproc1:
49026f9a767SRodney W. Grimes 	for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
49126f9a767SRodney W. Grimes 		vm_offset_t size;
49226f9a767SRodney W. Grimes 		int overage;
49326f9a767SRodney W. Grimes 		vm_offset_t limit;
494df8bae1dSRodney W. Grimes 
495df8bae1dSRodney W. Grimes 		/*
49626f9a767SRodney W. Grimes 		 * if this is a system process or if we have already
49726f9a767SRodney W. Grimes 		 * looked at this process, skip it.
498df8bae1dSRodney W. Grimes 		 */
49926f9a767SRodney W. Grimes 		if (p->p_flag & (P_SYSTEM|P_WEXIT)) {
50026f9a767SRodney W. Grimes 			continue;
501df8bae1dSRodney W. Grimes 		}
502df8bae1dSRodney W. Grimes 
503df8bae1dSRodney W. Grimes 		/*
50426f9a767SRodney W. Grimes 		 * if the process is in a non-running type state,
50526f9a767SRodney W. Grimes 		 * don't touch it.
506df8bae1dSRodney W. Grimes 		 */
50726f9a767SRodney W. Grimes 		if (p->p_stat != SRUN && p->p_stat != SSLEEP) {
50826f9a767SRodney W. Grimes 			continue;
50926f9a767SRodney W. Grimes 		}
51026f9a767SRodney W. Grimes 
51126f9a767SRodney W. Grimes 		/*
51226f9a767SRodney W. Grimes 		 * get a limit
51326f9a767SRodney W. Grimes 		 */
51426f9a767SRodney W. Grimes 		limit = min(p->p_rlimit[RLIMIT_RSS].rlim_cur,
51526f9a767SRodney W. Grimes 			    p->p_rlimit[RLIMIT_RSS].rlim_max);
51626f9a767SRodney W. Grimes 
51726f9a767SRodney W. Grimes 		/*
51826f9a767SRodney W. Grimes 		 * let processes that are swapped out really be swapped out
51926f9a767SRodney W. Grimes 		 * set the limit to nothing (will force a swap-out.)
52026f9a767SRodney W. Grimes 		 */
52126f9a767SRodney W. Grimes 		if ((p->p_flag & P_INMEM) == 0)
52226f9a767SRodney W. Grimes 			limit = 0;
52326f9a767SRodney W. Grimes 
52426f9a767SRodney W. Grimes 		size = p->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG;
52526f9a767SRodney W. Grimes 		if (size >= limit) {
52626f9a767SRodney W. Grimes 			overage = (size - limit) / NBPG;
52726f9a767SRodney W. Grimes 			vm_pageout_map_deactivate_pages(&p->p_vmspace->vm_map,
52826f9a767SRodney W. Grimes 				(vm_map_entry_t) 0, &overage, vm_pageout_object_deactivate_pages);
52926f9a767SRodney W. Grimes 		}
53026f9a767SRodney W. Grimes 
53126f9a767SRodney W. Grimes 	}
53226f9a767SRodney W. Grimes 
53326f9a767SRodney W. Grimes 	if (((cnt.v_free_count + cnt.v_inactive_count) >=
53426f9a767SRodney W. Grimes 		(cnt.v_inactive_target + cnt.v_free_target)) &&
53526f9a767SRodney W. Grimes 		(cnt.v_free_count >= cnt.v_free_target))
53626f9a767SRodney W. Grimes 		return force_wakeup;
53726f9a767SRodney W. Grimes 
53826f9a767SRodney W. Grimes 	pages_freed = 0;
53926f9a767SRodney W. Grimes 	desired_free = cnt.v_free_target;
540df8bae1dSRodney W. Grimes 
541df8bae1dSRodney W. Grimes 	/*
542df8bae1dSRodney W. Grimes 	 *	Start scanning the inactive queue for pages we can free.
543df8bae1dSRodney W. Grimes 	 *	We keep scanning until we have enough free pages or
544df8bae1dSRodney W. Grimes 	 *	we have scanned through the entire queue.  If we
545df8bae1dSRodney W. Grimes 	 *	encounter dirty pages, we start cleaning them.
546df8bae1dSRodney W. Grimes 	 */
547df8bae1dSRodney W. Grimes 
54826f9a767SRodney W. Grimes 	maxlaunder = (cnt.v_free_target - cnt.v_free_count);
54926f9a767SRodney W. Grimes 	maxscan = cnt.v_inactive_count;
55026f9a767SRodney W. Grimes rescan1:
55126f9a767SRodney W. Grimes 	m = vm_page_queue_inactive.tqh_first;
55226f9a767SRodney W. Grimes 	while (m && (maxscan-- > 0) &&
55326f9a767SRodney W. Grimes 		(cnt.v_free_count < desired_free) ) {
55426f9a767SRodney W. Grimes 		vm_page_t	next;
555df8bae1dSRodney W. Grimes 
556df8bae1dSRodney W. Grimes 		next = m->pageq.tqe_next;
557df8bae1dSRodney W. Grimes 
55826f9a767SRodney W. Grimes 		if( (m->flags & PG_INACTIVE) == 0) {
55926f9a767SRodney W. Grimes 			printf("vm_pageout_scan: page not inactive?");
560df8bae1dSRodney W. Grimes 			continue;
561df8bae1dSRodney W. Grimes 		}
562df8bae1dSRodney W. Grimes 
563df8bae1dSRodney W. Grimes 		/*
56426f9a767SRodney W. Grimes 		 * activate held pages
56526f9a767SRodney W. Grimes 		 */
56626f9a767SRodney W. Grimes 		if (m->hold_count != 0) {
56726f9a767SRodney W. Grimes 			vm_page_activate(m);
56826f9a767SRodney W. Grimes 			m = next;
56926f9a767SRodney W. Grimes 			continue;
57026f9a767SRodney W. Grimes 		}
57126f9a767SRodney W. Grimes 
57226f9a767SRodney W. Grimes 		/*
57326f9a767SRodney W. Grimes 		 * dont mess with busy pages
57426f9a767SRodney W. Grimes 		 */
57526f9a767SRodney W. Grimes 		if (m->flags & PG_BUSY) {
57626f9a767SRodney W. Grimes 			m = next;
57726f9a767SRodney W. Grimes 			continue;
57826f9a767SRodney W. Grimes 		}
57926f9a767SRodney W. Grimes 
58026f9a767SRodney W. Grimes 		/*
58126f9a767SRodney W. Grimes 		 * if page is clean and but the page has been referenced,
58226f9a767SRodney W. Grimes 		 * then reactivate the page, but if we are very low on memory
58326f9a767SRodney W. Grimes 		 * or the page has not been referenced, then we free it to the
58426f9a767SRodney W. Grimes 		 * vm system.
585df8bae1dSRodney W. Grimes 		 */
586df8bae1dSRodney W. Grimes 		if (m->flags & PG_CLEAN) {
58726f9a767SRodney W. Grimes 			if ((cnt.v_free_count > vm_pageout_free_min)			/* XXX */
58826f9a767SRodney W. Grimes 				&& pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
58926f9a767SRodney W. Grimes 				vm_page_activate(m);
59026f9a767SRodney W. Grimes 			} else if (!m->act_count) {
591df8bae1dSRodney W. Grimes 				pmap_page_protect(VM_PAGE_TO_PHYS(m),
592df8bae1dSRodney W. Grimes 						  VM_PROT_NONE);
593df8bae1dSRodney W. Grimes 				vm_page_free(m);
59426f9a767SRodney W. Grimes 				++pages_freed;
59526f9a767SRodney W. Grimes 			} else {
59626f9a767SRodney W. Grimes 				m->act_count -= min(m->act_count, ACT_DECLINE);
59726f9a767SRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq);
59826f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&vm_page_queue_inactive, m, pageq);
599df8bae1dSRodney W. Grimes 			}
60026f9a767SRodney W. Grimes 		} else if ((m->flags & PG_LAUNDRY) && maxlaunder > 0) {
60126f9a767SRodney W. Grimes 			int written;
60226f9a767SRodney W. Grimes 			if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
60326f9a767SRodney W. Grimes 				pmap_clear_reference(VM_PAGE_TO_PHYS(m));
60426f9a767SRodney W. Grimes 				vm_page_activate(m);
60526f9a767SRodney W. Grimes 				m = next;
606df8bae1dSRodney W. Grimes 				continue;
607df8bae1dSRodney W. Grimes 			}
608df8bae1dSRodney W. Grimes 			/*
60926f9a767SRodney W. Grimes 			 *	If a page is dirty, then it is either
61026f9a767SRodney W. Grimes 			 *	being washed (but not yet cleaned)
61126f9a767SRodney W. Grimes 			 *	or it is still in the laundry.  If it is
61226f9a767SRodney W. Grimes 			 *	still in the laundry, then we start the
61326f9a767SRodney W. Grimes 			 *	cleaning operation.
614df8bae1dSRodney W. Grimes 			 */
615df8bae1dSRodney W. Grimes 
61626f9a767SRodney W. Grimes 			if (written = vm_pageout_clean(m,0)) {
61726f9a767SRodney W. Grimes 				maxlaunder -= written;
61826f9a767SRodney W. Grimes 			}
619df8bae1dSRodney W. Grimes 			/*
62026f9a767SRodney W. Grimes 			 * if the next page has been re-activated, start scanning again
621df8bae1dSRodney W. Grimes 			 */
622df8bae1dSRodney W. Grimes 			if (next && (next->flags & PG_INACTIVE) == 0)
62326f9a767SRodney W. Grimes 				goto rescan1;
62426f9a767SRodney W. Grimes 		} else if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
62526f9a767SRodney W. Grimes 			pmap_clear_reference(VM_PAGE_TO_PHYS(m));
62626f9a767SRodney W. Grimes 			vm_page_activate(m);
62726f9a767SRodney W. Grimes 		}
62826f9a767SRodney W. Grimes 		m = next;
62926f9a767SRodney W. Grimes 	}
63026f9a767SRodney W. Grimes 
63126f9a767SRodney W. Grimes 	/*
63226f9a767SRodney W. Grimes 	 * now check malloc area or swap processes out if we are in low
63326f9a767SRodney W. Grimes 	 * memory conditions
63426f9a767SRodney W. Grimes 	 */
63526f9a767SRodney W. Grimes 	if (cnt.v_free_count <= cnt.v_free_min) {
63626f9a767SRodney W. Grimes 		/*
63726f9a767SRodney W. Grimes 		 * swap out inactive processes
63826f9a767SRodney W. Grimes 		 */
63926f9a767SRodney W. Grimes 		swapout_threads();
640df8bae1dSRodney W. Grimes 	}
641df8bae1dSRodney W. Grimes 
642df8bae1dSRodney W. Grimes 	/*
643df8bae1dSRodney W. Grimes 	 *	Compute the page shortage.  If we are still very low on memory
644df8bae1dSRodney W. Grimes 	 *	be sure that we will move a minimal amount of pages from active
645df8bae1dSRodney W. Grimes 	 *	to inactive.
646df8bae1dSRodney W. Grimes 	 */
647df8bae1dSRodney W. Grimes 
64826f9a767SRodney W. Grimes 	page_shortage = cnt.v_inactive_target -
64926f9a767SRodney W. Grimes 	    (cnt.v_free_count + cnt.v_inactive_count);
65026f9a767SRodney W. Grimes 
65126f9a767SRodney W. Grimes 	if (page_shortage <= 0) {
65226f9a767SRodney W. Grimes 		if (pages_freed == 0) {
65326f9a767SRodney W. Grimes 			if( cnt.v_free_count < cnt.v_free_min) {
65426f9a767SRodney W. Grimes 				page_shortage = cnt.v_free_min - cnt.v_free_count;
65526f9a767SRodney W. Grimes 			} else if(((cnt.v_free_count + cnt.v_inactive_count) <
65626f9a767SRodney W. Grimes 				(cnt.v_free_min + cnt.v_inactive_target))) {
657df8bae1dSRodney W. Grimes 				page_shortage = 1;
65826f9a767SRodney W. Grimes 			} else {
65926f9a767SRodney W. Grimes 				page_shortage = 0;
66026f9a767SRodney W. Grimes 			}
661df8bae1dSRodney W. Grimes 		}
662df8bae1dSRodney W. Grimes 
663df8bae1dSRodney W. Grimes 	}
664df8bae1dSRodney W. Grimes 
66526f9a767SRodney W. Grimes 	maxscan = cnt.v_active_count;
66626f9a767SRodney W. Grimes 	m = vm_page_queue_active.tqh_first;
66726f9a767SRodney W. Grimes 	while (m && maxscan-- && (page_shortage > 0)) {
66826f9a767SRodney W. Grimes 
66926f9a767SRodney W. Grimes 		next = m->pageq.tqe_next;
670df8bae1dSRodney W. Grimes 
671df8bae1dSRodney W. Grimes 		/*
67226f9a767SRodney W. Grimes  		 * Don't deactivate pages that are busy.
673df8bae1dSRodney W. Grimes 		 */
67426f9a767SRodney W. Grimes 		if ((m->flags & PG_BUSY) || (m->hold_count != 0)) {
67526f9a767SRodney W. Grimes 			m = next;
67626f9a767SRodney W. Grimes 			continue;
677df8bae1dSRodney W. Grimes 		}
678df8bae1dSRodney W. Grimes 
67926f9a767SRodney W. Grimes 		if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
680df8bae1dSRodney W. Grimes 			pmap_clear_reference(VM_PAGE_TO_PHYS(m));
68126f9a767SRodney W. Grimes 			if (m->act_count < ACT_MAX)
68226f9a767SRodney W. Grimes 				m->act_count += ACT_ADVANCE;
68326f9a767SRodney W. Grimes 			TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
68426f9a767SRodney W. Grimes 			TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq);
68526f9a767SRodney W. Grimes 			TAILQ_REMOVE(&m->object->memq, m, listq);
68626f9a767SRodney W. Grimes 			TAILQ_INSERT_TAIL(&m->object->memq, m, listq);
68726f9a767SRodney W. Grimes 		} else {
68826f9a767SRodney W. Grimes 			m->act_count -= min(m->act_count, ACT_DECLINE);
689df8bae1dSRodney W. Grimes 
690df8bae1dSRodney W. Grimes 			/*
69126f9a767SRodney W. Grimes 			 * if the page act_count is zero -- then we deactivate
692df8bae1dSRodney W. Grimes 			 */
69326f9a767SRodney W. Grimes 			if (!m->act_count) {
69426f9a767SRodney W. Grimes 				vm_page_deactivate(m);
69526f9a767SRodney W. Grimes 				--page_shortage;
69626f9a767SRodney W. Grimes 			/*
69726f9a767SRodney W. Grimes 			 * else if on the next go-around we will deactivate the page
69826f9a767SRodney W. Grimes 			 * we need to place the page on the end of the queue to age
69926f9a767SRodney W. Grimes 			 * the other pages in memory.
70026f9a767SRodney W. Grimes 			 */
70126f9a767SRodney W. Grimes 			} else {
70226f9a767SRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
70326f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq);
70426f9a767SRodney W. Grimes 				TAILQ_REMOVE(&m->object->memq, m, listq);
70526f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&m->object->memq, m, listq);
706df8bae1dSRodney W. Grimes 			}
707df8bae1dSRodney W. Grimes 		}
708df8bae1dSRodney W. Grimes 
70926f9a767SRodney W. Grimes 		m = next;
71026f9a767SRodney W. Grimes 	}
711df8bae1dSRodney W. Grimes 
712df8bae1dSRodney W. Grimes 	/*
71326f9a767SRodney W. Grimes 	 * if we have not freed any pages and we are desparate for memory
71426f9a767SRodney W. Grimes 	 * then we keep trying until we get some (any) memory.
715df8bae1dSRodney W. Grimes 	 */
71626f9a767SRodney W. Grimes 
71726f9a767SRodney W. Grimes 	if( !force_wakeup && (swap_pager_full || !force_wakeup ||
71826f9a767SRodney W. Grimes 		(pages_freed == 0 && (cnt.v_free_count < cnt.v_free_min)))){
71926f9a767SRodney W. Grimes 		vm_pager_sync();
72026f9a767SRodney W. Grimes 		force_wakeup = 1;
72126f9a767SRodney W. Grimes 		goto morefree;
72226f9a767SRodney W. Grimes 	}
72326f9a767SRodney W. Grimes 	vm_page_pagesfreed += pages_freed;
72426f9a767SRodney W. Grimes 	return force_wakeup;
72526f9a767SRodney W. Grimes }
72626f9a767SRodney W. Grimes 
727df8bae1dSRodney W. Grimes void
72826f9a767SRodney W. Grimes vm_pagescan()
729df8bae1dSRodney W. Grimes {
73026f9a767SRodney W. Grimes 	int maxscan, pages_scanned, pages_referenced, nextscan, scantick = hz/20;
73126f9a767SRodney W. Grimes 	int m_ref, next_ref;
73226f9a767SRodney W. Grimes 	vm_page_t m, next;
73326f9a767SRodney W. Grimes 
73426f9a767SRodney W. Grimes 	(void) spl0();
73526f9a767SRodney W. Grimes 
73626f9a767SRodney W. Grimes 	nextscan = scantick;
73726f9a767SRodney W. Grimes 
73826f9a767SRodney W. Grimes scanloop:
73926f9a767SRodney W. Grimes 
74026f9a767SRodney W. Grimes 	pages_scanned = 0;
74126f9a767SRodney W. Grimes 	pages_referenced = 0;
74226f9a767SRodney W. Grimes 	maxscan = min(cnt.v_active_count, MAXSCAN);
743df8bae1dSRodney W. Grimes 
744df8bae1dSRodney W. Grimes 	/*
74526f9a767SRodney W. Grimes 	 * Gather statistics on page usage.
746df8bae1dSRodney W. Grimes 	 */
74726f9a767SRodney W. Grimes 	m = vm_page_queue_active.tqh_first;
74826f9a767SRodney W. Grimes 	while (m && (maxscan-- > 0)) {
74926f9a767SRodney W. Grimes 
75026f9a767SRodney W. Grimes 		++pages_scanned;
75126f9a767SRodney W. Grimes 
75226f9a767SRodney W. Grimes 		next = m->pageq.tqe_next;
75326f9a767SRodney W. Grimes 
75426f9a767SRodney W. Grimes 		/*
75526f9a767SRodney W. Grimes  		 * Dont mess with pages that are busy.
75626f9a767SRodney W. Grimes 		 */
75726f9a767SRodney W. Grimes 		if ((m->flags & PG_BUSY) || (m->hold_count != 0)) {
75826f9a767SRodney W. Grimes 			TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
75926f9a767SRodney W. Grimes 			TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq);
76026f9a767SRodney W. Grimes 			m = next;
76126f9a767SRodney W. Grimes 			continue;
762df8bae1dSRodney W. Grimes 		}
763df8bae1dSRodney W. Grimes 
764df8bae1dSRodney W. Grimes 		/*
76526f9a767SRodney W. Grimes 		 * Advance pages that have been referenced, decline pages that
76626f9a767SRodney W. Grimes 		 * have not.
767df8bae1dSRodney W. Grimes 		 */
76826f9a767SRodney W. Grimes 		if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
76926f9a767SRodney W. Grimes 			pmap_clear_reference(VM_PAGE_TO_PHYS(m));
77026f9a767SRodney W. Grimes 			pages_referenced++;
77126f9a767SRodney W. Grimes 			if (m->act_count < ACT_MAX)
77226f9a767SRodney W. Grimes 				m->act_count += ACT_ADVANCE;
77326f9a767SRodney W. Grimes 			TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
77426f9a767SRodney W. Grimes 			TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq);
77526f9a767SRodney W. Grimes 			TAILQ_REMOVE(&m->object->memq, m, listq);
77626f9a767SRodney W. Grimes 			TAILQ_INSERT_TAIL(&m->object->memq, m, listq);
77726f9a767SRodney W. Grimes 		} else {
77826f9a767SRodney W. Grimes 			m->act_count -= min(m->act_count, ACT_DECLINE);
779df8bae1dSRodney W. Grimes 			/*
78026f9a767SRodney W. Grimes 			 * if the page act_count is zero, and we are low on mem -- then we deactivate
781df8bae1dSRodney W. Grimes 			 */
78226f9a767SRodney W. Grimes 			if (!m->act_count &&
78326f9a767SRodney W. Grimes 			    (cnt.v_free_count+cnt.v_inactive_count < cnt.v_free_target+cnt.v_inactive_target )) {
78426f9a767SRodney W. Grimes 				vm_page_deactivate(m);
785df8bae1dSRodney W. Grimes 			/*
78626f9a767SRodney W. Grimes 			 * else if on the next go-around we will deactivate the page
78726f9a767SRodney W. Grimes 			 * we need to place the page on the end of the queue to age
78826f9a767SRodney W. Grimes 			 * the other pages in memory.
789df8bae1dSRodney W. Grimes 			 */
79026f9a767SRodney W. Grimes 			} else {
79126f9a767SRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
79226f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&vm_page_queue_active, m, pageq);
79326f9a767SRodney W. Grimes 				TAILQ_REMOVE(&m->object->memq, m, listq);
79426f9a767SRodney W. Grimes 				TAILQ_INSERT_TAIL(&m->object->memq, m, listq);
795df8bae1dSRodney W. Grimes 			}
796df8bae1dSRodney W. Grimes 		}
79726f9a767SRodney W. Grimes 		m = next;
798df8bae1dSRodney W. Grimes 	}
79926f9a767SRodney W. Grimes 
80026f9a767SRodney W. Grimes 	if (pages_referenced) {
80126f9a767SRodney W. Grimes 		nextscan = (pages_scanned / pages_referenced) * scantick;
80226f9a767SRodney W. Grimes 		nextscan = max(nextscan, scantick);
80326f9a767SRodney W. Grimes 		nextscan = min(nextscan, hz);
80426f9a767SRodney W. Grimes 	} else
80526f9a767SRodney W. Grimes 		nextscan = hz;
80626f9a767SRodney W. Grimes 	tsleep((caddr_t) &vm_pagescanner, PVM, "scanw", nextscan);
80726f9a767SRodney W. Grimes 
80826f9a767SRodney W. Grimes 	goto scanloop;
80926f9a767SRodney W. Grimes }
810df8bae1dSRodney W. Grimes 
811df8bae1dSRodney W. Grimes /*
812df8bae1dSRodney W. Grimes  *	vm_pageout is the high level pageout daemon.
813df8bae1dSRodney W. Grimes  */
81426f9a767SRodney W. Grimes void
81526f9a767SRodney W. Grimes vm_pageout()
816df8bae1dSRodney W. Grimes {
81726f9a767SRodney W. Grimes 	extern npendingio, swiopend;
81826f9a767SRodney W. Grimes 	static nowakeup;
819df8bae1dSRodney W. Grimes 	(void) spl0();
820df8bae1dSRodney W. Grimes 
821df8bae1dSRodney W. Grimes 	/*
822df8bae1dSRodney W. Grimes 	 *	Initialize some paging parameters.
823df8bae1dSRodney W. Grimes 	 */
824df8bae1dSRodney W. Grimes 
82526f9a767SRodney W. Grimes vmretry:
82626f9a767SRodney W. Grimes 	cnt.v_free_min = 12;
82726f9a767SRodney W. Grimes 	cnt.v_free_reserved = 8;
82826f9a767SRodney W. Grimes 	if (cnt.v_free_min < 8)
82926f9a767SRodney W. Grimes 		cnt.v_free_min = 8;
83026f9a767SRodney W. Grimes 	if (cnt.v_free_min > 32)
83126f9a767SRodney W. Grimes 		cnt.v_free_min = 32;
83226f9a767SRodney W. Grimes 	vm_pageout_free_min = 4;
83326f9a767SRodney W. Grimes 	cnt.v_free_target = 2*cnt.v_free_min + cnt.v_free_reserved;
83426f9a767SRodney W. Grimes 	cnt.v_inactive_target = cnt.v_free_count / 12;
83526f9a767SRodney W. Grimes 	cnt.v_free_min += cnt.v_free_reserved;
836df8bae1dSRodney W. Grimes 
837df8bae1dSRodney W. Grimes         /* XXX does not really belong here */
838df8bae1dSRodney W. Grimes 	if (vm_page_max_wired == 0)
839df8bae1dSRodney W. Grimes 		vm_page_max_wired = cnt.v_free_count / 3;
840df8bae1dSRodney W. Grimes 
84126f9a767SRodney W. Grimes 
84226f9a767SRodney W. Grimes 	(void) swap_pager_alloc(0, 0, 0, 0);
84326f9a767SRodney W. Grimes 
844df8bae1dSRodney W. Grimes 	/*
845df8bae1dSRodney W. Grimes 	 *	The pageout daemon is never done, so loop
846df8bae1dSRodney W. Grimes 	 *	forever.
847df8bae1dSRodney W. Grimes 	 */
848df8bae1dSRodney W. Grimes 	while (TRUE) {
84926f9a767SRodney W. Grimes 		int force_wakeup;
85026f9a767SRodney W. Grimes 		extern struct loadavg averunnable;
851df8bae1dSRodney W. Grimes /*
85226f9a767SRodney W. Grimes 		cnt.v_free_min = 12 + averunnable.ldavg[0] / 1024;
85326f9a767SRodney W. Grimes 		cnt.v_free_target = 2*cnt.v_free_min + cnt.v_free_reserved;
85426f9a767SRodney W. Grimes 		cnt.v_inactive_target = cnt.v_free_target*2;
855df8bae1dSRodney W. Grimes */
856df8bae1dSRodney W. Grimes 
85726f9a767SRodney W. Grimes 		tsleep((caddr_t) &vm_pages_needed, PVM, "psleep", 0);
85826f9a767SRodney W. Grimes 
859df8bae1dSRodney W. Grimes 		vm_pager_sync();
86026f9a767SRodney W. Grimes 		/*
86126f9a767SRodney W. Grimes 		 * The force wakeup hack added to eliminate delays and potiential
86226f9a767SRodney W. Grimes 		 * deadlock.  It was possible for the page daemon to indefintely
86326f9a767SRodney W. Grimes 		 * postpone waking up a process that it might be waiting for memory
86426f9a767SRodney W. Grimes 		 * on.  The putmulti stuff seems to have aggravated the situation.
86526f9a767SRodney W. Grimes 		 */
86626f9a767SRodney W. Grimes 		force_wakeup = vm_pageout_scan();
86726f9a767SRodney W. Grimes 		vm_pager_sync();
86826f9a767SRodney W. Grimes 		if( force_wakeup)
86926f9a767SRodney W. Grimes 			wakeup( (caddr_t) &cnt.v_free_count);
87026f9a767SRodney W. Grimes 		cnt.v_scan++;
87126f9a767SRodney W. Grimes 		wakeup((caddr_t) kmem_map);
872df8bae1dSRodney W. Grimes 	}
873df8bae1dSRodney W. Grimes }
87426f9a767SRodney W. Grimes 
875