xref: /freebsd/sys/vm/vm_fault.c (revision 2d8acc0f4aee0ac81e6a065fad89c82c6237faf5)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1991, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  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.
826f9a767SRodney W. Grimes  *
9df8bae1dSRodney W. Grimes  *
10df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
11df8bae1dSRodney W. Grimes  * The Mach Operating System project at Carnegie-Mellon University.
12df8bae1dSRodney W. Grimes  *
13df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
14df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
15df8bae1dSRodney W. Grimes  * are met:
16df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
17df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
18df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
19df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
20df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
21df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
22df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
23df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
24df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
25df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
26df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
27df8bae1dSRodney W. Grimes  *    without specific prior written permission.
28df8bae1dSRodney W. Grimes  *
29df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
40df8bae1dSRodney W. Grimes  *
413c4dd356SDavid Greenman  *	from: @(#)vm_fault.c	8.4 (Berkeley) 1/12/94
42df8bae1dSRodney W. Grimes  *
43df8bae1dSRodney W. Grimes  *
44df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
45df8bae1dSRodney W. Grimes  * All rights reserved.
46df8bae1dSRodney W. Grimes  *
47df8bae1dSRodney W. Grimes  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
48df8bae1dSRodney W. Grimes  *
49df8bae1dSRodney W. Grimes  * Permission to use, copy, modify and distribute this software and
50df8bae1dSRodney W. Grimes  * its documentation is hereby granted, provided that both the copyright
51df8bae1dSRodney W. Grimes  * notice and this permission notice appear in all copies of the
52df8bae1dSRodney W. Grimes  * software, derivative works or modified versions, and any portions
53df8bae1dSRodney W. Grimes  * thereof, and that both notices appear in supporting documentation.
54df8bae1dSRodney W. Grimes  *
55df8bae1dSRodney W. Grimes  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
56df8bae1dSRodney W. Grimes  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
57df8bae1dSRodney W. Grimes  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
58df8bae1dSRodney W. Grimes  *
59df8bae1dSRodney W. Grimes  * Carnegie Mellon requests users of this software to return to
60df8bae1dSRodney W. Grimes  *
61df8bae1dSRodney W. Grimes  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
62df8bae1dSRodney W. Grimes  *  School of Computer Science
63df8bae1dSRodney W. Grimes  *  Carnegie Mellon University
64df8bae1dSRodney W. Grimes  *  Pittsburgh PA 15213-3890
65df8bae1dSRodney W. Grimes  *
66df8bae1dSRodney W. Grimes  * any improvements or extensions that they make and grant Carnegie the
67df8bae1dSRodney W. Grimes  * rights to redistribute these changes.
683c4dd356SDavid Greenman  *
692d8acc0fSJohn Dyson  * $Id: vm_fault.c,v 1.75 1998/01/17 09:16:49 dyson Exp $
70df8bae1dSRodney W. Grimes  */
71df8bae1dSRodney W. Grimes 
72df8bae1dSRodney W. Grimes /*
73df8bae1dSRodney W. Grimes  *	Page fault handling module.
74df8bae1dSRodney W. Grimes  */
75df8bae1dSRodney W. Grimes 
76df8bae1dSRodney W. Grimes #include <sys/param.h>
77df8bae1dSRodney W. Grimes #include <sys/systm.h>
7826f9a767SRodney W. Grimes #include <sys/proc.h>
7924a1cce3SDavid Greenman #include <sys/vnode.h>
8026f9a767SRodney W. Grimes #include <sys/resourcevar.h>
81efeaf95aSDavid Greenman #include <sys/vmmeter.h>
82df8bae1dSRodney W. Grimes 
83df8bae1dSRodney W. Grimes #include <vm/vm.h>
84efeaf95aSDavid Greenman #include <vm/vm_param.h>
85efeaf95aSDavid Greenman #include <vm/vm_prot.h>
86996c772fSJohn Dyson #include <sys/lock.h>
87efeaf95aSDavid Greenman #include <vm/pmap.h>
88efeaf95aSDavid Greenman #include <vm/vm_map.h>
89efeaf95aSDavid Greenman #include <vm/vm_object.h>
90df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
91df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h>
92a83c285cSDavid Greenman #include <vm/vm_kern.h>
9324a1cce3SDavid Greenman #include <vm/vm_pager.h>
9424a1cce3SDavid Greenman #include <vm/vnode_pager.h>
95efeaf95aSDavid Greenman #include <vm/vm_extern.h>
96df8bae1dSRodney W. Grimes 
9722ba64e8SJohn Dyson int vm_fault_additional_pages __P((vm_page_t, int, int, vm_page_t *, int *));
9826f9a767SRodney W. Grimes 
9947221757SJohn Dyson #define VM_FAULT_READ_AHEAD 8
10047221757SJohn Dyson #define VM_FAULT_READ_BEHIND 7
10126f9a767SRodney W. Grimes #define VM_FAULT_READ (VM_FAULT_READ_AHEAD+VM_FAULT_READ_BEHIND+1)
10226f9a767SRodney W. Grimes 
103df8bae1dSRodney W. Grimes /*
104df8bae1dSRodney W. Grimes  *	vm_fault:
105df8bae1dSRodney W. Grimes  *
106df8bae1dSRodney W. Grimes  *	Handle a page fault occuring at the given address,
107df8bae1dSRodney W. Grimes  *	requiring the given permissions, in the map specified.
108df8bae1dSRodney W. Grimes  *	If successful, the page is inserted into the
109df8bae1dSRodney W. Grimes  *	associated physical map.
110df8bae1dSRodney W. Grimes  *
111df8bae1dSRodney W. Grimes  *	NOTE: the given address should be truncated to the
112df8bae1dSRodney W. Grimes  *	proper page address.
113df8bae1dSRodney W. Grimes  *
114df8bae1dSRodney W. Grimes  *	KERN_SUCCESS is returned if the page fault is handled; otherwise,
115df8bae1dSRodney W. Grimes  *	a standard error specifying why the fault is fatal is returned.
116df8bae1dSRodney W. Grimes  *
117df8bae1dSRodney W. Grimes  *
118df8bae1dSRodney W. Grimes  *	The map in question must be referenced, and remains so.
119df8bae1dSRodney W. Grimes  *	Caller may hold no locks.
120df8bae1dSRodney W. Grimes  */
121df8bae1dSRodney W. Grimes int
122b9dcd593SBruce Evans vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, int fault_flags)
123df8bae1dSRodney W. Grimes {
124df8bae1dSRodney W. Grimes 	vm_object_t first_object;
125a316d390SJohn Dyson 	vm_pindex_t first_pindex;
126df8bae1dSRodney W. Grimes 	vm_map_entry_t entry;
127df8bae1dSRodney W. Grimes 	register vm_object_t object;
128a316d390SJohn Dyson 	register vm_pindex_t pindex;
12926f9a767SRodney W. Grimes 	vm_page_t m;
130df8bae1dSRodney W. Grimes 	vm_page_t first_m;
131df8bae1dSRodney W. Grimes 	vm_prot_t prot;
132df8bae1dSRodney W. Grimes 	int result;
133df8bae1dSRodney W. Grimes 	boolean_t wired;
134df8bae1dSRodney W. Grimes 	boolean_t lookup_still_valid;
1352d8acc0fSJohn Dyson 	int map_generation;
136df8bae1dSRodney W. Grimes 	vm_page_t old_m;
137df8bae1dSRodney W. Grimes 	vm_object_t next_object;
13826f9a767SRodney W. Grimes 	vm_page_t marray[VM_FAULT_READ];
13926f9a767SRodney W. Grimes 	int hardfault = 0;
1402d8acc0fSJohn Dyson 	int faultcount;
141f6b04d2bSDavid Greenman 	struct vnode *vp = NULL;
142996c772fSJohn Dyson 	struct proc *p = curproc;	/* XXX */
143df8bae1dSRodney W. Grimes 
144b8d95f16SDavid Greenman 	cnt.v_vm_faults++;	/* needs lock XXX */
145df8bae1dSRodney W. Grimes /*
146df8bae1dSRodney W. Grimes  *	Recovery actions
147df8bae1dSRodney W. Grimes  */
148df8bae1dSRodney W. Grimes #define	FREE_PAGE(m)	{				\
149df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);					\
150df8bae1dSRodney W. Grimes 	vm_page_free(m);				\
151df8bae1dSRodney W. Grimes }
152df8bae1dSRodney W. Grimes 
153df8bae1dSRodney W. Grimes #define	RELEASE_PAGE(m)	{				\
154df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);					\
15547221757SJohn Dyson 	if (m->queue != PQ_ACTIVE) { \
15647221757SJohn Dyson 		vm_page_activate(m);		\
15747221757SJohn Dyson 		m->act_count = 0; \
15847221757SJohn Dyson 	} \
159df8bae1dSRodney W. Grimes }
160df8bae1dSRodney W. Grimes 
161df8bae1dSRodney W. Grimes #define	UNLOCK_MAP	{				\
162df8bae1dSRodney W. Grimes 	if (lookup_still_valid) {			\
163df8bae1dSRodney W. Grimes 		vm_map_lookup_done(map, entry);		\
164df8bae1dSRodney W. Grimes 		lookup_still_valid = FALSE;		\
165df8bae1dSRodney W. Grimes 	}						\
166df8bae1dSRodney W. Grimes }
167df8bae1dSRodney W. Grimes 
168df8bae1dSRodney W. Grimes #define	UNLOCK_THINGS	{				\
169f919ebdeSDavid Greenman 	vm_object_pip_wakeup(object); \
170df8bae1dSRodney W. Grimes 	if (object != first_object) {			\
171df8bae1dSRodney W. Grimes 		FREE_PAGE(first_m);			\
172f919ebdeSDavid Greenman 		vm_object_pip_wakeup(first_object); \
173df8bae1dSRodney W. Grimes 	}						\
174df8bae1dSRodney W. Grimes 	UNLOCK_MAP;					\
17547221757SJohn Dyson 	if (vp != NULL) { \
17647221757SJohn Dyson 		vput(vp);		\
17747221757SJohn Dyson 		vp = NULL; \
17847221757SJohn Dyson 	} \
179df8bae1dSRodney W. Grimes }
180df8bae1dSRodney W. Grimes 
181df8bae1dSRodney W. Grimes #define	UNLOCK_AND_DEALLOCATE	{			\
182df8bae1dSRodney W. Grimes 	UNLOCK_THINGS;					\
183df8bae1dSRodney W. Grimes 	vm_object_deallocate(first_object);		\
184df8bae1dSRodney W. Grimes }
185df8bae1dSRodney W. Grimes 
18626f9a767SRodney W. Grimes 
187df8bae1dSRodney W. Grimes RetryFault:;
1882d8acc0fSJohn Dyson 	faultcount = 0;
189df8bae1dSRodney W. Grimes 
190df8bae1dSRodney W. Grimes 	/*
1910d94caffSDavid Greenman 	 * Find the backing store object and offset into it to begin the
1920d94caffSDavid Greenman 	 * search.
193df8bae1dSRodney W. Grimes 	 */
19422ba64e8SJohn Dyson 	if ((result = vm_map_lookup(&map, vaddr,
19522ba64e8SJohn Dyson 		fault_type, &entry, &first_object,
1962d8acc0fSJohn Dyson 		&first_pindex, &prot, &wired)) != KERN_SUCCESS) {
19747221757SJohn Dyson 		if ((result != KERN_PROTECTION_FAILURE) ||
19847221757SJohn Dyson 			((fault_flags & VM_FAULT_WIRE_MASK) != VM_FAULT_USER_WIRE)) {
19947221757SJohn Dyson 			return result;
20009e0c6ccSJohn Dyson 		}
20109e0c6ccSJohn Dyson 
2027aaaa4fdSJohn Dyson 		/*
2037aaaa4fdSJohn Dyson    		 * If we are user-wiring a r/w segment, and it is COW, then
2047aaaa4fdSJohn Dyson    		 * we need to do the COW operation.  Note that we don't COW
205595236dfSJohn Dyson    		 * currently RO sections now, because it is NOT desirable
2067aaaa4fdSJohn Dyson    		 * to COW .text.  We simply keep .text from ever being COW'ed
2077aaaa4fdSJohn Dyson    		 * and take the heat that one cannot debug wired .text sections.
2087aaaa4fdSJohn Dyson    		 */
20947221757SJohn Dyson 		result = vm_map_lookup(&map, vaddr,
21047221757SJohn Dyson 			VM_PROT_READ|VM_PROT_WRITE|VM_PROT_OVERRIDE_WRITE,
2112d8acc0fSJohn Dyson 			&entry, &first_object, &first_pindex, &prot, &wired);
21247221757SJohn Dyson 		if (result != KERN_SUCCESS) {
21347221757SJohn Dyson 			return result;
21447221757SJohn Dyson 		}
21547221757SJohn Dyson 
2167aaaa4fdSJohn Dyson 		/*
2177aaaa4fdSJohn Dyson 		 * If we don't COW now, on a user wire, the user will never
2187aaaa4fdSJohn Dyson 		 * be able to write to the mapping.  If we don't make this
2197aaaa4fdSJohn Dyson 		 * restriction, the bookkeeping would be nearly impossible.
2207aaaa4fdSJohn Dyson 		 */
22147221757SJohn Dyson 		if ((entry->protection & VM_PROT_WRITE) == 0)
2227aaaa4fdSJohn Dyson 			entry->max_protection &= ~VM_PROT_WRITE;
2237aaaa4fdSJohn Dyson 	}
22447221757SJohn Dyson 
2252d8acc0fSJohn Dyson 	map_generation = map->timestamp;
2262d8acc0fSJohn Dyson 
22747221757SJohn Dyson 	if (entry->eflags & MAP_ENTRY_NOFAULT) {
22847221757SJohn Dyson 		panic("vm_fault: fault on nofault entry, addr: %lx",
22947221757SJohn Dyson 			vaddr);
2307aaaa4fdSJohn Dyson 	}
2317aaaa4fdSJohn Dyson 
23295e5e988SJohn Dyson 	/*
23395e5e988SJohn Dyson 	 * Make a reference to this object to prevent its disposal while we
23495e5e988SJohn Dyson 	 * are messing with it.  Once we have the reference, the map is free
23595e5e988SJohn Dyson 	 * to be diddled.  Since objects reference their shadows (and copies),
23695e5e988SJohn Dyson 	 * they will stay around as well.
23795e5e988SJohn Dyson 	 */
23895e5e988SJohn Dyson 	vm_object_reference(first_object);
23995e5e988SJohn Dyson 	first_object->paging_in_progress++;
24095e5e988SJohn Dyson 
24124a1cce3SDavid Greenman 	vp = vnode_pager_lock(first_object);
2421efb74fbSJohn Dyson 	if ((fault_type & VM_PROT_WRITE) &&
2431efb74fbSJohn Dyson 		(first_object->type == OBJT_VNODE)) {
2441efb74fbSJohn Dyson 		vm_freeze_copyopts(first_object, first_pindex, first_pindex + 1);
2451efb74fbSJohn Dyson 	}
246f6b04d2bSDavid Greenman 
247df8bae1dSRodney W. Grimes 	lookup_still_valid = TRUE;
248df8bae1dSRodney W. Grimes 
249df8bae1dSRodney W. Grimes 	if (wired)
250df8bae1dSRodney W. Grimes 		fault_type = prot;
251df8bae1dSRodney W. Grimes 
252df8bae1dSRodney W. Grimes 	first_m = NULL;
253df8bae1dSRodney W. Grimes 
254df8bae1dSRodney W. Grimes 	/*
255df8bae1dSRodney W. Grimes 	 * INVARIANTS (through entire routine):
256df8bae1dSRodney W. Grimes 	 *
2570d94caffSDavid Greenman 	 * 1)	At all times, we must either have the object lock or a busy
25824a1cce3SDavid Greenman 	 * page in some object to prevent some other process from trying to
2590d94caffSDavid Greenman 	 * bring in the same page.
260df8bae1dSRodney W. Grimes 	 *
2610d94caffSDavid Greenman 	 * Note that we cannot hold any locks during the pager access or when
2620d94caffSDavid Greenman 	 * waiting for memory, so we use a busy page then.
263df8bae1dSRodney W. Grimes 	 *
2640d94caffSDavid Greenman 	 * Note also that we aren't as concerned about more than one thead
2650d94caffSDavid Greenman 	 * attempting to pager_data_unlock the same page at once, so we don't
2660d94caffSDavid Greenman 	 * hold the page as busy then, but do record the highest unlock value
2670d94caffSDavid Greenman 	 * so far.  [Unlock requests may also be delivered out of order.]
268df8bae1dSRodney W. Grimes 	 *
2690d94caffSDavid Greenman 	 * 2)	Once we have a busy page, we must remove it from the pageout
2700d94caffSDavid Greenman 	 * queues, so that the pageout daemon will not grab it away.
271df8bae1dSRodney W. Grimes 	 *
27224a1cce3SDavid Greenman 	 * 3)	To prevent another process from racing us down the shadow chain
2730d94caffSDavid Greenman 	 * and entering a new page in the top object before we do, we must
2740d94caffSDavid Greenman 	 * keep a busy page in the top object while following the shadow
2750d94caffSDavid Greenman 	 * chain.
276df8bae1dSRodney W. Grimes 	 *
2770d94caffSDavid Greenman 	 * 4)	We must increment paging_in_progress on any object for which
2780d94caffSDavid Greenman 	 * we have a busy page, to prevent vm_object_collapse from removing
2790d94caffSDavid Greenman 	 * the busy page without our noticing.
280df8bae1dSRodney W. Grimes 	 */
281df8bae1dSRodney W. Grimes 
282df8bae1dSRodney W. Grimes 	/*
283df8bae1dSRodney W. Grimes 	 * Search for the page at object/offset.
284df8bae1dSRodney W. Grimes 	 */
285df8bae1dSRodney W. Grimes 
286df8bae1dSRodney W. Grimes 	object = first_object;
287a316d390SJohn Dyson 	pindex = first_pindex;
288df8bae1dSRodney W. Grimes 
289df8bae1dSRodney W. Grimes 	/*
290df8bae1dSRodney W. Grimes 	 * See whether this page is resident
291df8bae1dSRodney W. Grimes 	 */
292df8bae1dSRodney W. Grimes 
293df8bae1dSRodney W. Grimes 	while (TRUE) {
29447221757SJohn Dyson 
29547221757SJohn Dyson 		if (object->flags & OBJ_DEAD) {
29647221757SJohn Dyson 			UNLOCK_AND_DEALLOCATE;
29747221757SJohn Dyson 			return (KERN_PROTECTION_FAILURE);
29847221757SJohn Dyson 		}
29947221757SJohn Dyson 
300a316d390SJohn Dyson 		m = vm_page_lookup(object, pindex);
301df8bae1dSRodney W. Grimes 		if (m != NULL) {
302c82b0181SJohn Dyson 			int queue;
303df8bae1dSRodney W. Grimes 			/*
3040d94caffSDavid Greenman 			 * If the page is being brought in, wait for it and
3050d94caffSDavid Greenman 			 * then retry.
306df8bae1dSRodney W. Grimes 			 */
3070d94caffSDavid Greenman 			if ((m->flags & PG_BUSY) || m->busy) {
30816f62314SDavid Greenman 				int s;
3090d94caffSDavid Greenman 
310df8bae1dSRodney W. Grimes 				UNLOCK_THINGS;
311b18bfc3dSJohn Dyson 				s = splvm();
312b18bfc3dSJohn Dyson 				if (((m->flags & PG_BUSY) || m->busy)) {
3130d94caffSDavid Greenman 					m->flags |= PG_WANTED | PG_REFERENCED;
314976e77fcSDavid Greenman 					cnt.v_intrans++;
31524a1cce3SDavid Greenman 					tsleep(m, PSWP, "vmpfw", 0);
31626f9a767SRodney W. Grimes 				}
31716f62314SDavid Greenman 				splx(s);
318df8bae1dSRodney W. Grimes 				vm_object_deallocate(first_object);
319df8bae1dSRodney W. Grimes 				goto RetryFault;
320df8bae1dSRodney W. Grimes 			}
321f6b04d2bSDavid Greenman 
322c82b0181SJohn Dyson 			queue = m->queue;
32367bf6868SJohn Dyson 			vm_page_unqueue_nowakeup(m);
324c82b0181SJohn Dyson 
325df8bae1dSRodney W. Grimes 			/*
32624a1cce3SDavid Greenman 			 * Mark page busy for other processes, and the pagedaemon.
327df8bae1dSRodney W. Grimes 			 */
3285070c7f8SJohn Dyson 			if (((queue - m->pc) == PQ_CACHE) &&
329886d3e11SJohn Dyson 			    (cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min) {
330c82b0181SJohn Dyson 				vm_page_activate(m);
33122ba64e8SJohn Dyson 				UNLOCK_AND_DEALLOCATE;
33222ba64e8SJohn Dyson 				VM_WAIT;
33322ba64e8SJohn Dyson 				goto RetryFault;
33422ba64e8SJohn Dyson 			}
33522ba64e8SJohn Dyson 
336886d3e11SJohn Dyson 			m->flags |= PG_BUSY;
3370ed43762SJohn Dyson 
33847221757SJohn Dyson 			if (((m->valid & VM_PAGE_BITS_ALL) != VM_PAGE_BITS_ALL) &&
339f919ebdeSDavid Greenman 				m->object != kernel_object && m->object != kmem_object) {
3400d94caffSDavid Greenman 				goto readrest;
3410d94caffSDavid Greenman 			}
342df8bae1dSRodney W. Grimes 			break;
343df8bae1dSRodney W. Grimes 		}
34447221757SJohn Dyson 		if (((object->type != OBJT_DEFAULT) &&
34547221757SJohn Dyson 				(((fault_flags & VM_FAULT_WIRE_MASK) == 0) || wired))
346df8bae1dSRodney W. Grimes 		    || (object == first_object)) {
347df8bae1dSRodney W. Grimes 
348a316d390SJohn Dyson 			if (pindex >= object->size) {
3495f55e841SDavid Greenman 				UNLOCK_AND_DEALLOCATE;
3505f55e841SDavid Greenman 				return (KERN_PROTECTION_FAILURE);
3515f55e841SDavid Greenman 			}
35222ba64e8SJohn Dyson 
353df8bae1dSRodney W. Grimes 			/*
3540d94caffSDavid Greenman 			 * Allocate a new page for this object/offset pair.
355df8bae1dSRodney W. Grimes 			 */
356a316d390SJohn Dyson 			m = vm_page_alloc(object, pindex,
357b18bfc3dSJohn Dyson 				(vp || object->backing_object)? VM_ALLOC_NORMAL: VM_ALLOC_ZERO);
358df8bae1dSRodney W. Grimes 
359df8bae1dSRodney W. Grimes 			if (m == NULL) {
360df8bae1dSRodney W. Grimes 				UNLOCK_AND_DEALLOCATE;
361df8bae1dSRodney W. Grimes 				VM_WAIT;
362df8bae1dSRodney W. Grimes 				goto RetryFault;
363df8bae1dSRodney W. Grimes 			}
364df8bae1dSRodney W. Grimes 		}
36547221757SJohn Dyson 
3660d94caffSDavid Greenman readrest:
36747221757SJohn Dyson 		if (object->type != OBJT_DEFAULT &&
36847221757SJohn Dyson 			(((fault_flags & VM_FAULT_WIRE_MASK) == 0) || wired)) {
369df8bae1dSRodney W. Grimes 			int rv;
37026f9a767SRodney W. Grimes 			int reqpage;
371867a482dSJohn Dyson 			int ahead, behind;
372867a482dSJohn Dyson 
373867a482dSJohn Dyson 			if (first_object->behavior == OBJ_RANDOM) {
374867a482dSJohn Dyson 				ahead = 0;
375867a482dSJohn Dyson 				behind = 0;
3762d8acc0fSJohn Dyson 			} else {
3772d8acc0fSJohn Dyson 				behind = (vaddr - entry->start) >> PAGE_SHIFT;
3782d8acc0fSJohn Dyson 				if (behind > VM_FAULT_READ_BEHIND)
3792d8acc0fSJohn Dyson 					behind = VM_FAULT_READ_BEHIND;
3802d8acc0fSJohn Dyson 
3812d8acc0fSJohn Dyson 				ahead = ((entry->end - vaddr) >> PAGE_SHIFT) - 1;
3822d8acc0fSJohn Dyson 				if (ahead > VM_FAULT_READ_AHEAD)
3832d8acc0fSJohn Dyson 					ahead = VM_FAULT_READ_AHEAD;
384867a482dSJohn Dyson 			}
385867a482dSJohn Dyson 
386ff97964aSJohn Dyson 			if ((first_object->type != OBJT_DEVICE) &&
387ff97964aSJohn Dyson 				(first_object->behavior == OBJ_SEQUENTIAL)) {
388867a482dSJohn Dyson 				vm_pindex_t firstpindex, tmppindex;
389867a482dSJohn Dyson 				if (first_pindex <
390867a482dSJohn Dyson 					2*(VM_FAULT_READ_BEHIND + VM_FAULT_READ_AHEAD + 1))
391867a482dSJohn Dyson 					firstpindex = 0;
392867a482dSJohn Dyson 				else
393867a482dSJohn Dyson 					firstpindex = first_pindex -
394867a482dSJohn Dyson 						2*(VM_FAULT_READ_BEHIND + VM_FAULT_READ_AHEAD + 1);
395867a482dSJohn Dyson 
396867a482dSJohn Dyson 				for(tmppindex = first_pindex - 1;
3972100d645SPeter Wemm 					tmppindex >= firstpindex;
398867a482dSJohn Dyson 					--tmppindex) {
399867a482dSJohn Dyson 					vm_page_t mt;
400867a482dSJohn Dyson 					mt = vm_page_lookup( first_object, tmppindex);
401867a482dSJohn Dyson 					if (mt == NULL || (mt->valid != VM_PAGE_BITS_ALL))
402867a482dSJohn Dyson 						break;
403ff97964aSJohn Dyson 					if (mt->busy ||
404ff97964aSJohn Dyson 						(mt->flags & (PG_BUSY|PG_FICTITIOUS)) ||
405ff97964aSJohn Dyson 						mt->hold_count ||
406867a482dSJohn Dyson 						mt->wire_count)
407867a482dSJohn Dyson 						continue;
408867a482dSJohn Dyson 					if (mt->dirty == 0)
409867a482dSJohn Dyson 						vm_page_test_dirty(mt);
410867a482dSJohn Dyson 					if (mt->dirty) {
411867a482dSJohn Dyson 						vm_page_protect(mt, VM_PROT_NONE);
412867a482dSJohn Dyson 						vm_page_deactivate(mt);
413867a482dSJohn Dyson 					} else {
414867a482dSJohn Dyson 						vm_page_cache(mt);
415867a482dSJohn Dyson 					}
416867a482dSJohn Dyson 				}
417867a482dSJohn Dyson 
418867a482dSJohn Dyson 				ahead += behind;
419867a482dSJohn Dyson 				behind = 0;
420867a482dSJohn Dyson 			}
421df8bae1dSRodney W. Grimes 
422df8bae1dSRodney W. Grimes 			/*
4230d94caffSDavid Greenman 			 * now we find out if any other pages should be paged
4240d94caffSDavid Greenman 			 * in at this time this routine checks to see if the
4250d94caffSDavid Greenman 			 * pages surrounding this fault reside in the same
4260d94caffSDavid Greenman 			 * object as the page for this fault.  If they do,
4270d94caffSDavid Greenman 			 * then they are faulted in also into the object.  The
4280d94caffSDavid Greenman 			 * array "marray" returned contains an array of
4290d94caffSDavid Greenman 			 * vm_page_t structs where one of them is the
4300d94caffSDavid Greenman 			 * vm_page_t passed to the routine.  The reqpage
4310d94caffSDavid Greenman 			 * return value is the index into the marray for the
4320d94caffSDavid Greenman 			 * vm_page_t passed to the routine.
43326f9a767SRodney W. Grimes 			 */
43405f0fdd2SPoul-Henning Kamp 			faultcount = vm_fault_additional_pages(
435867a482dSJohn Dyson 			    m, behind, ahead, marray, &reqpage);
436df8bae1dSRodney W. Grimes 
437df8bae1dSRodney W. Grimes 			/*
4380d94caffSDavid Greenman 			 * Call the pager to retrieve the data, if any, after
4390d94caffSDavid Greenman 			 * releasing the lock on the map.
440df8bae1dSRodney W. Grimes 			 */
441df8bae1dSRodney W. Grimes 			UNLOCK_MAP;
442df8bae1dSRodney W. Grimes 
44326f9a767SRodney W. Grimes 			rv = faultcount ?
44424a1cce3SDavid Greenman 			    vm_pager_get_pages(object, marray, faultcount,
44524a1cce3SDavid Greenman 				reqpage) : VM_PAGER_FAIL;
44622ba64e8SJohn Dyson 
44726f9a767SRodney W. Grimes 			if (rv == VM_PAGER_OK) {
448df8bae1dSRodney W. Grimes 				/*
449f230c45cSJohn Dyson 				 * Found the page. Leave it busy while we play
450f230c45cSJohn Dyson 				 * with it.
451f230c45cSJohn Dyson 				 */
452f230c45cSJohn Dyson 
453f230c45cSJohn Dyson 				/*
4540d94caffSDavid Greenman 				 * Relookup in case pager changed page. Pager
4550d94caffSDavid Greenman 				 * is responsible for disposition of old page
4560d94caffSDavid Greenman 				 * if moved.
457df8bae1dSRodney W. Grimes 				 */
458a316d390SJohn Dyson 				m = vm_page_lookup(object, pindex);
459f6b04d2bSDavid Greenman 				if( !m) {
460f6b04d2bSDavid Greenman 					UNLOCK_AND_DEALLOCATE;
461f6b04d2bSDavid Greenman 					goto RetryFault;
462f6b04d2bSDavid Greenman 				}
463f6b04d2bSDavid Greenman 
46426f9a767SRodney W. Grimes 				hardfault++;
465df8bae1dSRodney W. Grimes 				break;
466df8bae1dSRodney W. Grimes 			}
467df8bae1dSRodney W. Grimes 			/*
4680d94caffSDavid Greenman 			 * Remove the bogus page (which does not exist at this
4690d94caffSDavid Greenman 			 * object/offset); before doing so, we must get back
4700d94caffSDavid Greenman 			 * our object lock to preserve our invariant.
471df8bae1dSRodney W. Grimes 			 *
47224a1cce3SDavid Greenman 			 * Also wake up any other process that may want to bring
4730d94caffSDavid Greenman 			 * in this page.
474df8bae1dSRodney W. Grimes 			 *
4750d94caffSDavid Greenman 			 * If this is the top-level object, we must leave the
47624a1cce3SDavid Greenman 			 * busy page to prevent another process from rushing
4770d94caffSDavid Greenman 			 * past us, and inserting the page in that object at
4780d94caffSDavid Greenman 			 * the same time that we are.
479df8bae1dSRodney W. Grimes 			 */
48026f9a767SRodney W. Grimes 
481a83c285cSDavid Greenman 			if (rv == VM_PAGER_ERROR)
482a83c285cSDavid Greenman 				printf("vm_fault: pager input (probably hardware) error, PID %d failure\n",
483a83c285cSDavid Greenman 				    curproc->p_pid);
48426f9a767SRodney W. Grimes 			/*
485a83c285cSDavid Greenman 			 * Data outside the range of the pager or an I/O error
48626f9a767SRodney W. Grimes 			 */
487a83c285cSDavid Greenman 			/*
4880d94caffSDavid Greenman 			 * XXX - the check for kernel_map is a kludge to work
4890d94caffSDavid Greenman 			 * around having the machine panic on a kernel space
4900d94caffSDavid Greenman 			 * fault w/ I/O error.
491a83c285cSDavid Greenman 			 */
49247221757SJohn Dyson 			if (((map != kernel_map) && (rv == VM_PAGER_ERROR)) ||
49347221757SJohn Dyson 				(rv == VM_PAGER_BAD)) {
49426f9a767SRodney W. Grimes 				FREE_PAGE(m);
49526f9a767SRodney W. Grimes 				UNLOCK_AND_DEALLOCATE;
496a83c285cSDavid Greenman 				return ((rv == VM_PAGER_ERROR) ? KERN_FAILURE : KERN_PROTECTION_FAILURE);
49726f9a767SRodney W. Grimes 			}
498df8bae1dSRodney W. Grimes 			if (object != first_object) {
499df8bae1dSRodney W. Grimes 				FREE_PAGE(m);
50026f9a767SRodney W. Grimes 				/*
50126f9a767SRodney W. Grimes 				 * XXX - we cannot just fall out at this
50226f9a767SRodney W. Grimes 				 * point, m has been freed and is invalid!
50326f9a767SRodney W. Grimes 				 */
504df8bae1dSRodney W. Grimes 			}
505df8bae1dSRodney W. Grimes 		}
506df8bae1dSRodney W. Grimes 		/*
50724a1cce3SDavid Greenman 		 * We get here if the object has default pager (or unwiring) or the
5080d94caffSDavid Greenman 		 * pager doesn't have the page.
509df8bae1dSRodney W. Grimes 		 */
510df8bae1dSRodney W. Grimes 		if (object == first_object)
511df8bae1dSRodney W. Grimes 			first_m = m;
512df8bae1dSRodney W. Grimes 
513df8bae1dSRodney W. Grimes 		/*
5140d94caffSDavid Greenman 		 * Move on to the next object.  Lock the next object before
5150d94caffSDavid Greenman 		 * unlocking the current one.
516df8bae1dSRodney W. Grimes 		 */
517df8bae1dSRodney W. Grimes 
518a316d390SJohn Dyson 		pindex += OFF_TO_IDX(object->backing_object_offset);
51924a1cce3SDavid Greenman 		next_object = object->backing_object;
520df8bae1dSRodney W. Grimes 		if (next_object == NULL) {
521df8bae1dSRodney W. Grimes 			/*
5220d94caffSDavid Greenman 			 * If there's no object left, fill the page in the top
5230d94caffSDavid Greenman 			 * object with zeros.
524df8bae1dSRodney W. Grimes 			 */
525df8bae1dSRodney W. Grimes 			if (object != first_object) {
526f919ebdeSDavid Greenman 				vm_object_pip_wakeup(object);
527df8bae1dSRodney W. Grimes 
528df8bae1dSRodney W. Grimes 				object = first_object;
529a316d390SJohn Dyson 				pindex = first_pindex;
530df8bae1dSRodney W. Grimes 				m = first_m;
531df8bae1dSRodney W. Grimes 			}
532df8bae1dSRodney W. Grimes 			first_m = NULL;
533df8bae1dSRodney W. Grimes 
534f230c45cSJohn Dyson 			if ((m->flags & PG_ZERO) == 0)
535df8bae1dSRodney W. Grimes 				vm_page_zero_fill(m);
536df8bae1dSRodney W. Grimes 			cnt.v_zfod++;
537df8bae1dSRodney W. Grimes 			break;
5380d94caffSDavid Greenman 		} else {
53926f9a767SRodney W. Grimes 			if (object != first_object) {
540f919ebdeSDavid Greenman 				vm_object_pip_wakeup(object);
541c0503609SDavid Greenman 			}
542df8bae1dSRodney W. Grimes 			object = next_object;
543df8bae1dSRodney W. Grimes 			object->paging_in_progress++;
544df8bae1dSRodney W. Grimes 		}
545df8bae1dSRodney W. Grimes 	}
546df8bae1dSRodney W. Grimes 
547925a3a41SJohn Dyson #if defined(DIAGNOSTIC)
548f919ebdeSDavid Greenman 	if ((m->flags & PG_BUSY) == 0)
549f919ebdeSDavid Greenman 		panic("vm_fault: not busy after main loop");
550925a3a41SJohn Dyson #endif
551df8bae1dSRodney W. Grimes 
552df8bae1dSRodney W. Grimes 	/*
5530d94caffSDavid Greenman 	 * PAGE HAS BEEN FOUND. [Loop invariant still holds -- the object lock
554df8bae1dSRodney W. Grimes 	 * is held.]
555df8bae1dSRodney W. Grimes 	 */
556df8bae1dSRodney W. Grimes 
557df8bae1dSRodney W. Grimes 	old_m = m;	/* save page that would be copied */
558df8bae1dSRodney W. Grimes 
559df8bae1dSRodney W. Grimes 	/*
5600d94caffSDavid Greenman 	 * If the page is being written, but isn't already owned by the
5610d94caffSDavid Greenman 	 * top-level object, we have to copy it into a new page owned by the
5620d94caffSDavid Greenman 	 * top-level object.
563df8bae1dSRodney W. Grimes 	 */
564df8bae1dSRodney W. Grimes 
565df8bae1dSRodney W. Grimes 	if (object != first_object) {
566df8bae1dSRodney W. Grimes 		/*
5670d94caffSDavid Greenman 		 * We only really need to copy if we want to write it.
568df8bae1dSRodney W. Grimes 		 */
569df8bae1dSRodney W. Grimes 
570df8bae1dSRodney W. Grimes 		if (fault_type & VM_PROT_WRITE) {
571df8bae1dSRodney W. Grimes 
572df8bae1dSRodney W. Grimes 			/*
573b5b40fa6SJohn Dyson 			 * This allows pages to be virtually copied from a backing_object
574b5b40fa6SJohn Dyson 			 * into the first_object, where the backing object has no other
575b5b40fa6SJohn Dyson 			 * refs to it, and cannot gain any more refs.  Instead of a
576b5b40fa6SJohn Dyson 			 * bcopy, we just move the page from the backing object to the
577b5b40fa6SJohn Dyson 			 * first object.  Note that we must mark the page dirty in the
578b5b40fa6SJohn Dyson 			 * first object so that it will go out to swap when needed.
579df8bae1dSRodney W. Grimes 			 */
5802d8acc0fSJohn Dyson 			if (map_generation == map->timestamp &&
581de5f6a77SJohn Dyson 				/*
582de5f6a77SJohn Dyson 				 * Only one shadow object
583de5f6a77SJohn Dyson 				 */
584de5f6a77SJohn Dyson 				(object->shadow_count == 1) &&
585de5f6a77SJohn Dyson 				/*
586de5f6a77SJohn Dyson 				 * No COW refs, except us
587de5f6a77SJohn Dyson 				 */
588de5f6a77SJohn Dyson 				(object->ref_count == 1) &&
589de5f6a77SJohn Dyson 				/*
590de5f6a77SJohn Dyson 				 * Noone else can look this object up
591de5f6a77SJohn Dyson 				 */
592de5f6a77SJohn Dyson 				(object->handle == NULL) &&
593de5f6a77SJohn Dyson 				/*
594de5f6a77SJohn Dyson 				 * No other ways to look the object up
595de5f6a77SJohn Dyson 				 */
596de5f6a77SJohn Dyson 				((object->type == OBJT_DEFAULT) ||
597de5f6a77SJohn Dyson 				 (object->type == OBJT_SWAP)) &&
598de5f6a77SJohn Dyson 				/*
599de5f6a77SJohn Dyson 				 * We don't chase down the shadow chain
600de5f6a77SJohn Dyson 				 */
6012d8acc0fSJohn Dyson 				(object == first_object->backing_object) &&
602df8bae1dSRodney W. Grimes 
603df8bae1dSRodney W. Grimes 				/*
6042d8acc0fSJohn Dyson 				 * grab the lock if we need to
6052d8acc0fSJohn Dyson 				 */
6062d8acc0fSJohn Dyson 				(lookup_still_valid ||
6072d8acc0fSJohn Dyson 						(((entry->eflags & MAP_ENTRY_IS_A_MAP) == 0) &&
6082d8acc0fSJohn Dyson 						 lockmgr(&map->lock,
6092d8acc0fSJohn Dyson 							LK_EXCLUSIVE|LK_NOWAIT, (void *)0, curproc) == 0))) {
6102d8acc0fSJohn Dyson 
6112d8acc0fSJohn Dyson 				lookup_still_valid = 1;
6122d8acc0fSJohn Dyson 				/*
613de5f6a77SJohn Dyson 				 * get rid of the unnecessary page
614df8bae1dSRodney W. Grimes 				 */
615de5f6a77SJohn Dyson 				vm_page_protect(first_m, VM_PROT_NONE);
616de5f6a77SJohn Dyson 				PAGE_WAKEUP(first_m);
617de5f6a77SJohn Dyson 				vm_page_free(first_m);
618de5f6a77SJohn Dyson 				/*
619de5f6a77SJohn Dyson 				 * grab the page and put it into the process'es object
620de5f6a77SJohn Dyson 				 */
621de5f6a77SJohn Dyson 				vm_page_rename(m, first_object, first_pindex);
622de5f6a77SJohn Dyson 				first_m = m;
623de5f6a77SJohn Dyson 				m->dirty = VM_PAGE_BITS_ALL;
624de5f6a77SJohn Dyson 				m = NULL;
625de5f6a77SJohn Dyson 			} else {
626de5f6a77SJohn Dyson 				/*
627de5f6a77SJohn Dyson 				 * Oh, well, lets copy it.
628de5f6a77SJohn Dyson 				 */
629de5f6a77SJohn Dyson 				vm_page_copy(m, first_m);
630de5f6a77SJohn Dyson 			}
631df8bae1dSRodney W. Grimes 
632de5f6a77SJohn Dyson 			if (m) {
6332d8acc0fSJohn Dyson 				if (m->queue != PQ_ACTIVE) {
634df8bae1dSRodney W. Grimes 					vm_page_activate(m);
6352d8acc0fSJohn Dyson 					m->act_count = 0;
6362d8acc0fSJohn Dyson 				}
6372d8acc0fSJohn Dyson 
638df8bae1dSRodney W. Grimes 			/*
639df8bae1dSRodney W. Grimes 			 * We no longer need the old page or object.
640df8bae1dSRodney W. Grimes 			 */
641df8bae1dSRodney W. Grimes 				PAGE_WAKEUP(m);
642de5f6a77SJohn Dyson 			}
643df8bae1dSRodney W. Grimes 
644de5f6a77SJohn Dyson 			vm_object_pip_wakeup(object);
645df8bae1dSRodney W. Grimes 			/*
646df8bae1dSRodney W. Grimes 			 * Only use the new page below...
647df8bae1dSRodney W. Grimes 			 */
648df8bae1dSRodney W. Grimes 
649df8bae1dSRodney W. Grimes 			cnt.v_cow_faults++;
650df8bae1dSRodney W. Grimes 			m = first_m;
651df8bae1dSRodney W. Grimes 			object = first_object;
652a316d390SJohn Dyson 			pindex = first_pindex;
653df8bae1dSRodney W. Grimes 
6540d94caffSDavid Greenman 		} else {
655df8bae1dSRodney W. Grimes 			prot &= ~VM_PROT_WRITE;
656df8bae1dSRodney W. Grimes 		}
657df8bae1dSRodney W. Grimes 	}
658df8bae1dSRodney W. Grimes 
659df8bae1dSRodney W. Grimes 	/*
6600d94caffSDavid Greenman 	 * We must verify that the maps have not changed since our last
6610d94caffSDavid Greenman 	 * lookup.
662df8bae1dSRodney W. Grimes 	 */
663df8bae1dSRodney W. Grimes 
6642d8acc0fSJohn Dyson 	if (!lookup_still_valid &&
6652d8acc0fSJohn Dyson 		(map->timestamp != map_generation)) {
666df8bae1dSRodney W. Grimes 		vm_object_t retry_object;
667a316d390SJohn Dyson 		vm_pindex_t retry_pindex;
668df8bae1dSRodney W. Grimes 		vm_prot_t retry_prot;
669df8bae1dSRodney W. Grimes 
670df8bae1dSRodney W. Grimes 		/*
6710d94caffSDavid Greenman 		 * Since map entries may be pageable, make sure we can take a
6720d94caffSDavid Greenman 		 * page fault on them.
673df8bae1dSRodney W. Grimes 		 */
674df8bae1dSRodney W. Grimes 
675df8bae1dSRodney W. Grimes 		/*
67624a1cce3SDavid Greenman 		 * To avoid trying to write_lock the map while another process
6770d94caffSDavid Greenman 		 * has it read_locked (in vm_map_pageable), we do not try for
6780d94caffSDavid Greenman 		 * write permission.  If the page is still writable, we will
6790d94caffSDavid Greenman 		 * get write permission.  If it is not, or has been marked
6800d94caffSDavid Greenman 		 * needs_copy, we enter the mapping without write permission,
6810d94caffSDavid Greenman 		 * and will merely take another fault.
682df8bae1dSRodney W. Grimes 		 */
6830d94caffSDavid Greenman 		result = vm_map_lookup(&map, vaddr, fault_type & ~VM_PROT_WRITE,
6842d8acc0fSJohn Dyson 		    &entry, &retry_object, &retry_pindex, &retry_prot, &wired);
6852d8acc0fSJohn Dyson 		map_generation = map->timestamp;
686df8bae1dSRodney W. Grimes 
687df8bae1dSRodney W. Grimes 		/*
6880d94caffSDavid Greenman 		 * If we don't need the page any longer, put it on the active
6890d94caffSDavid Greenman 		 * list (the easiest thing to do here).  If no one needs it,
6900d94caffSDavid Greenman 		 * pageout will grab it eventually.
691df8bae1dSRodney W. Grimes 		 */
692df8bae1dSRodney W. Grimes 
693df8bae1dSRodney W. Grimes 		if (result != KERN_SUCCESS) {
694df8bae1dSRodney W. Grimes 			RELEASE_PAGE(m);
695df8bae1dSRodney W. Grimes 			UNLOCK_AND_DEALLOCATE;
696df8bae1dSRodney W. Grimes 			return (result);
697df8bae1dSRodney W. Grimes 		}
698df8bae1dSRodney W. Grimes 		lookup_still_valid = TRUE;
699df8bae1dSRodney W. Grimes 
700df8bae1dSRodney W. Grimes 		if ((retry_object != first_object) ||
701a316d390SJohn Dyson 		    (retry_pindex != first_pindex)) {
702df8bae1dSRodney W. Grimes 			RELEASE_PAGE(m);
703df8bae1dSRodney W. Grimes 			UNLOCK_AND_DEALLOCATE;
704df8bae1dSRodney W. Grimes 			goto RetryFault;
705df8bae1dSRodney W. Grimes 		}
706df8bae1dSRodney W. Grimes 		/*
7070d94caffSDavid Greenman 		 * Check whether the protection has changed or the object has
7080d94caffSDavid Greenman 		 * been copied while we left the map unlocked. Changing from
7090d94caffSDavid Greenman 		 * read to write permission is OK - we leave the page
7100d94caffSDavid Greenman 		 * write-protected, and catch the write fault. Changing from
7110d94caffSDavid Greenman 		 * write to read permission means that we can't mark the page
7120d94caffSDavid Greenman 		 * write-enabled after all.
713df8bae1dSRodney W. Grimes 		 */
714df8bae1dSRodney W. Grimes 		prot &= retry_prot;
715df8bae1dSRodney W. Grimes 	}
716df8bae1dSRodney W. Grimes 
717df8bae1dSRodney W. Grimes 	/*
7180d94caffSDavid Greenman 	 * Put this page into the physical map. We had to do the unlock above
7190d94caffSDavid Greenman 	 * because pmap_enter may cause other faults.   We don't put the page
7200d94caffSDavid Greenman 	 * back on the active queue until later so that the page-out daemon
7210d94caffSDavid Greenman 	 * won't find us (yet).
722df8bae1dSRodney W. Grimes 	 */
723df8bae1dSRodney W. Grimes 
7242ddba215SDavid Greenman 	if (prot & VM_PROT_WRITE) {
725f919ebdeSDavid Greenman 		m->flags |= PG_WRITEABLE;
726aef922f5SJohn Dyson 		m->object->flags |= OBJ_WRITEABLE|OBJ_MIGHTBEDIRTY;
7272ddba215SDavid Greenman 		/*
7282ddba215SDavid Greenman 		 * If the fault is a write, we know that this page is being
7292ddba215SDavid Greenman 		 * written NOW. This will save on the pmap_is_modified() calls
7302ddba215SDavid Greenman 		 * later.
7312ddba215SDavid Greenman 		 */
732a04c970aSJohn Dyson 		if (fault_flags & VM_FAULT_DIRTY) {
7332ddba215SDavid Greenman 			m->dirty = VM_PAGE_BITS_ALL;
7342ddba215SDavid Greenman 		}
7352ddba215SDavid Greenman 	}
736f6b04d2bSDavid Greenman 
73730dcfc09SJohn Dyson 	UNLOCK_THINGS;
73865bc79b8SJohn Dyson 	m->valid = VM_PAGE_BITS_ALL;
739ff97964aSJohn Dyson 	m->flags &= ~PG_ZERO;
740f919ebdeSDavid Greenman 
741df8bae1dSRodney W. Grimes 	pmap_enter(map->pmap, vaddr, VM_PAGE_TO_PHYS(m), prot, wired);
7422d8acc0fSJohn Dyson 	if (((fault_flags & VM_FAULT_WIRE_MASK) == 0) && (wired == 0)) {
7432d8acc0fSJohn Dyson 		pmap_prefault(map->pmap, vaddr, entry);
7442d8acc0fSJohn Dyson 	}
745df8bae1dSRodney W. Grimes 
746ff97964aSJohn Dyson 	m->flags |= PG_MAPPED|PG_REFERENCED;
747a04c970aSJohn Dyson 	if (fault_flags & VM_FAULT_HOLD)
748a04c970aSJohn Dyson 		vm_page_hold(m);
749ff97964aSJohn Dyson 
750df8bae1dSRodney W. Grimes 	/*
7510d94caffSDavid Greenman 	 * If the page is not wired down, then put it where the pageout daemon
7520d94caffSDavid Greenman 	 * can find it.
753df8bae1dSRodney W. Grimes 	 */
754a04c970aSJohn Dyson 	if (fault_flags & VM_FAULT_WIRE_MASK) {
755df8bae1dSRodney W. Grimes 		if (wired)
756df8bae1dSRodney W. Grimes 			vm_page_wire(m);
757df8bae1dSRodney W. Grimes 		else
758df8bae1dSRodney W. Grimes 			vm_page_unwire(m);
7590d94caffSDavid Greenman 	} else {
760bd7e5f99SJohn Dyson 		if (m->queue != PQ_ACTIVE)
761df8bae1dSRodney W. Grimes 			vm_page_activate(m);
76226f9a767SRodney W. Grimes 	}
76326f9a767SRodney W. Grimes 
764a1f6d91cSDavid Greenman 	if (curproc && (curproc->p_flag & P_INMEM) && curproc->p_stats) {
76526f9a767SRodney W. Grimes 		if (hardfault) {
76626f9a767SRodney W. Grimes 			curproc->p_stats->p_ru.ru_majflt++;
76726f9a767SRodney W. Grimes 		} else {
76826f9a767SRodney W. Grimes 			curproc->p_stats->p_ru.ru_minflt++;
76926f9a767SRodney W. Grimes 		}
77026f9a767SRodney W. Grimes 	}
771df8bae1dSRodney W. Grimes 
772df8bae1dSRodney W. Grimes 	/*
773df8bae1dSRodney W. Grimes 	 * Unlock everything, and return
774df8bae1dSRodney W. Grimes 	 */
775df8bae1dSRodney W. Grimes 
776df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);
77730dcfc09SJohn Dyson 	vm_object_deallocate(first_object);
778df8bae1dSRodney W. Grimes 
779df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
780df8bae1dSRodney W. Grimes 
781df8bae1dSRodney W. Grimes }
782df8bae1dSRodney W. Grimes 
783df8bae1dSRodney W. Grimes /*
784df8bae1dSRodney W. Grimes  *	vm_fault_wire:
785df8bae1dSRodney W. Grimes  *
786df8bae1dSRodney W. Grimes  *	Wire down a range of virtual addresses in a map.
787df8bae1dSRodney W. Grimes  */
788df8bae1dSRodney W. Grimes int
789df8bae1dSRodney W. Grimes vm_fault_wire(map, start, end)
790df8bae1dSRodney W. Grimes 	vm_map_t map;
791df8bae1dSRodney W. Grimes 	vm_offset_t start, end;
792df8bae1dSRodney W. Grimes {
79326f9a767SRodney W. Grimes 
794df8bae1dSRodney W. Grimes 	register vm_offset_t va;
795df8bae1dSRodney W. Grimes 	register pmap_t pmap;
796df8bae1dSRodney W. Grimes 	int rv;
797df8bae1dSRodney W. Grimes 
798df8bae1dSRodney W. Grimes 	pmap = vm_map_pmap(map);
799df8bae1dSRodney W. Grimes 
800df8bae1dSRodney W. Grimes 	/*
8010d94caffSDavid Greenman 	 * Inform the physical mapping system that the range of addresses may
8020d94caffSDavid Greenman 	 * not fault, so that page tables and such can be locked down as well.
803df8bae1dSRodney W. Grimes 	 */
804df8bae1dSRodney W. Grimes 
805df8bae1dSRodney W. Grimes 	pmap_pageable(pmap, start, end, FALSE);
806df8bae1dSRodney W. Grimes 
807df8bae1dSRodney W. Grimes 	/*
8080d94caffSDavid Greenman 	 * We simulate a fault to get the page and enter it in the physical
8090d94caffSDavid Greenman 	 * map.
810df8bae1dSRodney W. Grimes 	 */
811df8bae1dSRodney W. Grimes 
812df8bae1dSRodney W. Grimes 	for (va = start; va < end; va += PAGE_SIZE) {
8137aaaa4fdSJohn Dyson 		rv = vm_fault(map, va, VM_PROT_READ|VM_PROT_WRITE,
8147aaaa4fdSJohn Dyson 			VM_FAULT_CHANGE_WIRING);
8157aaaa4fdSJohn Dyson 		if (rv) {
8167aaaa4fdSJohn Dyson 			if (va != start)
8177aaaa4fdSJohn Dyson 				vm_fault_unwire(map, start, va);
8187aaaa4fdSJohn Dyson 			return (rv);
8197aaaa4fdSJohn Dyson 		}
8207aaaa4fdSJohn Dyson 	}
8217aaaa4fdSJohn Dyson 	return (KERN_SUCCESS);
8227aaaa4fdSJohn Dyson }
8237aaaa4fdSJohn Dyson 
8247aaaa4fdSJohn Dyson /*
8257aaaa4fdSJohn Dyson  *	vm_fault_user_wire:
8267aaaa4fdSJohn Dyson  *
8277aaaa4fdSJohn Dyson  *	Wire down a range of virtual addresses in a map.  This
8287aaaa4fdSJohn Dyson  *	is for user mode though, so we only ask for read access
8297aaaa4fdSJohn Dyson  *	on currently read only sections.
8307aaaa4fdSJohn Dyson  */
8317aaaa4fdSJohn Dyson int
8327aaaa4fdSJohn Dyson vm_fault_user_wire(map, start, end)
8337aaaa4fdSJohn Dyson 	vm_map_t map;
8347aaaa4fdSJohn Dyson 	vm_offset_t start, end;
8357aaaa4fdSJohn Dyson {
8367aaaa4fdSJohn Dyson 
8377aaaa4fdSJohn Dyson 	register vm_offset_t va;
8387aaaa4fdSJohn Dyson 	register pmap_t pmap;
8397aaaa4fdSJohn Dyson 	int rv;
8407aaaa4fdSJohn Dyson 
8417aaaa4fdSJohn Dyson 	pmap = vm_map_pmap(map);
8427aaaa4fdSJohn Dyson 
8437aaaa4fdSJohn Dyson 	/*
8447aaaa4fdSJohn Dyson 	 * Inform the physical mapping system that the range of addresses may
8457aaaa4fdSJohn Dyson 	 * not fault, so that page tables and such can be locked down as well.
8467aaaa4fdSJohn Dyson 	 */
8472d8acc0fSJohn Dyson 
8487aaaa4fdSJohn Dyson 	pmap_pageable(pmap, start, end, FALSE);
8497aaaa4fdSJohn Dyson 
8507aaaa4fdSJohn Dyson 	/*
8517aaaa4fdSJohn Dyson 	 * We simulate a fault to get the page and enter it in the physical
8527aaaa4fdSJohn Dyson 	 * map.
8537aaaa4fdSJohn Dyson 	 */
8547aaaa4fdSJohn Dyson 	for (va = start; va < end; va += PAGE_SIZE) {
8557aaaa4fdSJohn Dyson 		rv = vm_fault(map, va, VM_PROT_READ, VM_FAULT_USER_WIRE);
856df8bae1dSRodney W. Grimes 		if (rv) {
857df8bae1dSRodney W. Grimes 			if (va != start)
858df8bae1dSRodney W. Grimes 				vm_fault_unwire(map, start, va);
859df8bae1dSRodney W. Grimes 			return (rv);
860df8bae1dSRodney W. Grimes 		}
861df8bae1dSRodney W. Grimes 	}
862df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
863df8bae1dSRodney W. Grimes }
864df8bae1dSRodney W. Grimes 
865df8bae1dSRodney W. Grimes 
866df8bae1dSRodney W. Grimes /*
867df8bae1dSRodney W. Grimes  *	vm_fault_unwire:
868df8bae1dSRodney W. Grimes  *
869df8bae1dSRodney W. Grimes  *	Unwire a range of virtual addresses in a map.
870df8bae1dSRodney W. Grimes  */
87126f9a767SRodney W. Grimes void
87226f9a767SRodney W. Grimes vm_fault_unwire(map, start, end)
873df8bae1dSRodney W. Grimes 	vm_map_t map;
874df8bae1dSRodney W. Grimes 	vm_offset_t start, end;
875df8bae1dSRodney W. Grimes {
876df8bae1dSRodney W. Grimes 
877df8bae1dSRodney W. Grimes 	register vm_offset_t va, pa;
878df8bae1dSRodney W. Grimes 	register pmap_t pmap;
879df8bae1dSRodney W. Grimes 
880df8bae1dSRodney W. Grimes 	pmap = vm_map_pmap(map);
881df8bae1dSRodney W. Grimes 
882df8bae1dSRodney W. Grimes 	/*
8830d94caffSDavid Greenman 	 * Since the pages are wired down, we must be able to get their
8840d94caffSDavid Greenman 	 * mappings from the physical map system.
885df8bae1dSRodney W. Grimes 	 */
886df8bae1dSRodney W. Grimes 
887df8bae1dSRodney W. Grimes 	for (va = start; va < end; va += PAGE_SIZE) {
888df8bae1dSRodney W. Grimes 		pa = pmap_extract(pmap, va);
889b18bfc3dSJohn Dyson 		if (pa != (vm_offset_t) 0) {
890df8bae1dSRodney W. Grimes 			pmap_change_wiring(pmap, va, FALSE);
891df8bae1dSRodney W. Grimes 			vm_page_unwire(PHYS_TO_VM_PAGE(pa));
892df8bae1dSRodney W. Grimes 		}
893b18bfc3dSJohn Dyson 	}
894df8bae1dSRodney W. Grimes 
895df8bae1dSRodney W. Grimes 	/*
8960d94caffSDavid Greenman 	 * Inform the physical mapping system that the range of addresses may
8970d94caffSDavid Greenman 	 * fault, so that page tables and such may be unwired themselves.
898df8bae1dSRodney W. Grimes 	 */
899df8bae1dSRodney W. Grimes 
900df8bae1dSRodney W. Grimes 	pmap_pageable(pmap, start, end, TRUE);
901df8bae1dSRodney W. Grimes 
902df8bae1dSRodney W. Grimes }
903df8bae1dSRodney W. Grimes 
904df8bae1dSRodney W. Grimes /*
905df8bae1dSRodney W. Grimes  *	Routine:
906df8bae1dSRodney W. Grimes  *		vm_fault_copy_entry
907df8bae1dSRodney W. Grimes  *	Function:
908df8bae1dSRodney W. Grimes  *		Copy all of the pages from a wired-down map entry to another.
909df8bae1dSRodney W. Grimes  *
910df8bae1dSRodney W. Grimes  *	In/out conditions:
911df8bae1dSRodney W. Grimes  *		The source and destination maps must be locked for write.
912df8bae1dSRodney W. Grimes  *		The source map entry must be wired down (or be a sharing map
913df8bae1dSRodney W. Grimes  *		entry corresponding to a main map entry that is wired down).
914df8bae1dSRodney W. Grimes  */
915df8bae1dSRodney W. Grimes 
91626f9a767SRodney W. Grimes void
91726f9a767SRodney W. Grimes vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry)
918df8bae1dSRodney W. Grimes 	vm_map_t dst_map;
919df8bae1dSRodney W. Grimes 	vm_map_t src_map;
920df8bae1dSRodney W. Grimes 	vm_map_entry_t dst_entry;
921df8bae1dSRodney W. Grimes 	vm_map_entry_t src_entry;
922df8bae1dSRodney W. Grimes {
923df8bae1dSRodney W. Grimes 	vm_object_t dst_object;
924df8bae1dSRodney W. Grimes 	vm_object_t src_object;
925a316d390SJohn Dyson 	vm_ooffset_t dst_offset;
926a316d390SJohn Dyson 	vm_ooffset_t src_offset;
927df8bae1dSRodney W. Grimes 	vm_prot_t prot;
928df8bae1dSRodney W. Grimes 	vm_offset_t vaddr;
929df8bae1dSRodney W. Grimes 	vm_page_t dst_m;
930df8bae1dSRodney W. Grimes 	vm_page_t src_m;
931df8bae1dSRodney W. Grimes 
932df8bae1dSRodney W. Grimes #ifdef	lint
933df8bae1dSRodney W. Grimes 	src_map++;
9340d94caffSDavid Greenman #endif	/* lint */
935df8bae1dSRodney W. Grimes 
936df8bae1dSRodney W. Grimes 	src_object = src_entry->object.vm_object;
937df8bae1dSRodney W. Grimes 	src_offset = src_entry->offset;
938df8bae1dSRodney W. Grimes 
939df8bae1dSRodney W. Grimes 	/*
9400d94caffSDavid Greenman 	 * Create the top-level object for the destination entry. (Doesn't
9410d94caffSDavid Greenman 	 * actually shadow anything - we copy the pages directly.)
942df8bae1dSRodney W. Grimes 	 */
94324a1cce3SDavid Greenman 	dst_object = vm_object_allocate(OBJT_DEFAULT,
944a316d390SJohn Dyson 	    (vm_size_t) OFF_TO_IDX(dst_entry->end - dst_entry->start));
945df8bae1dSRodney W. Grimes 
946df8bae1dSRodney W. Grimes 	dst_entry->object.vm_object = dst_object;
947df8bae1dSRodney W. Grimes 	dst_entry->offset = 0;
948df8bae1dSRodney W. Grimes 
949df8bae1dSRodney W. Grimes 	prot = dst_entry->max_protection;
950df8bae1dSRodney W. Grimes 
951df8bae1dSRodney W. Grimes 	/*
9520d94caffSDavid Greenman 	 * Loop through all of the pages in the entry's range, copying each
9530d94caffSDavid Greenman 	 * one from the source object (it should be there) to the destination
9540d94caffSDavid Greenman 	 * object.
955df8bae1dSRodney W. Grimes 	 */
956df8bae1dSRodney W. Grimes 	for (vaddr = dst_entry->start, dst_offset = 0;
957df8bae1dSRodney W. Grimes 	    vaddr < dst_entry->end;
958df8bae1dSRodney W. Grimes 	    vaddr += PAGE_SIZE, dst_offset += PAGE_SIZE) {
959df8bae1dSRodney W. Grimes 
960df8bae1dSRodney W. Grimes 		/*
961df8bae1dSRodney W. Grimes 		 * Allocate a page in the destination object
962df8bae1dSRodney W. Grimes 		 */
963df8bae1dSRodney W. Grimes 		do {
964a316d390SJohn Dyson 			dst_m = vm_page_alloc(dst_object,
965a316d390SJohn Dyson 				OFF_TO_IDX(dst_offset), VM_ALLOC_NORMAL);
966df8bae1dSRodney W. Grimes 			if (dst_m == NULL) {
967df8bae1dSRodney W. Grimes 				VM_WAIT;
968df8bae1dSRodney W. Grimes 			}
969df8bae1dSRodney W. Grimes 		} while (dst_m == NULL);
970df8bae1dSRodney W. Grimes 
971df8bae1dSRodney W. Grimes 		/*
972df8bae1dSRodney W. Grimes 		 * Find the page in the source object, and copy it in.
9730d94caffSDavid Greenman 		 * (Because the source is wired down, the page will be in
9740d94caffSDavid Greenman 		 * memory.)
975df8bae1dSRodney W. Grimes 		 */
976a316d390SJohn Dyson 		src_m = vm_page_lookup(src_object,
977a316d390SJohn Dyson 			OFF_TO_IDX(dst_offset + src_offset));
978df8bae1dSRodney W. Grimes 		if (src_m == NULL)
979df8bae1dSRodney W. Grimes 			panic("vm_fault_copy_wired: page missing");
980df8bae1dSRodney W. Grimes 
981df8bae1dSRodney W. Grimes 		vm_page_copy(src_m, dst_m);
982df8bae1dSRodney W. Grimes 
983df8bae1dSRodney W. Grimes 		/*
984df8bae1dSRodney W. Grimes 		 * Enter it in the pmap...
985df8bae1dSRodney W. Grimes 		 */
986df8bae1dSRodney W. Grimes 
987ccbb2f72SJohn Dyson 		dst_m->flags &= ~PG_ZERO;
988df8bae1dSRodney W. Grimes 		pmap_enter(dst_map->pmap, vaddr, VM_PAGE_TO_PHYS(dst_m),
989df8bae1dSRodney W. Grimes 		    prot, FALSE);
990a6e6bcc5SJohn Dyson 		dst_m->flags |= PG_WRITEABLE|PG_MAPPED;
991df8bae1dSRodney W. Grimes 
992df8bae1dSRodney W. Grimes 		/*
993df8bae1dSRodney W. Grimes 		 * Mark it no longer busy, and put it on the active list.
994df8bae1dSRodney W. Grimes 		 */
995df8bae1dSRodney W. Grimes 		vm_page_activate(dst_m);
996df8bae1dSRodney W. Grimes 		PAGE_WAKEUP(dst_m);
997df8bae1dSRodney W. Grimes 	}
998df8bae1dSRodney W. Grimes }
99926f9a767SRodney W. Grimes 
100026f9a767SRodney W. Grimes 
100126f9a767SRodney W. Grimes /*
100226f9a767SRodney W. Grimes  * This routine checks around the requested page for other pages that
100322ba64e8SJohn Dyson  * might be able to be faulted in.  This routine brackets the viable
100422ba64e8SJohn Dyson  * pages for the pages to be paged in.
100526f9a767SRodney W. Grimes  *
100626f9a767SRodney W. Grimes  * Inputs:
100722ba64e8SJohn Dyson  *	m, rbehind, rahead
100826f9a767SRodney W. Grimes  *
100926f9a767SRodney W. Grimes  * Outputs:
101026f9a767SRodney W. Grimes  *  marray (array of vm_page_t), reqpage (index of requested page)
101126f9a767SRodney W. Grimes  *
101226f9a767SRodney W. Grimes  * Return value:
101326f9a767SRodney W. Grimes  *  number of pages in marray
101426f9a767SRodney W. Grimes  */
101526f9a767SRodney W. Grimes int
101622ba64e8SJohn Dyson vm_fault_additional_pages(m, rbehind, rahead, marray, reqpage)
101726f9a767SRodney W. Grimes 	vm_page_t m;
101826f9a767SRodney W. Grimes 	int rbehind;
101922ba64e8SJohn Dyson 	int rahead;
102026f9a767SRodney W. Grimes 	vm_page_t *marray;
102126f9a767SRodney W. Grimes 	int *reqpage;
102226f9a767SRodney W. Grimes {
10232d8acc0fSJohn Dyson 	int i,j;
102426f9a767SRodney W. Grimes 	vm_object_t object;
1025a316d390SJohn Dyson 	vm_pindex_t pindex, startpindex, endpindex, tpindex;
102626f9a767SRodney W. Grimes 	vm_page_t rtm;
1027170db9c6SJohn Dyson 	int cbehind, cahead;
102826f9a767SRodney W. Grimes 
102926f9a767SRodney W. Grimes 	object = m->object;
1030a316d390SJohn Dyson 	pindex = m->pindex;
103126f9a767SRodney W. Grimes 
103226f9a767SRodney W. Grimes 	/*
1033f35329acSJohn Dyson 	 * we don't fault-ahead for device pager
1034f35329acSJohn Dyson 	 */
1035f35329acSJohn Dyson 	if (object->type == OBJT_DEVICE) {
1036f35329acSJohn Dyson 		*reqpage = 0;
1037f35329acSJohn Dyson 		marray[0] = m;
1038f35329acSJohn Dyson 		return 1;
1039f35329acSJohn Dyson 	}
1040f35329acSJohn Dyson 
1041f35329acSJohn Dyson 	/*
104226f9a767SRodney W. Grimes 	 * if the requested page is not available, then give up now
104326f9a767SRodney W. Grimes 	 */
104426f9a767SRodney W. Grimes 
1045170db9c6SJohn Dyson 	if (!vm_pager_has_page(object,
10462d8acc0fSJohn Dyson 		OFF_TO_IDX(object->paging_offset) + pindex, &cbehind, &cahead)) {
104726f9a767SRodney W. Grimes 		return 0;
10482d8acc0fSJohn Dyson 	}
104926f9a767SRodney W. Grimes 
105022ba64e8SJohn Dyson 	if ((cbehind == 0) && (cahead == 0)) {
105122ba64e8SJohn Dyson 		*reqpage = 0;
105222ba64e8SJohn Dyson 		marray[0] = m;
105322ba64e8SJohn Dyson 		return 1;
1054170db9c6SJohn Dyson 	}
105522ba64e8SJohn Dyson 
105622ba64e8SJohn Dyson 	if (rahead > cahead) {
105722ba64e8SJohn Dyson 		rahead = cahead;
105822ba64e8SJohn Dyson 	}
105922ba64e8SJohn Dyson 
1060170db9c6SJohn Dyson 	if (rbehind > cbehind) {
1061170db9c6SJohn Dyson 		rbehind = cbehind;
1062170db9c6SJohn Dyson 	}
1063170db9c6SJohn Dyson 
106426f9a767SRodney W. Grimes 	/*
106526f9a767SRodney W. Grimes 	 * try to do any readahead that we might have free pages for.
106626f9a767SRodney W. Grimes 	 */
1067ccbb2f72SJohn Dyson 	if ((rahead + rbehind) >
106822ba64e8SJohn Dyson 		((cnt.v_free_count + cnt.v_cache_count) - cnt.v_free_reserved)) {
1069f919ebdeSDavid Greenman 		pagedaemon_wakeup();
107026f9a767SRodney W. Grimes 		marray[0] = m;
10712d8acc0fSJohn Dyson 		*reqpage = 0;
107226f9a767SRodney W. Grimes 		return 1;
107326f9a767SRodney W. Grimes 	}
107422ba64e8SJohn Dyson 
107526f9a767SRodney W. Grimes 	/*
10762d8acc0fSJohn Dyson 	 * scan backward for the read behind pages -- in memory
107726f9a767SRodney W. Grimes 	 */
10782d8acc0fSJohn Dyson 	if (pindex > 0) {
10792d8acc0fSJohn Dyson 		if (rbehind > pindex) {
1080a316d390SJohn Dyson 			rbehind = pindex;
10812d8acc0fSJohn Dyson 			startpindex = 0;
10822d8acc0fSJohn Dyson 		} else {
1083a316d390SJohn Dyson 			startpindex = pindex - rbehind;
10842d8acc0fSJohn Dyson 		}
10852d8acc0fSJohn Dyson 
10862d8acc0fSJohn Dyson 		for ( tpindex = pindex - 1; tpindex >= startpindex; tpindex -= 1) {
1087a316d390SJohn Dyson 			if (vm_page_lookup( object, tpindex)) {
1088a316d390SJohn Dyson 				startpindex = tpindex + 1;
108926f9a767SRodney W. Grimes 				break;
109026f9a767SRodney W. Grimes 			}
1091a316d390SJohn Dyson 			if (tpindex == 0)
109226f9a767SRodney W. Grimes 				break;
1093317205caSDavid Greenman 		}
109426f9a767SRodney W. Grimes 
10952d8acc0fSJohn Dyson 		for(i = 0, tpindex = startpindex; tpindex < pindex; i++, tpindex++) {
109626f9a767SRodney W. Grimes 
10972d8acc0fSJohn Dyson 			rtm = vm_page_alloc(object, tpindex, VM_ALLOC_NORMAL);
1098ccbb2f72SJohn Dyson 			if (rtm == NULL) {
1099ccbb2f72SJohn Dyson 				for (j = 0; j < i; j++) {
110021bf3904SJohn Dyson 					FREE_PAGE(marray[j]);
110126f9a767SRodney W. Grimes 				}
110226f9a767SRodney W. Grimes 				marray[0] = m;
11032d8acc0fSJohn Dyson 				*reqpage = 0;
110426f9a767SRodney W. Grimes 				return 1;
110526f9a767SRodney W. Grimes 			}
1106170db9c6SJohn Dyson 
11072d8acc0fSJohn Dyson 			marray[i] = rtm;
110826f9a767SRodney W. Grimes 		}
11092d8acc0fSJohn Dyson 	} else {
11102d8acc0fSJohn Dyson 		startpindex = 0;
11112d8acc0fSJohn Dyson 		i = 0;
11122d8acc0fSJohn Dyson 	}
11132d8acc0fSJohn Dyson 
11142d8acc0fSJohn Dyson 	marray[i] = m;
11152d8acc0fSJohn Dyson 	/* page offset of the required page */
11162d8acc0fSJohn Dyson 	*reqpage = i;
11172d8acc0fSJohn Dyson 
11182d8acc0fSJohn Dyson 	tpindex = pindex + 1;
11192d8acc0fSJohn Dyson 	i++;
11202d8acc0fSJohn Dyson 
11212d8acc0fSJohn Dyson 	/*
11222d8acc0fSJohn Dyson 	 * scan forward for the read ahead pages
11232d8acc0fSJohn Dyson 	 */
11242d8acc0fSJohn Dyson 	endpindex = tpindex + rahead;
11252d8acc0fSJohn Dyson 	if (endpindex > object->size)
11262d8acc0fSJohn Dyson 		endpindex = object->size;
11272d8acc0fSJohn Dyson 
11282d8acc0fSJohn Dyson 	for( ; tpindex < endpindex; i++, tpindex++) {
11292d8acc0fSJohn Dyson 
11302d8acc0fSJohn Dyson 		if (vm_page_lookup(object, tpindex)) {
11312d8acc0fSJohn Dyson 			break;
11322d8acc0fSJohn Dyson 		}
11332d8acc0fSJohn Dyson 
11342d8acc0fSJohn Dyson 		rtm = vm_page_alloc(object, tpindex, VM_ALLOC_NORMAL);
11352d8acc0fSJohn Dyson 		if (rtm == NULL) {
11362d8acc0fSJohn Dyson 			break;
11372d8acc0fSJohn Dyson 		}
11382d8acc0fSJohn Dyson 
11392d8acc0fSJohn Dyson 		marray[i] = rtm;
11402d8acc0fSJohn Dyson 	}
11412d8acc0fSJohn Dyson 
11422d8acc0fSJohn Dyson 	/* return number of bytes of pages */
11432d8acc0fSJohn Dyson 	return i;
114426f9a767SRodney W. Grimes }
1145