xref: /freebsd/sys/vm/vm_fault.c (revision 7aaaa4fd5d96bb6673a24c41e28152cbbd46457f)
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  *
697aaaa4fdSJohn Dyson  * $Id: vm_fault.c,v 1.58 1996/11/30 22:41:46 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>
8005f0fdd2SPoul-Henning Kamp #include <sys/resource.h>
8105f0fdd2SPoul-Henning Kamp #include <sys/signalvar.h>
8226f9a767SRodney W. Grimes #include <sys/resourcevar.h>
83efeaf95aSDavid Greenman #include <sys/vmmeter.h>
8409e0c6ccSJohn Dyson #include <sys/buf.h>
85df8bae1dSRodney W. Grimes 
86df8bae1dSRodney W. Grimes #include <vm/vm.h>
87efeaf95aSDavid Greenman #include <vm/vm_param.h>
88efeaf95aSDavid Greenman #include <vm/vm_prot.h>
89efeaf95aSDavid Greenman #include <vm/lock.h>
90efeaf95aSDavid Greenman #include <vm/pmap.h>
91efeaf95aSDavid Greenman #include <vm/vm_map.h>
92efeaf95aSDavid Greenman #include <vm/vm_object.h>
93df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
94df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h>
95a83c285cSDavid Greenman #include <vm/vm_kern.h>
9624a1cce3SDavid Greenman #include <vm/vm_pager.h>
9724a1cce3SDavid Greenman #include <vm/vnode_pager.h>
98cd41fc12SDavid Greenman #include <vm/swap_pager.h>
99efeaf95aSDavid Greenman #include <vm/vm_extern.h>
100df8bae1dSRodney W. Grimes 
10122ba64e8SJohn Dyson int vm_fault_additional_pages __P((vm_page_t, int, int, vm_page_t *, int *));
10226f9a767SRodney W. Grimes 
10326f9a767SRodney W. Grimes #define VM_FAULT_READ_AHEAD 4
10426f9a767SRodney W. Grimes #define VM_FAULT_READ_BEHIND 3
10526f9a767SRodney W. Grimes #define VM_FAULT_READ (VM_FAULT_READ_AHEAD+VM_FAULT_READ_BEHIND+1)
10626f9a767SRodney W. Grimes 
107df8bae1dSRodney W. Grimes /*
108df8bae1dSRodney W. Grimes  *	vm_fault:
109df8bae1dSRodney W. Grimes  *
110df8bae1dSRodney W. Grimes  *	Handle a page fault occuring at the given address,
111df8bae1dSRodney W. Grimes  *	requiring the given permissions, in the map specified.
112df8bae1dSRodney W. Grimes  *	If successful, the page is inserted into the
113df8bae1dSRodney W. Grimes  *	associated physical map.
114df8bae1dSRodney W. Grimes  *
115df8bae1dSRodney W. Grimes  *	NOTE: the given address should be truncated to the
116df8bae1dSRodney W. Grimes  *	proper page address.
117df8bae1dSRodney W. Grimes  *
118df8bae1dSRodney W. Grimes  *	KERN_SUCCESS is returned if the page fault is handled; otherwise,
119df8bae1dSRodney W. Grimes  *	a standard error specifying why the fault is fatal is returned.
120df8bae1dSRodney W. Grimes  *
121df8bae1dSRodney W. Grimes  *
122df8bae1dSRodney W. Grimes  *	The map in question must be referenced, and remains so.
123df8bae1dSRodney W. Grimes  *	Caller may hold no locks.
124df8bae1dSRodney W. Grimes  */
125df8bae1dSRodney W. Grimes int
126df8bae1dSRodney W. Grimes vm_fault(map, vaddr, fault_type, change_wiring)
127df8bae1dSRodney W. Grimes 	vm_map_t map;
128df8bae1dSRodney W. Grimes 	vm_offset_t vaddr;
129df8bae1dSRodney W. Grimes 	vm_prot_t fault_type;
130df8bae1dSRodney W. Grimes 	boolean_t change_wiring;
131df8bae1dSRodney W. Grimes {
132df8bae1dSRodney W. Grimes 	vm_object_t first_object;
133a316d390SJohn Dyson 	vm_pindex_t first_pindex;
134df8bae1dSRodney W. Grimes 	vm_map_entry_t entry;
135df8bae1dSRodney W. Grimes 	register vm_object_t object;
136a316d390SJohn Dyson 	register vm_pindex_t pindex;
13726f9a767SRodney W. Grimes 	vm_page_t m;
138df8bae1dSRodney W. Grimes 	vm_page_t first_m;
139df8bae1dSRodney W. Grimes 	vm_prot_t prot;
140df8bae1dSRodney W. Grimes 	int result;
141df8bae1dSRodney W. Grimes 	boolean_t wired;
142df8bae1dSRodney W. Grimes 	boolean_t su;
143df8bae1dSRodney W. Grimes 	boolean_t lookup_still_valid;
144df8bae1dSRodney W. Grimes 	vm_page_t old_m;
145df8bae1dSRodney W. Grimes 	vm_object_t next_object;
14626f9a767SRodney W. Grimes 	vm_page_t marray[VM_FAULT_READ];
14726f9a767SRodney W. Grimes 	int hardfault = 0;
148f6b04d2bSDavid Greenman 	struct vnode *vp = NULL;
149df8bae1dSRodney W. Grimes 
150b8d95f16SDavid Greenman 	cnt.v_vm_faults++;	/* needs lock XXX */
151df8bae1dSRodney W. Grimes /*
152df8bae1dSRodney W. Grimes  *	Recovery actions
153df8bae1dSRodney W. Grimes  */
154df8bae1dSRodney W. Grimes #define	FREE_PAGE(m)	{				\
155df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);					\
156df8bae1dSRodney W. Grimes 	vm_page_free(m);				\
157df8bae1dSRodney W. Grimes }
158df8bae1dSRodney W. Grimes 
159df8bae1dSRodney W. Grimes #define	RELEASE_PAGE(m)	{				\
160df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);					\
161bd7e5f99SJohn Dyson 	if (m->queue != PQ_ACTIVE) vm_page_activate(m);		\
162df8bae1dSRodney W. Grimes }
163df8bae1dSRodney W. Grimes 
164df8bae1dSRodney W. Grimes #define	UNLOCK_MAP	{				\
165df8bae1dSRodney W. Grimes 	if (lookup_still_valid) {			\
166df8bae1dSRodney W. Grimes 		vm_map_lookup_done(map, entry);		\
167df8bae1dSRodney W. Grimes 		lookup_still_valid = FALSE;		\
168df8bae1dSRodney W. Grimes 	}						\
169df8bae1dSRodney W. Grimes }
170df8bae1dSRodney W. Grimes 
171df8bae1dSRodney W. Grimes #define	UNLOCK_THINGS	{				\
172f919ebdeSDavid Greenman 	vm_object_pip_wakeup(object); \
173df8bae1dSRodney W. Grimes 	if (object != first_object) {			\
174df8bae1dSRodney W. Grimes 		FREE_PAGE(first_m);			\
175f919ebdeSDavid Greenman 		vm_object_pip_wakeup(first_object); \
176df8bae1dSRodney W. Grimes 	}						\
177df8bae1dSRodney W. Grimes 	UNLOCK_MAP;					\
17824a1cce3SDavid Greenman 	if (vp != NULL) VOP_UNLOCK(vp);			\
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:;
188df8bae1dSRodney W. Grimes 
189df8bae1dSRodney W. Grimes 	/*
1900d94caffSDavid Greenman 	 * Find the backing store object and offset into it to begin the
1910d94caffSDavid Greenman 	 * search.
192df8bae1dSRodney W. Grimes 	 */
193df8bae1dSRodney W. Grimes 
19422ba64e8SJohn Dyson 	if ((result = vm_map_lookup(&map, vaddr,
19522ba64e8SJohn Dyson 		fault_type, &entry, &first_object,
196a316d390SJohn Dyson 		&first_pindex, &prot, &wired, &su)) != KERN_SUCCESS) {
197df8bae1dSRodney W. Grimes 		return (result);
198df8bae1dSRodney W. Grimes 	}
199f6b04d2bSDavid Greenman 
20009e0c6ccSJohn Dyson 	if (entry->nofault) {
20109e0c6ccSJohn Dyson 		panic("vm_fault: fault on nofault entry, addr: %lx",
20209e0c6ccSJohn Dyson 			vaddr);
20309e0c6ccSJohn Dyson 	}
20409e0c6ccSJohn Dyson 
2057aaaa4fdSJohn Dyson 	/*
2067aaaa4fdSJohn Dyson 	 * If we are user-wiring a r/w segment, and it is COW, then
2077aaaa4fdSJohn Dyson 	 * we need to do the COW operation.  Note that we don't COW
2087aaaa4fdSJohn Dyson 	 * currently RO sections now, because there it is NOT desireable
2097aaaa4fdSJohn Dyson 	 * to COW .text.  We simply keep .text from ever being COW'ed
2107aaaa4fdSJohn Dyson 	 * and take the heat that one cannot debug wired .text sections.
2117aaaa4fdSJohn Dyson 	 */
2127aaaa4fdSJohn Dyson 	if ((change_wiring == VM_FAULT_USER_WIRE) && entry->needs_copy) {
2137aaaa4fdSJohn Dyson 		if(entry->protection & VM_PROT_WRITE) {
2147aaaa4fdSJohn Dyson 			int tresult;
2157aaaa4fdSJohn Dyson 			vm_map_lookup_done(map, entry);
2167aaaa4fdSJohn Dyson 
2177aaaa4fdSJohn Dyson 			tresult = vm_map_lookup(&map, vaddr, VM_PROT_READ|VM_PROT_WRITE,
2187aaaa4fdSJohn Dyson 				&entry, &first_object, &first_pindex, &prot, &wired, &su);
2197aaaa4fdSJohn Dyson 			if (tresult != KERN_SUCCESS)
2207aaaa4fdSJohn Dyson 				return tresult;
2217aaaa4fdSJohn Dyson 		} else {
2227aaaa4fdSJohn Dyson 			/*
2237aaaa4fdSJohn Dyson 			 * If we don't COW now, on a user wire, the user will never
2247aaaa4fdSJohn Dyson 			 * be able to write to the mapping.  If we don't make this
2257aaaa4fdSJohn Dyson 			 * restriction, the bookkeeping would be nearly impossible.
2267aaaa4fdSJohn Dyson 			 */
2277aaaa4fdSJohn Dyson 			entry->max_protection &= ~VM_PROT_WRITE;
2287aaaa4fdSJohn Dyson 		}
2297aaaa4fdSJohn Dyson 	}
2307aaaa4fdSJohn Dyson 
23124a1cce3SDavid Greenman 	vp = vnode_pager_lock(first_object);
232f6b04d2bSDavid Greenman 
233df8bae1dSRodney W. Grimes 	lookup_still_valid = TRUE;
234df8bae1dSRodney W. Grimes 
235df8bae1dSRodney W. Grimes 	if (wired)
236df8bae1dSRodney W. Grimes 		fault_type = prot;
237df8bae1dSRodney W. Grimes 
238df8bae1dSRodney W. Grimes 	first_m = NULL;
239df8bae1dSRodney W. Grimes 
240df8bae1dSRodney W. Grimes 	/*
2410d94caffSDavid Greenman 	 * Make a reference to this object to prevent its disposal while we
2420d94caffSDavid Greenman 	 * are messing with it.  Once we have the reference, the map is free
2430d94caffSDavid Greenman 	 * to be diddled.  Since objects reference their shadows (and copies),
2440d94caffSDavid Greenman 	 * they will stay around as well.
245df8bae1dSRodney W. Grimes 	 */
246df8bae1dSRodney W. Grimes 
247df8bae1dSRodney W. Grimes 	first_object->ref_count++;
248df8bae1dSRodney W. Grimes 	first_object->paging_in_progress++;
249df8bae1dSRodney W. Grimes 
250df8bae1dSRodney W. Grimes 	/*
251df8bae1dSRodney W. Grimes 	 * INVARIANTS (through entire routine):
252df8bae1dSRodney W. Grimes 	 *
2530d94caffSDavid Greenman 	 * 1)	At all times, we must either have the object lock or a busy
25424a1cce3SDavid Greenman 	 * page in some object to prevent some other process from trying to
2550d94caffSDavid Greenman 	 * bring in the same page.
256df8bae1dSRodney W. Grimes 	 *
2570d94caffSDavid Greenman 	 * Note that we cannot hold any locks during the pager access or when
2580d94caffSDavid Greenman 	 * waiting for memory, so we use a busy page then.
259df8bae1dSRodney W. Grimes 	 *
2600d94caffSDavid Greenman 	 * Note also that we aren't as concerned about more than one thead
2610d94caffSDavid Greenman 	 * attempting to pager_data_unlock the same page at once, so we don't
2620d94caffSDavid Greenman 	 * hold the page as busy then, but do record the highest unlock value
2630d94caffSDavid Greenman 	 * so far.  [Unlock requests may also be delivered out of order.]
264df8bae1dSRodney W. Grimes 	 *
2650d94caffSDavid Greenman 	 * 2)	Once we have a busy page, we must remove it from the pageout
2660d94caffSDavid Greenman 	 * queues, so that the pageout daemon will not grab it away.
267df8bae1dSRodney W. Grimes 	 *
26824a1cce3SDavid Greenman 	 * 3)	To prevent another process from racing us down the shadow chain
2690d94caffSDavid Greenman 	 * and entering a new page in the top object before we do, we must
2700d94caffSDavid Greenman 	 * keep a busy page in the top object while following the shadow
2710d94caffSDavid Greenman 	 * chain.
272df8bae1dSRodney W. Grimes 	 *
2730d94caffSDavid Greenman 	 * 4)	We must increment paging_in_progress on any object for which
2740d94caffSDavid Greenman 	 * we have a busy page, to prevent vm_object_collapse from removing
2750d94caffSDavid Greenman 	 * the busy page without our noticing.
276df8bae1dSRodney W. Grimes 	 */
277df8bae1dSRodney W. Grimes 
278df8bae1dSRodney W. Grimes 	/*
279df8bae1dSRodney W. Grimes 	 * Search for the page at object/offset.
280df8bae1dSRodney W. Grimes 	 */
281df8bae1dSRodney W. Grimes 
282df8bae1dSRodney W. Grimes 	object = first_object;
283a316d390SJohn Dyson 	pindex = first_pindex;
284df8bae1dSRodney W. Grimes 
285df8bae1dSRodney W. Grimes 	/*
286df8bae1dSRodney W. Grimes 	 * See whether this page is resident
287df8bae1dSRodney W. Grimes 	 */
288df8bae1dSRodney W. Grimes 
289df8bae1dSRodney W. Grimes 	while (TRUE) {
290a316d390SJohn Dyson 		m = vm_page_lookup(object, pindex);
291df8bae1dSRodney W. Grimes 		if (m != NULL) {
292c82b0181SJohn Dyson 			int queue;
293df8bae1dSRodney W. Grimes 			/*
2940d94caffSDavid Greenman 			 * If the page is being brought in, wait for it and
2950d94caffSDavid Greenman 			 * then retry.
296df8bae1dSRodney W. Grimes 			 */
2970d94caffSDavid Greenman 			if ((m->flags & PG_BUSY) || m->busy) {
29816f62314SDavid Greenman 				int s;
2990d94caffSDavid Greenman 
300df8bae1dSRodney W. Grimes 				UNLOCK_THINGS;
301b18bfc3dSJohn Dyson 				s = splvm();
302b18bfc3dSJohn Dyson 				if (((m->flags & PG_BUSY) || m->busy)) {
3030d94caffSDavid Greenman 					m->flags |= PG_WANTED | PG_REFERENCED;
304976e77fcSDavid Greenman 					cnt.v_intrans++;
30524a1cce3SDavid Greenman 					tsleep(m, PSWP, "vmpfw", 0);
30626f9a767SRodney W. Grimes 				}
30716f62314SDavid Greenman 				splx(s);
308df8bae1dSRodney W. Grimes 				vm_object_deallocate(first_object);
309df8bae1dSRodney W. Grimes 				goto RetryFault;
310df8bae1dSRodney W. Grimes 			}
311f6b04d2bSDavid Greenman 
312c82b0181SJohn Dyson 			queue = m->queue;
31367bf6868SJohn Dyson 			vm_page_unqueue_nowakeup(m);
314c82b0181SJohn Dyson 
315df8bae1dSRodney W. Grimes 			/*
31624a1cce3SDavid Greenman 			 * Mark page busy for other processes, and the pagedaemon.
317df8bae1dSRodney W. Grimes 			 */
3185070c7f8SJohn Dyson 			if (((queue - m->pc) == PQ_CACHE) &&
319886d3e11SJohn Dyson 			    (cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min) {
320c82b0181SJohn Dyson 				vm_page_activate(m);
32122ba64e8SJohn Dyson 				UNLOCK_AND_DEALLOCATE;
32222ba64e8SJohn Dyson 				VM_WAIT;
32322ba64e8SJohn Dyson 				goto RetryFault;
32422ba64e8SJohn Dyson 			}
32522ba64e8SJohn Dyson 
326886d3e11SJohn Dyson 			m->flags |= PG_BUSY;
3270ed43762SJohn Dyson 
328f230c45cSJohn Dyson 			if (m->valid &&
329f230c45cSJohn Dyson 				((m->valid & VM_PAGE_BITS_ALL) != VM_PAGE_BITS_ALL) &&
330f919ebdeSDavid Greenman 				m->object != kernel_object && m->object != kmem_object) {
3310d94caffSDavid Greenman 				goto readrest;
3320d94caffSDavid Greenman 			}
333df8bae1dSRodney W. Grimes 			break;
334df8bae1dSRodney W. Grimes 		}
33524a1cce3SDavid Greenman 		if (((object->type != OBJT_DEFAULT) && (!change_wiring || wired))
336df8bae1dSRodney W. Grimes 		    || (object == first_object)) {
337df8bae1dSRodney W. Grimes 
338a316d390SJohn Dyson 			if (pindex >= object->size) {
3395f55e841SDavid Greenman 				UNLOCK_AND_DEALLOCATE;
3405f55e841SDavid Greenman 				return (KERN_PROTECTION_FAILURE);
3415f55e841SDavid Greenman 			}
34222ba64e8SJohn Dyson 
343df8bae1dSRodney W. Grimes 			/*
3440d94caffSDavid Greenman 			 * Allocate a new page for this object/offset pair.
345df8bae1dSRodney W. Grimes 			 */
346a316d390SJohn Dyson 			m = vm_page_alloc(object, pindex,
347b18bfc3dSJohn Dyson 				(vp || object->backing_object)?VM_ALLOC_NORMAL:VM_ALLOC_ZERO);
348df8bae1dSRodney W. Grimes 
349df8bae1dSRodney W. Grimes 			if (m == NULL) {
350df8bae1dSRodney W. Grimes 				UNLOCK_AND_DEALLOCATE;
351df8bae1dSRodney W. Grimes 				VM_WAIT;
352df8bae1dSRodney W. Grimes 				goto RetryFault;
353df8bae1dSRodney W. Grimes 			}
354df8bae1dSRodney W. Grimes 		}
3550d94caffSDavid Greenman readrest:
35624a1cce3SDavid Greenman 		if (object->type != OBJT_DEFAULT && (!change_wiring || wired)) {
357df8bae1dSRodney W. Grimes 			int rv;
35826f9a767SRodney W. Grimes 			int faultcount;
35926f9a767SRodney W. Grimes 			int reqpage;
360867a482dSJohn Dyson 			int ahead, behind;
361867a482dSJohn Dyson 
362867a482dSJohn Dyson 			ahead = VM_FAULT_READ_AHEAD;
363867a482dSJohn Dyson 			behind = VM_FAULT_READ_BEHIND;
364867a482dSJohn Dyson 			if (first_object->behavior == OBJ_RANDOM) {
365867a482dSJohn Dyson 				ahead = 0;
366867a482dSJohn Dyson 				behind = 0;
367867a482dSJohn Dyson 			}
368867a482dSJohn Dyson 
369ff97964aSJohn Dyson 			if ((first_object->type != OBJT_DEVICE) &&
370ff97964aSJohn Dyson 				(first_object->behavior == OBJ_SEQUENTIAL)) {
371867a482dSJohn Dyson 				vm_pindex_t firstpindex, tmppindex;
372867a482dSJohn Dyson 				if (first_pindex <
373867a482dSJohn Dyson 					2*(VM_FAULT_READ_BEHIND + VM_FAULT_READ_AHEAD + 1))
374867a482dSJohn Dyson 					firstpindex = 0;
375867a482dSJohn Dyson 				else
376867a482dSJohn Dyson 					firstpindex = first_pindex -
377867a482dSJohn Dyson 						2*(VM_FAULT_READ_BEHIND + VM_FAULT_READ_AHEAD + 1);
378867a482dSJohn Dyson 
379867a482dSJohn Dyson 				for(tmppindex = first_pindex - 1;
380867a482dSJohn Dyson 					tmppindex >= first_pindex;
381867a482dSJohn Dyson 					--tmppindex) {
382867a482dSJohn Dyson 					vm_page_t mt;
383867a482dSJohn Dyson 					mt = vm_page_lookup( first_object, tmppindex);
384867a482dSJohn Dyson 					if (mt == NULL || (mt->valid != VM_PAGE_BITS_ALL))
385867a482dSJohn Dyson 						break;
386ff97964aSJohn Dyson 					if (mt->busy ||
387ff97964aSJohn Dyson 						(mt->flags & (PG_BUSY|PG_FICTITIOUS)) ||
388ff97964aSJohn Dyson 						mt->hold_count ||
389867a482dSJohn Dyson 						mt->wire_count)
390867a482dSJohn Dyson 						continue;
391867a482dSJohn Dyson 					if (mt->dirty == 0)
392867a482dSJohn Dyson 						vm_page_test_dirty(mt);
393867a482dSJohn Dyson 					if (mt->dirty) {
394867a482dSJohn Dyson 						vm_page_protect(mt, VM_PROT_NONE);
395867a482dSJohn Dyson 						vm_page_deactivate(mt);
396867a482dSJohn Dyson 					} else {
397867a482dSJohn Dyson 						vm_page_cache(mt);
398867a482dSJohn Dyson 					}
399867a482dSJohn Dyson 				}
400867a482dSJohn Dyson 
401867a482dSJohn Dyson 				ahead += behind;
402867a482dSJohn Dyson 				behind = 0;
403867a482dSJohn Dyson 			}
404df8bae1dSRodney W. Grimes 
405df8bae1dSRodney W. Grimes 			/*
4060d94caffSDavid Greenman 			 * now we find out if any other pages should be paged
4070d94caffSDavid Greenman 			 * in at this time this routine checks to see if the
4080d94caffSDavid Greenman 			 * pages surrounding this fault reside in the same
4090d94caffSDavid Greenman 			 * object as the page for this fault.  If they do,
4100d94caffSDavid Greenman 			 * then they are faulted in also into the object.  The
4110d94caffSDavid Greenman 			 * array "marray" returned contains an array of
4120d94caffSDavid Greenman 			 * vm_page_t structs where one of them is the
4130d94caffSDavid Greenman 			 * vm_page_t passed to the routine.  The reqpage
4140d94caffSDavid Greenman 			 * return value is the index into the marray for the
4150d94caffSDavid Greenman 			 * vm_page_t passed to the routine.
41626f9a767SRodney W. Grimes 			 */
41705f0fdd2SPoul-Henning Kamp 			faultcount = vm_fault_additional_pages(
418867a482dSJohn Dyson 			    m, behind, ahead, marray, &reqpage);
419df8bae1dSRodney W. Grimes 
420df8bae1dSRodney W. Grimes 			/*
4210d94caffSDavid Greenman 			 * Call the pager to retrieve the data, if any, after
4220d94caffSDavid Greenman 			 * releasing the lock on the map.
423df8bae1dSRodney W. Grimes 			 */
424df8bae1dSRodney W. Grimes 			UNLOCK_MAP;
425df8bae1dSRodney W. Grimes 
42626f9a767SRodney W. Grimes 			rv = faultcount ?
42724a1cce3SDavid Greenman 			    vm_pager_get_pages(object, marray, faultcount,
42824a1cce3SDavid Greenman 				reqpage) : VM_PAGER_FAIL;
42922ba64e8SJohn Dyson 
43026f9a767SRodney W. Grimes 			if (rv == VM_PAGER_OK) {
431df8bae1dSRodney W. Grimes 				/*
432f230c45cSJohn Dyson 				 * Found the page. Leave it busy while we play
433f230c45cSJohn Dyson 				 * with it.
434f230c45cSJohn Dyson 				 */
435f230c45cSJohn Dyson 
436f230c45cSJohn Dyson 				/*
4370d94caffSDavid Greenman 				 * Relookup in case pager changed page. Pager
4380d94caffSDavid Greenman 				 * is responsible for disposition of old page
4390d94caffSDavid Greenman 				 * if moved.
440df8bae1dSRodney W. Grimes 				 */
441a316d390SJohn Dyson 				m = vm_page_lookup(object, pindex);
442f6b04d2bSDavid Greenman 				if( !m) {
443f6b04d2bSDavid Greenman 					UNLOCK_AND_DEALLOCATE;
444f6b04d2bSDavid Greenman 					goto RetryFault;
445f6b04d2bSDavid Greenman 				}
446f6b04d2bSDavid Greenman 
44726f9a767SRodney W. Grimes 				hardfault++;
448df8bae1dSRodney W. Grimes 				break;
449df8bae1dSRodney W. Grimes 			}
450df8bae1dSRodney W. Grimes 			/*
4510d94caffSDavid Greenman 			 * Remove the bogus page (which does not exist at this
4520d94caffSDavid Greenman 			 * object/offset); before doing so, we must get back
4530d94caffSDavid Greenman 			 * our object lock to preserve our invariant.
454df8bae1dSRodney W. Grimes 			 *
45524a1cce3SDavid Greenman 			 * Also wake up any other process that may want to bring
4560d94caffSDavid Greenman 			 * in this page.
457df8bae1dSRodney W. Grimes 			 *
4580d94caffSDavid Greenman 			 * If this is the top-level object, we must leave the
45924a1cce3SDavid Greenman 			 * busy page to prevent another process from rushing
4600d94caffSDavid Greenman 			 * past us, and inserting the page in that object at
4610d94caffSDavid Greenman 			 * the same time that we are.
462df8bae1dSRodney W. Grimes 			 */
46326f9a767SRodney W. Grimes 
464a83c285cSDavid Greenman 			if (rv == VM_PAGER_ERROR)
465a83c285cSDavid Greenman 				printf("vm_fault: pager input (probably hardware) error, PID %d failure\n",
466a83c285cSDavid Greenman 				    curproc->p_pid);
46726f9a767SRodney W. Grimes 			/*
468a83c285cSDavid Greenman 			 * Data outside the range of the pager or an I/O error
46926f9a767SRodney W. Grimes 			 */
470a83c285cSDavid Greenman 			/*
4710d94caffSDavid Greenman 			 * XXX - the check for kernel_map is a kludge to work
4720d94caffSDavid Greenman 			 * around having the machine panic on a kernel space
4730d94caffSDavid Greenman 			 * fault w/ I/O error.
474a83c285cSDavid Greenman 			 */
475a83c285cSDavid Greenman 			if (((map != kernel_map) && (rv == VM_PAGER_ERROR)) || (rv == VM_PAGER_BAD)) {
47626f9a767SRodney W. Grimes 				FREE_PAGE(m);
47726f9a767SRodney W. Grimes 				UNLOCK_AND_DEALLOCATE;
478a83c285cSDavid Greenman 				return ((rv == VM_PAGER_ERROR) ? KERN_FAILURE : KERN_PROTECTION_FAILURE);
47926f9a767SRodney W. Grimes 			}
480df8bae1dSRodney W. Grimes 			if (object != first_object) {
481df8bae1dSRodney W. Grimes 				FREE_PAGE(m);
48226f9a767SRodney W. Grimes 				/*
48326f9a767SRodney W. Grimes 				 * XXX - we cannot just fall out at this
48426f9a767SRodney W. Grimes 				 * point, m has been freed and is invalid!
48526f9a767SRodney W. Grimes 				 */
486df8bae1dSRodney W. Grimes 			}
487df8bae1dSRodney W. Grimes 		}
488df8bae1dSRodney W. Grimes 		/*
48924a1cce3SDavid Greenman 		 * We get here if the object has default pager (or unwiring) or the
4900d94caffSDavid Greenman 		 * pager doesn't have the page.
491df8bae1dSRodney W. Grimes 		 */
492df8bae1dSRodney W. Grimes 		if (object == first_object)
493df8bae1dSRodney W. Grimes 			first_m = m;
494df8bae1dSRodney W. Grimes 
495df8bae1dSRodney W. Grimes 		/*
4960d94caffSDavid Greenman 		 * Move on to the next object.  Lock the next object before
4970d94caffSDavid Greenman 		 * unlocking the current one.
498df8bae1dSRodney W. Grimes 		 */
499df8bae1dSRodney W. Grimes 
500a316d390SJohn Dyson 		pindex += OFF_TO_IDX(object->backing_object_offset);
50124a1cce3SDavid Greenman 		next_object = object->backing_object;
502df8bae1dSRodney W. Grimes 		if (next_object == NULL) {
503df8bae1dSRodney W. Grimes 			/*
5040d94caffSDavid Greenman 			 * If there's no object left, fill the page in the top
5050d94caffSDavid Greenman 			 * object with zeros.
506df8bae1dSRodney W. Grimes 			 */
507df8bae1dSRodney W. Grimes 			if (object != first_object) {
508f919ebdeSDavid Greenman 				vm_object_pip_wakeup(object);
509df8bae1dSRodney W. Grimes 
510df8bae1dSRodney W. Grimes 				object = first_object;
511a316d390SJohn Dyson 				pindex = first_pindex;
512df8bae1dSRodney W. Grimes 				m = first_m;
513df8bae1dSRodney W. Grimes 			}
514df8bae1dSRodney W. Grimes 			first_m = NULL;
515df8bae1dSRodney W. Grimes 
516f230c45cSJohn Dyson 			if ((m->flags & PG_ZERO) == 0)
517df8bae1dSRodney W. Grimes 				vm_page_zero_fill(m);
518df8bae1dSRodney W. Grimes 			cnt.v_zfod++;
519df8bae1dSRodney W. Grimes 			break;
5200d94caffSDavid Greenman 		} else {
52126f9a767SRodney W. Grimes 			if (object != first_object) {
522f919ebdeSDavid Greenman 				vm_object_pip_wakeup(object);
523c0503609SDavid Greenman 			}
524df8bae1dSRodney W. Grimes 			object = next_object;
525df8bae1dSRodney W. Grimes 			object->paging_in_progress++;
526df8bae1dSRodney W. Grimes 		}
527df8bae1dSRodney W. Grimes 	}
528df8bae1dSRodney W. Grimes 
529f919ebdeSDavid Greenman 	if ((m->flags & PG_BUSY) == 0)
530f919ebdeSDavid Greenman 		panic("vm_fault: not busy after main loop");
531df8bae1dSRodney W. Grimes 
532df8bae1dSRodney W. Grimes 	/*
5330d94caffSDavid Greenman 	 * PAGE HAS BEEN FOUND. [Loop invariant still holds -- the object lock
534df8bae1dSRodney W. Grimes 	 * is held.]
535df8bae1dSRodney W. Grimes 	 */
536df8bae1dSRodney W. Grimes 
537df8bae1dSRodney W. Grimes 	old_m = m;	/* save page that would be copied */
538df8bae1dSRodney W. Grimes 
539df8bae1dSRodney W. Grimes 	/*
5400d94caffSDavid Greenman 	 * If the page is being written, but isn't already owned by the
5410d94caffSDavid Greenman 	 * top-level object, we have to copy it into a new page owned by the
5420d94caffSDavid Greenman 	 * top-level object.
543df8bae1dSRodney W. Grimes 	 */
544df8bae1dSRodney W. Grimes 
545df8bae1dSRodney W. Grimes 	if (object != first_object) {
546df8bae1dSRodney W. Grimes 		/*
5470d94caffSDavid Greenman 		 * We only really need to copy if we want to write it.
548df8bae1dSRodney W. Grimes 		 */
549df8bae1dSRodney W. Grimes 
550df8bae1dSRodney W. Grimes 		if (fault_type & VM_PROT_WRITE) {
551df8bae1dSRodney W. Grimes 
552df8bae1dSRodney W. Grimes 			/*
553b5b40fa6SJohn Dyson 			 * This allows pages to be virtually copied from a backing_object
554b5b40fa6SJohn Dyson 			 * into the first_object, where the backing object has no other
555b5b40fa6SJohn Dyson 			 * refs to it, and cannot gain any more refs.  Instead of a
556b5b40fa6SJohn Dyson 			 * bcopy, we just move the page from the backing object to the
557b5b40fa6SJohn Dyson 			 * first object.  Note that we must mark the page dirty in the
558b5b40fa6SJohn Dyson 			 * first object so that it will go out to swap when needed.
559df8bae1dSRodney W. Grimes 			 */
560de5f6a77SJohn Dyson 			if (lookup_still_valid &&
561de5f6a77SJohn Dyson 				/*
562de5f6a77SJohn Dyson 				 * Only one shadow object
563de5f6a77SJohn Dyson 				 */
564de5f6a77SJohn Dyson 				(object->shadow_count == 1) &&
565de5f6a77SJohn Dyson 				/*
566de5f6a77SJohn Dyson 				 * No COW refs, except us
567de5f6a77SJohn Dyson 				 */
568de5f6a77SJohn Dyson 				(object->ref_count == 1) &&
569de5f6a77SJohn Dyson 				/*
570de5f6a77SJohn Dyson 				 * Noone else can look this object up
571de5f6a77SJohn Dyson 				 */
572de5f6a77SJohn Dyson 				(object->handle == NULL) &&
573de5f6a77SJohn Dyson 				/*
574de5f6a77SJohn Dyson 				 * No other ways to look the object up
575de5f6a77SJohn Dyson 				 */
576de5f6a77SJohn Dyson 				((object->type == OBJT_DEFAULT) ||
577de5f6a77SJohn Dyson 				 (object->type == OBJT_SWAP)) &&
578de5f6a77SJohn Dyson 				/*
579de5f6a77SJohn Dyson 				 * We don't chase down the shadow chain
580de5f6a77SJohn Dyson 				 */
581de5f6a77SJohn Dyson 				(object == first_object->backing_object)) {
582df8bae1dSRodney W. Grimes 
583df8bae1dSRodney W. Grimes 				/*
584de5f6a77SJohn Dyson 				 * get rid of the unnecessary page
585df8bae1dSRodney W. Grimes 				 */
586de5f6a77SJohn Dyson 				vm_page_protect(first_m, VM_PROT_NONE);
587de5f6a77SJohn Dyson 				PAGE_WAKEUP(first_m);
588de5f6a77SJohn Dyson 				vm_page_free(first_m);
589de5f6a77SJohn Dyson 				/*
590de5f6a77SJohn Dyson 				 * grab the page and put it into the process'es object
591de5f6a77SJohn Dyson 				 */
592de5f6a77SJohn Dyson 				vm_page_rename(m, first_object, first_pindex);
593de5f6a77SJohn Dyson 				first_m = m;
594de5f6a77SJohn Dyson 				m->dirty = VM_PAGE_BITS_ALL;
595de5f6a77SJohn Dyson 				m = NULL;
596de5f6a77SJohn Dyson 			} else {
597de5f6a77SJohn Dyson 				/*
598de5f6a77SJohn Dyson 				 * Oh, well, lets copy it.
599de5f6a77SJohn Dyson 				 */
600de5f6a77SJohn Dyson 				vm_page_copy(m, first_m);
601de5f6a77SJohn Dyson 			}
602df8bae1dSRodney W. Grimes 
603b5b40fa6SJohn Dyson 			/*
604b5b40fa6SJohn Dyson 			 * This code handles the case where there are two references to the
605b5b40fa6SJohn Dyson 			 * backing object, and one reference is getting a copy of the
606b5b40fa6SJohn Dyson 			 * page.  If the other reference is the only other object that
607b5b40fa6SJohn Dyson 			 * points to the backing object, then perform a virtual copy
608b5b40fa6SJohn Dyson 			 * from the backing object to the other object after the
609b5b40fa6SJohn Dyson 			 * page is copied to the current first_object.  If the other
610b5b40fa6SJohn Dyson 			 * object already has the page, we destroy it in the backing object
611b5b40fa6SJohn Dyson 			 * performing an optimized collapse-type operation.  We don't
612b5b40fa6SJohn Dyson 			 * bother removing the page from the backing object's swap space.
613b5b40fa6SJohn Dyson 			 */
614de5f6a77SJohn Dyson 			if (lookup_still_valid &&
615de5f6a77SJohn Dyson 				/*
616de5f6a77SJohn Dyson 				 * make sure that we have two shadow objs
617de5f6a77SJohn Dyson 				 */
618de5f6a77SJohn Dyson 				(object->shadow_count == 2) &&
619de5f6a77SJohn Dyson 				/*
620de5f6a77SJohn Dyson 				 * And no COW refs -- note that there are sometimes
621de5f6a77SJohn Dyson 				 * temp refs to objs, but ignore that case -- we just
622de5f6a77SJohn Dyson 				 * punt.
623de5f6a77SJohn Dyson 				 */
624de5f6a77SJohn Dyson 				(object->ref_count == 2) &&
625de5f6a77SJohn Dyson 				/*
626de5f6a77SJohn Dyson 				 * Noone else can look us up
627de5f6a77SJohn Dyson 				 */
628de5f6a77SJohn Dyson 				(object->handle == NULL) &&
629de5f6a77SJohn Dyson 				/*
630de5f6a77SJohn Dyson 				 * Not something that can be referenced elsewhere
631de5f6a77SJohn Dyson 				 */
632de5f6a77SJohn Dyson 				((object->type == OBJT_DEFAULT) ||
633de5f6a77SJohn Dyson 				 (object->type == OBJT_SWAP)) &&
634de5f6a77SJohn Dyson 				/*
635de5f6a77SJohn Dyson 				 * We don't bother chasing down object chain
636de5f6a77SJohn Dyson 				 */
637de5f6a77SJohn Dyson 				(object == first_object->backing_object)) {
638de5f6a77SJohn Dyson 
639de5f6a77SJohn Dyson 				vm_object_t other_object;
640de5f6a77SJohn Dyson 				vm_pindex_t other_pindex, other_pindex_offset;
641de5f6a77SJohn Dyson 				vm_page_t tm;
642de5f6a77SJohn Dyson 
643b18bfc3dSJohn Dyson 				other_object = TAILQ_FIRST(&object->shadow_head);
644de5f6a77SJohn Dyson 				if (other_object == first_object)
645b18bfc3dSJohn Dyson 					other_object = TAILQ_NEXT(other_object, shadow_list);
646de5f6a77SJohn Dyson 				if (!other_object)
647de5f6a77SJohn Dyson 					panic("vm_fault: other object missing");
648de5f6a77SJohn Dyson 				if (other_object &&
649de5f6a77SJohn Dyson 					(other_object->type == OBJT_DEFAULT) &&
650de5f6a77SJohn Dyson 					(other_object->paging_in_progress == 0)) {
651de5f6a77SJohn Dyson 					other_pindex_offset =
652de5f6a77SJohn Dyson 						OFF_TO_IDX(other_object->backing_object_offset);
653de5f6a77SJohn Dyson 					if (pindex >= other_pindex_offset) {
654de5f6a77SJohn Dyson 						other_pindex = pindex - other_pindex_offset;
655de5f6a77SJohn Dyson 						/*
656de5f6a77SJohn Dyson 						 * If the other object has the page, just free it.
657de5f6a77SJohn Dyson 						 */
658de5f6a77SJohn Dyson 						if ((tm = vm_page_lookup(other_object, other_pindex))) {
659de5f6a77SJohn Dyson 							if ((tm->flags & PG_BUSY) == 0 &&
660de5f6a77SJohn Dyson 								tm->busy == 0 &&
661de5f6a77SJohn Dyson 								tm->valid == VM_PAGE_BITS_ALL) {
662de5f6a77SJohn Dyson 								/*
663de5f6a77SJohn Dyson 								 * get rid of the unnecessary page
664de5f6a77SJohn Dyson 								 */
665de5f6a77SJohn Dyson 								vm_page_protect(m, VM_PROT_NONE);
666de5f6a77SJohn Dyson 								PAGE_WAKEUP(m);
667de5f6a77SJohn Dyson 								vm_page_free(m);
668de5f6a77SJohn Dyson 								m = NULL;
669de5f6a77SJohn Dyson 								tm->dirty = VM_PAGE_BITS_ALL;
670de5f6a77SJohn Dyson 								first_m->dirty = VM_PAGE_BITS_ALL;
671de5f6a77SJohn Dyson 							}
672de5f6a77SJohn Dyson 						} else {
673de5f6a77SJohn Dyson 							/*
674de5f6a77SJohn Dyson 							 * If the other object doesn't have the page,
675de5f6a77SJohn Dyson 							 * then we move it there.
676de5f6a77SJohn Dyson 							 */
677de5f6a77SJohn Dyson 							vm_page_rename(m, other_object, other_pindex);
678de5f6a77SJohn Dyson 							m->dirty = VM_PAGE_BITS_ALL;
67965bc79b8SJohn Dyson 							m->valid = VM_PAGE_BITS_ALL;
680de5f6a77SJohn Dyson 						}
681de5f6a77SJohn Dyson 					}
682de5f6a77SJohn Dyson 				}
683de5f6a77SJohn Dyson 			}
684de5f6a77SJohn Dyson 
685de5f6a77SJohn Dyson 			if (m) {
686bd7e5f99SJohn Dyson 				if (m->queue != PQ_ACTIVE)
687df8bae1dSRodney W. Grimes 					vm_page_activate(m);
688df8bae1dSRodney W. Grimes 			/*
689df8bae1dSRodney W. Grimes 			 * We no longer need the old page or object.
690df8bae1dSRodney W. Grimes 			 */
691df8bae1dSRodney W. Grimes 				PAGE_WAKEUP(m);
692de5f6a77SJohn Dyson 			}
693df8bae1dSRodney W. Grimes 
694de5f6a77SJohn Dyson 			vm_object_pip_wakeup(object);
695df8bae1dSRodney W. Grimes 			/*
696df8bae1dSRodney W. Grimes 			 * Only use the new page below...
697df8bae1dSRodney W. Grimes 			 */
698df8bae1dSRodney W. Grimes 
699df8bae1dSRodney W. Grimes 			cnt.v_cow_faults++;
700df8bae1dSRodney W. Grimes 			m = first_m;
701df8bae1dSRodney W. Grimes 			object = first_object;
702a316d390SJohn Dyson 			pindex = first_pindex;
703df8bae1dSRodney W. Grimes 
704df8bae1dSRodney W. Grimes 			/*
7050d94caffSDavid Greenman 			 * Now that we've gotten the copy out of the way,
7060d94caffSDavid Greenman 			 * let's try to collapse the top object.
70724a1cce3SDavid Greenman 			 *
708df8bae1dSRodney W. Grimes 			 * But we have to play ugly games with
709df8bae1dSRodney W. Grimes 			 * paging_in_progress to do that...
710df8bae1dSRodney W. Grimes 			 */
711f919ebdeSDavid Greenman 			vm_object_pip_wakeup(object);
712df8bae1dSRodney W. Grimes 			vm_object_collapse(object);
713df8bae1dSRodney W. Grimes 			object->paging_in_progress++;
7140d94caffSDavid Greenman 		} else {
715df8bae1dSRodney W. Grimes 			prot &= ~VM_PROT_WRITE;
716df8bae1dSRodney W. Grimes 		}
717df8bae1dSRodney W. Grimes 	}
718df8bae1dSRodney W. Grimes 
719df8bae1dSRodney W. Grimes 	/*
7200d94caffSDavid Greenman 	 * We must verify that the maps have not changed since our last
7210d94caffSDavid Greenman 	 * lookup.
722df8bae1dSRodney W. Grimes 	 */
723df8bae1dSRodney W. Grimes 
724df8bae1dSRodney W. Grimes 	if (!lookup_still_valid) {
725df8bae1dSRodney W. Grimes 		vm_object_t retry_object;
726a316d390SJohn Dyson 		vm_pindex_t retry_pindex;
727df8bae1dSRodney W. Grimes 		vm_prot_t retry_prot;
728df8bae1dSRodney W. Grimes 
729df8bae1dSRodney W. Grimes 		/*
7300d94caffSDavid Greenman 		 * Since map entries may be pageable, make sure we can take a
7310d94caffSDavid Greenman 		 * page fault on them.
732df8bae1dSRodney W. Grimes 		 */
733df8bae1dSRodney W. Grimes 
734df8bae1dSRodney W. Grimes 		/*
73524a1cce3SDavid Greenman 		 * To avoid trying to write_lock the map while another process
7360d94caffSDavid Greenman 		 * has it read_locked (in vm_map_pageable), we do not try for
7370d94caffSDavid Greenman 		 * write permission.  If the page is still writable, we will
7380d94caffSDavid Greenman 		 * get write permission.  If it is not, or has been marked
7390d94caffSDavid Greenman 		 * needs_copy, we enter the mapping without write permission,
7400d94caffSDavid Greenman 		 * and will merely take another fault.
741df8bae1dSRodney W. Grimes 		 */
7420d94caffSDavid Greenman 		result = vm_map_lookup(&map, vaddr, fault_type & ~VM_PROT_WRITE,
743a316d390SJohn Dyson 		    &entry, &retry_object, &retry_pindex, &retry_prot, &wired, &su);
744df8bae1dSRodney W. Grimes 
745df8bae1dSRodney W. Grimes 		/*
7460d94caffSDavid Greenman 		 * If we don't need the page any longer, put it on the active
7470d94caffSDavid Greenman 		 * list (the easiest thing to do here).  If no one needs it,
7480d94caffSDavid Greenman 		 * pageout will grab it eventually.
749df8bae1dSRodney W. Grimes 		 */
750df8bae1dSRodney W. Grimes 
751df8bae1dSRodney W. Grimes 		if (result != KERN_SUCCESS) {
752df8bae1dSRodney W. Grimes 			RELEASE_PAGE(m);
753df8bae1dSRodney W. Grimes 			UNLOCK_AND_DEALLOCATE;
754df8bae1dSRodney W. Grimes 			return (result);
755df8bae1dSRodney W. Grimes 		}
756df8bae1dSRodney W. Grimes 		lookup_still_valid = TRUE;
757df8bae1dSRodney W. Grimes 
758df8bae1dSRodney W. Grimes 		if ((retry_object != first_object) ||
759a316d390SJohn Dyson 		    (retry_pindex != first_pindex)) {
760df8bae1dSRodney W. Grimes 			RELEASE_PAGE(m);
761df8bae1dSRodney W. Grimes 			UNLOCK_AND_DEALLOCATE;
762df8bae1dSRodney W. Grimes 			goto RetryFault;
763df8bae1dSRodney W. Grimes 		}
764df8bae1dSRodney W. Grimes 		/*
7650d94caffSDavid Greenman 		 * Check whether the protection has changed or the object has
7660d94caffSDavid Greenman 		 * been copied while we left the map unlocked. Changing from
7670d94caffSDavid Greenman 		 * read to write permission is OK - we leave the page
7680d94caffSDavid Greenman 		 * write-protected, and catch the write fault. Changing from
7690d94caffSDavid Greenman 		 * write to read permission means that we can't mark the page
7700d94caffSDavid Greenman 		 * write-enabled after all.
771df8bae1dSRodney W. Grimes 		 */
772df8bae1dSRodney W. Grimes 		prot &= retry_prot;
773df8bae1dSRodney W. Grimes 	}
774df8bae1dSRodney W. Grimes 
775df8bae1dSRodney W. Grimes 	/*
7760d94caffSDavid Greenman 	 * Put this page into the physical map. We had to do the unlock above
7770d94caffSDavid Greenman 	 * because pmap_enter may cause other faults.   We don't put the page
7780d94caffSDavid Greenman 	 * back on the active queue until later so that the page-out daemon
7790d94caffSDavid Greenman 	 * won't find us (yet).
780df8bae1dSRodney W. Grimes 	 */
781df8bae1dSRodney W. Grimes 
7822ddba215SDavid Greenman 	if (prot & VM_PROT_WRITE) {
783f919ebdeSDavid Greenman 		m->flags |= PG_WRITEABLE;
784aef922f5SJohn Dyson 		m->object->flags |= OBJ_WRITEABLE|OBJ_MIGHTBEDIRTY;
7852ddba215SDavid Greenman 		/*
7862ddba215SDavid Greenman 		 * If the fault is a write, we know that this page is being
7872ddba215SDavid Greenman 		 * written NOW. This will save on the pmap_is_modified() calls
7882ddba215SDavid Greenman 		 * later.
7892ddba215SDavid Greenman 		 */
7902ddba215SDavid Greenman 		if (fault_type & VM_PROT_WRITE) {
7912ddba215SDavid Greenman 			m->dirty = VM_PAGE_BITS_ALL;
7922ddba215SDavid Greenman 		}
7932ddba215SDavid Greenman 	}
794f6b04d2bSDavid Greenman 
79530dcfc09SJohn Dyson 	UNLOCK_THINGS;
79665bc79b8SJohn Dyson 	m->valid = VM_PAGE_BITS_ALL;
797ff97964aSJohn Dyson 	m->flags &= ~PG_ZERO;
798f919ebdeSDavid Greenman 
799df8bae1dSRodney W. Grimes 	pmap_enter(map->pmap, vaddr, VM_PAGE_TO_PHYS(m), prot, wired);
800b18bfc3dSJohn Dyson 	if ((change_wiring == 0) && (wired == 0))
8016d40c3d3SDavid Greenman 		pmap_prefault(map->pmap, vaddr, entry, first_object);
802df8bae1dSRodney W. Grimes 
803ff97964aSJohn Dyson 	m->flags |= PG_MAPPED|PG_REFERENCED;
804ff97964aSJohn Dyson 
805df8bae1dSRodney W. Grimes 	/*
8060d94caffSDavid Greenman 	 * If the page is not wired down, then put it where the pageout daemon
8070d94caffSDavid Greenman 	 * can find it.
808df8bae1dSRodney W. Grimes 	 */
809df8bae1dSRodney W. Grimes 	if (change_wiring) {
810df8bae1dSRodney W. Grimes 		if (wired)
811df8bae1dSRodney W. Grimes 			vm_page_wire(m);
812df8bae1dSRodney W. Grimes 		else
813df8bae1dSRodney W. Grimes 			vm_page_unwire(m);
8140d94caffSDavid Greenman 	} else {
815bd7e5f99SJohn Dyson 		if (m->queue != PQ_ACTIVE)
816df8bae1dSRodney W. Grimes 			vm_page_activate(m);
81726f9a767SRodney W. Grimes 	}
81826f9a767SRodney W. Grimes 
819a1f6d91cSDavid Greenman 	if (curproc && (curproc->p_flag & P_INMEM) && curproc->p_stats) {
82026f9a767SRodney W. Grimes 		if (hardfault) {
82126f9a767SRodney W. Grimes 			curproc->p_stats->p_ru.ru_majflt++;
82226f9a767SRodney W. Grimes 		} else {
82326f9a767SRodney W. Grimes 			curproc->p_stats->p_ru.ru_minflt++;
82426f9a767SRodney W. Grimes 		}
82526f9a767SRodney W. Grimes 	}
826df8bae1dSRodney W. Grimes 
827df8bae1dSRodney W. Grimes 	/*
828df8bae1dSRodney W. Grimes 	 * Unlock everything, and return
829df8bae1dSRodney W. Grimes 	 */
830df8bae1dSRodney W. Grimes 
831df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);
83230dcfc09SJohn Dyson 	vm_object_deallocate(first_object);
833df8bae1dSRodney W. Grimes 
834df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
835df8bae1dSRodney W. Grimes 
836df8bae1dSRodney W. Grimes }
837df8bae1dSRodney W. Grimes 
838df8bae1dSRodney W. Grimes /*
839df8bae1dSRodney W. Grimes  *	vm_fault_wire:
840df8bae1dSRodney W. Grimes  *
841df8bae1dSRodney W. Grimes  *	Wire down a range of virtual addresses in a map.
842df8bae1dSRodney W. Grimes  */
843df8bae1dSRodney W. Grimes int
844df8bae1dSRodney W. Grimes vm_fault_wire(map, start, end)
845df8bae1dSRodney W. Grimes 	vm_map_t map;
846df8bae1dSRodney W. Grimes 	vm_offset_t start, end;
847df8bae1dSRodney W. Grimes {
84826f9a767SRodney W. Grimes 
849df8bae1dSRodney W. Grimes 	register vm_offset_t va;
850df8bae1dSRodney W. Grimes 	register pmap_t pmap;
851df8bae1dSRodney W. Grimes 	int rv;
852df8bae1dSRodney W. Grimes 
853df8bae1dSRodney W. Grimes 	pmap = vm_map_pmap(map);
854df8bae1dSRodney W. Grimes 
855df8bae1dSRodney W. Grimes 	/*
8560d94caffSDavid Greenman 	 * Inform the physical mapping system that the range of addresses may
8570d94caffSDavid Greenman 	 * not fault, so that page tables and such can be locked down as well.
858df8bae1dSRodney W. Grimes 	 */
859df8bae1dSRodney W. Grimes 
860df8bae1dSRodney W. Grimes 	pmap_pageable(pmap, start, end, FALSE);
861df8bae1dSRodney W. Grimes 
862df8bae1dSRodney W. Grimes 	/*
8630d94caffSDavid Greenman 	 * We simulate a fault to get the page and enter it in the physical
8640d94caffSDavid Greenman 	 * map.
865df8bae1dSRodney W. Grimes 	 */
866df8bae1dSRodney W. Grimes 
867df8bae1dSRodney W. Grimes 	for (va = start; va < end; va += PAGE_SIZE) {
8687aaaa4fdSJohn Dyson 		rv = vm_fault(map, va, VM_PROT_READ|VM_PROT_WRITE,
8697aaaa4fdSJohn Dyson 			VM_FAULT_CHANGE_WIRING);
8707aaaa4fdSJohn Dyson 		if (rv) {
8717aaaa4fdSJohn Dyson 			if (va != start)
8727aaaa4fdSJohn Dyson 				vm_fault_unwire(map, start, va);
8737aaaa4fdSJohn Dyson 			return (rv);
8747aaaa4fdSJohn Dyson 		}
8757aaaa4fdSJohn Dyson 	}
8767aaaa4fdSJohn Dyson 	return (KERN_SUCCESS);
8777aaaa4fdSJohn Dyson }
8787aaaa4fdSJohn Dyson 
8797aaaa4fdSJohn Dyson /*
8807aaaa4fdSJohn Dyson  *	vm_fault_user_wire:
8817aaaa4fdSJohn Dyson  *
8827aaaa4fdSJohn Dyson  *	Wire down a range of virtual addresses in a map.  This
8837aaaa4fdSJohn Dyson  *	is for user mode though, so we only ask for read access
8847aaaa4fdSJohn Dyson  *	on currently read only sections.
8857aaaa4fdSJohn Dyson  */
8867aaaa4fdSJohn Dyson int
8877aaaa4fdSJohn Dyson vm_fault_user_wire(map, start, end)
8887aaaa4fdSJohn Dyson 	vm_map_t map;
8897aaaa4fdSJohn Dyson 	vm_offset_t start, end;
8907aaaa4fdSJohn Dyson {
8917aaaa4fdSJohn Dyson 
8927aaaa4fdSJohn Dyson 	register vm_offset_t va;
8937aaaa4fdSJohn Dyson 	register pmap_t pmap;
8947aaaa4fdSJohn Dyson 	int rv;
8957aaaa4fdSJohn Dyson 
8967aaaa4fdSJohn Dyson 	pmap = vm_map_pmap(map);
8977aaaa4fdSJohn Dyson 
8987aaaa4fdSJohn Dyson 	/*
8997aaaa4fdSJohn Dyson 	 * Inform the physical mapping system that the range of addresses may
9007aaaa4fdSJohn Dyson 	 * not fault, so that page tables and such can be locked down as well.
9017aaaa4fdSJohn Dyson 	 */
9027aaaa4fdSJohn Dyson 	pmap_pageable(pmap, start, end, FALSE);
9037aaaa4fdSJohn Dyson 
9047aaaa4fdSJohn Dyson 	/*
9057aaaa4fdSJohn Dyson 	 * We simulate a fault to get the page and enter it in the physical
9067aaaa4fdSJohn Dyson 	 * map.
9077aaaa4fdSJohn Dyson 	 */
9087aaaa4fdSJohn Dyson 	for (va = start; va < end; va += PAGE_SIZE) {
9097aaaa4fdSJohn Dyson 		rv = vm_fault(map, va, VM_PROT_READ, VM_FAULT_USER_WIRE);
910df8bae1dSRodney W. Grimes 		if (rv) {
911df8bae1dSRodney W. Grimes 			if (va != start)
912df8bae1dSRodney W. Grimes 				vm_fault_unwire(map, start, va);
913df8bae1dSRodney W. Grimes 			return (rv);
914df8bae1dSRodney W. Grimes 		}
915df8bae1dSRodney W. Grimes 	}
916df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
917df8bae1dSRodney W. Grimes }
918df8bae1dSRodney W. Grimes 
919df8bae1dSRodney W. Grimes 
920df8bae1dSRodney W. Grimes /*
921df8bae1dSRodney W. Grimes  *	vm_fault_unwire:
922df8bae1dSRodney W. Grimes  *
923df8bae1dSRodney W. Grimes  *	Unwire a range of virtual addresses in a map.
924df8bae1dSRodney W. Grimes  */
92526f9a767SRodney W. Grimes void
92626f9a767SRodney W. Grimes vm_fault_unwire(map, start, end)
927df8bae1dSRodney W. Grimes 	vm_map_t map;
928df8bae1dSRodney W. Grimes 	vm_offset_t start, end;
929df8bae1dSRodney W. Grimes {
930df8bae1dSRodney W. Grimes 
931df8bae1dSRodney W. Grimes 	register vm_offset_t va, pa;
932df8bae1dSRodney W. Grimes 	register pmap_t pmap;
933df8bae1dSRodney W. Grimes 
934df8bae1dSRodney W. Grimes 	pmap = vm_map_pmap(map);
935df8bae1dSRodney W. Grimes 
936df8bae1dSRodney W. Grimes 	/*
9370d94caffSDavid Greenman 	 * Since the pages are wired down, we must be able to get their
9380d94caffSDavid Greenman 	 * mappings from the physical map system.
939df8bae1dSRodney W. Grimes 	 */
940df8bae1dSRodney W. Grimes 
941df8bae1dSRodney W. Grimes 	for (va = start; va < end; va += PAGE_SIZE) {
942df8bae1dSRodney W. Grimes 		pa = pmap_extract(pmap, va);
943b18bfc3dSJohn Dyson 		if (pa != (vm_offset_t) 0) {
944df8bae1dSRodney W. Grimes 			pmap_change_wiring(pmap, va, FALSE);
945df8bae1dSRodney W. Grimes 			vm_page_unwire(PHYS_TO_VM_PAGE(pa));
946df8bae1dSRodney W. Grimes 		}
947b18bfc3dSJohn Dyson 	}
948df8bae1dSRodney W. Grimes 
949df8bae1dSRodney W. Grimes 	/*
9500d94caffSDavid Greenman 	 * Inform the physical mapping system that the range of addresses may
9510d94caffSDavid Greenman 	 * fault, so that page tables and such may be unwired themselves.
952df8bae1dSRodney W. Grimes 	 */
953df8bae1dSRodney W. Grimes 
954df8bae1dSRodney W. Grimes 	pmap_pageable(pmap, start, end, TRUE);
955df8bae1dSRodney W. Grimes 
956df8bae1dSRodney W. Grimes }
957df8bae1dSRodney W. Grimes 
958df8bae1dSRodney W. Grimes /*
959df8bae1dSRodney W. Grimes  *	Routine:
960df8bae1dSRodney W. Grimes  *		vm_fault_copy_entry
961df8bae1dSRodney W. Grimes  *	Function:
962df8bae1dSRodney W. Grimes  *		Copy all of the pages from a wired-down map entry to another.
963df8bae1dSRodney W. Grimes  *
964df8bae1dSRodney W. Grimes  *	In/out conditions:
965df8bae1dSRodney W. Grimes  *		The source and destination maps must be locked for write.
966df8bae1dSRodney W. Grimes  *		The source map entry must be wired down (or be a sharing map
967df8bae1dSRodney W. Grimes  *		entry corresponding to a main map entry that is wired down).
968df8bae1dSRodney W. Grimes  */
969df8bae1dSRodney W. Grimes 
97026f9a767SRodney W. Grimes void
97126f9a767SRodney W. Grimes vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry)
972df8bae1dSRodney W. Grimes 	vm_map_t dst_map;
973df8bae1dSRodney W. Grimes 	vm_map_t src_map;
974df8bae1dSRodney W. Grimes 	vm_map_entry_t dst_entry;
975df8bae1dSRodney W. Grimes 	vm_map_entry_t src_entry;
976df8bae1dSRodney W. Grimes {
977df8bae1dSRodney W. Grimes 	vm_object_t dst_object;
978df8bae1dSRodney W. Grimes 	vm_object_t src_object;
979a316d390SJohn Dyson 	vm_ooffset_t dst_offset;
980a316d390SJohn Dyson 	vm_ooffset_t src_offset;
981df8bae1dSRodney W. Grimes 	vm_prot_t prot;
982df8bae1dSRodney W. Grimes 	vm_offset_t vaddr;
983df8bae1dSRodney W. Grimes 	vm_page_t dst_m;
984df8bae1dSRodney W. Grimes 	vm_page_t src_m;
985df8bae1dSRodney W. Grimes 
986df8bae1dSRodney W. Grimes #ifdef	lint
987df8bae1dSRodney W. Grimes 	src_map++;
9880d94caffSDavid Greenman #endif	/* lint */
989df8bae1dSRodney W. Grimes 
990df8bae1dSRodney W. Grimes 	src_object = src_entry->object.vm_object;
991df8bae1dSRodney W. Grimes 	src_offset = src_entry->offset;
992df8bae1dSRodney W. Grimes 
993df8bae1dSRodney W. Grimes 	/*
9940d94caffSDavid Greenman 	 * Create the top-level object for the destination entry. (Doesn't
9950d94caffSDavid Greenman 	 * actually shadow anything - we copy the pages directly.)
996df8bae1dSRodney W. Grimes 	 */
99724a1cce3SDavid Greenman 	dst_object = vm_object_allocate(OBJT_DEFAULT,
998a316d390SJohn Dyson 	    (vm_size_t) OFF_TO_IDX(dst_entry->end - dst_entry->start));
999df8bae1dSRodney W. Grimes 
1000df8bae1dSRodney W. Grimes 	dst_entry->object.vm_object = dst_object;
1001df8bae1dSRodney W. Grimes 	dst_entry->offset = 0;
1002df8bae1dSRodney W. Grimes 
1003df8bae1dSRodney W. Grimes 	prot = dst_entry->max_protection;
1004df8bae1dSRodney W. Grimes 
1005df8bae1dSRodney W. Grimes 	/*
10060d94caffSDavid Greenman 	 * Loop through all of the pages in the entry's range, copying each
10070d94caffSDavid Greenman 	 * one from the source object (it should be there) to the destination
10080d94caffSDavid Greenman 	 * object.
1009df8bae1dSRodney W. Grimes 	 */
1010df8bae1dSRodney W. Grimes 	for (vaddr = dst_entry->start, dst_offset = 0;
1011df8bae1dSRodney W. Grimes 	    vaddr < dst_entry->end;
1012df8bae1dSRodney W. Grimes 	    vaddr += PAGE_SIZE, dst_offset += PAGE_SIZE) {
1013df8bae1dSRodney W. Grimes 
1014df8bae1dSRodney W. Grimes 		/*
1015df8bae1dSRodney W. Grimes 		 * Allocate a page in the destination object
1016df8bae1dSRodney W. Grimes 		 */
1017df8bae1dSRodney W. Grimes 		do {
1018a316d390SJohn Dyson 			dst_m = vm_page_alloc(dst_object,
1019a316d390SJohn Dyson 				OFF_TO_IDX(dst_offset), VM_ALLOC_NORMAL);
1020df8bae1dSRodney W. Grimes 			if (dst_m == NULL) {
1021df8bae1dSRodney W. Grimes 				VM_WAIT;
1022df8bae1dSRodney W. Grimes 			}
1023df8bae1dSRodney W. Grimes 		} while (dst_m == NULL);
1024df8bae1dSRodney W. Grimes 
1025df8bae1dSRodney W. Grimes 		/*
1026df8bae1dSRodney W. Grimes 		 * Find the page in the source object, and copy it in.
10270d94caffSDavid Greenman 		 * (Because the source is wired down, the page will be in
10280d94caffSDavid Greenman 		 * memory.)
1029df8bae1dSRodney W. Grimes 		 */
1030a316d390SJohn Dyson 		src_m = vm_page_lookup(src_object,
1031a316d390SJohn Dyson 			OFF_TO_IDX(dst_offset + src_offset));
1032df8bae1dSRodney W. Grimes 		if (src_m == NULL)
1033df8bae1dSRodney W. Grimes 			panic("vm_fault_copy_wired: page missing");
1034df8bae1dSRodney W. Grimes 
1035df8bae1dSRodney W. Grimes 		vm_page_copy(src_m, dst_m);
1036df8bae1dSRodney W. Grimes 
1037df8bae1dSRodney W. Grimes 		/*
1038df8bae1dSRodney W. Grimes 		 * Enter it in the pmap...
1039df8bae1dSRodney W. Grimes 		 */
1040df8bae1dSRodney W. Grimes 
1041ccbb2f72SJohn Dyson 		dst_m->flags &= ~PG_ZERO;
1042df8bae1dSRodney W. Grimes 		pmap_enter(dst_map->pmap, vaddr, VM_PAGE_TO_PHYS(dst_m),
1043df8bae1dSRodney W. Grimes 		    prot, FALSE);
1044a6e6bcc5SJohn Dyson 		dst_m->flags |= PG_WRITEABLE|PG_MAPPED;
1045df8bae1dSRodney W. Grimes 
1046df8bae1dSRodney W. Grimes 		/*
1047df8bae1dSRodney W. Grimes 		 * Mark it no longer busy, and put it on the active list.
1048df8bae1dSRodney W. Grimes 		 */
1049df8bae1dSRodney W. Grimes 		vm_page_activate(dst_m);
1050df8bae1dSRodney W. Grimes 		PAGE_WAKEUP(dst_m);
1051df8bae1dSRodney W. Grimes 	}
1052df8bae1dSRodney W. Grimes }
105326f9a767SRodney W. Grimes 
105426f9a767SRodney W. Grimes 
105526f9a767SRodney W. Grimes /*
105626f9a767SRodney W. Grimes  * This routine checks around the requested page for other pages that
105722ba64e8SJohn Dyson  * might be able to be faulted in.  This routine brackets the viable
105822ba64e8SJohn Dyson  * pages for the pages to be paged in.
105926f9a767SRodney W. Grimes  *
106026f9a767SRodney W. Grimes  * Inputs:
106122ba64e8SJohn Dyson  *	m, rbehind, rahead
106226f9a767SRodney W. Grimes  *
106326f9a767SRodney W. Grimes  * Outputs:
106426f9a767SRodney W. Grimes  *  marray (array of vm_page_t), reqpage (index of requested page)
106526f9a767SRodney W. Grimes  *
106626f9a767SRodney W. Grimes  * Return value:
106726f9a767SRodney W. Grimes  *  number of pages in marray
106826f9a767SRodney W. Grimes  */
106926f9a767SRodney W. Grimes int
107022ba64e8SJohn Dyson vm_fault_additional_pages(m, rbehind, rahead, marray, reqpage)
107126f9a767SRodney W. Grimes 	vm_page_t m;
107226f9a767SRodney W. Grimes 	int rbehind;
107322ba64e8SJohn Dyson 	int rahead;
107426f9a767SRodney W. Grimes 	vm_page_t *marray;
107526f9a767SRodney W. Grimes 	int *reqpage;
107626f9a767SRodney W. Grimes {
107726f9a767SRodney W. Grimes 	int i;
107826f9a767SRodney W. Grimes 	vm_object_t object;
1079a316d390SJohn Dyson 	vm_pindex_t pindex, startpindex, endpindex, tpindex;
1080a316d390SJohn Dyson 	vm_offset_t size;
108126f9a767SRodney W. Grimes 	vm_page_t rtm;
108226f9a767SRodney W. Grimes 	int treqpage;
1083170db9c6SJohn Dyson 	int cbehind, cahead;
108426f9a767SRodney W. Grimes 
108526f9a767SRodney W. Grimes 	object = m->object;
1086a316d390SJohn Dyson 	pindex = m->pindex;
108726f9a767SRodney W. Grimes 
108826f9a767SRodney W. Grimes 	/*
1089f35329acSJohn Dyson 	 * we don't fault-ahead for device pager
1090f35329acSJohn Dyson 	 */
1091f35329acSJohn Dyson 	if (object->type == OBJT_DEVICE) {
1092f35329acSJohn Dyson 		*reqpage = 0;
1093f35329acSJohn Dyson 		marray[0] = m;
1094f35329acSJohn Dyson 		return 1;
1095f35329acSJohn Dyson 	}
1096f35329acSJohn Dyson 
1097f35329acSJohn Dyson 	/*
109826f9a767SRodney W. Grimes 	 * if the requested page is not available, then give up now
109926f9a767SRodney W. Grimes 	 */
110026f9a767SRodney W. Grimes 
1101170db9c6SJohn Dyson 	if (!vm_pager_has_page(object,
1102a316d390SJohn Dyson 		OFF_TO_IDX(object->paging_offset) + pindex, &cbehind, &cahead))
110326f9a767SRodney W. Grimes 		return 0;
110426f9a767SRodney W. Grimes 
110522ba64e8SJohn Dyson 	if ((cbehind == 0) && (cahead == 0)) {
110622ba64e8SJohn Dyson 		*reqpage = 0;
110722ba64e8SJohn Dyson 		marray[0] = m;
110822ba64e8SJohn Dyson 		return 1;
1109170db9c6SJohn Dyson 	}
111022ba64e8SJohn Dyson 
111122ba64e8SJohn Dyson 	if (rahead > cahead) {
111222ba64e8SJohn Dyson 		rahead = cahead;
111322ba64e8SJohn Dyson 	}
111422ba64e8SJohn Dyson 
1115170db9c6SJohn Dyson 	if (rbehind > cbehind) {
1116170db9c6SJohn Dyson 		rbehind = cbehind;
1117170db9c6SJohn Dyson 	}
1118170db9c6SJohn Dyson 
111926f9a767SRodney W. Grimes 	/*
112026f9a767SRodney W. Grimes 	 * try to do any readahead that we might have free pages for.
112126f9a767SRodney W. Grimes 	 */
1122ccbb2f72SJohn Dyson 	if ((rahead + rbehind) >
112322ba64e8SJohn Dyson 		((cnt.v_free_count + cnt.v_cache_count) - cnt.v_free_reserved)) {
1124f919ebdeSDavid Greenman 		pagedaemon_wakeup();
112526f9a767SRodney W. Grimes 		*reqpage = 0;
112626f9a767SRodney W. Grimes 		marray[0] = m;
112726f9a767SRodney W. Grimes 		return 1;
112826f9a767SRodney W. Grimes 	}
112922ba64e8SJohn Dyson 
113026f9a767SRodney W. Grimes 	/*
11310d94caffSDavid Greenman 	 * scan backward for the read behind pages -- in memory or on disk not
11320d94caffSDavid Greenman 	 * in same object
113326f9a767SRodney W. Grimes 	 */
1134a316d390SJohn Dyson 	tpindex = pindex - 1;
1135a316d390SJohn Dyson 	if (tpindex < pindex) {
1136a316d390SJohn Dyson 		if (rbehind > pindex)
1137a316d390SJohn Dyson 			rbehind = pindex;
1138a316d390SJohn Dyson 		startpindex = pindex - rbehind;
1139a316d390SJohn Dyson 		while (tpindex >= startpindex) {
1140a316d390SJohn Dyson 			if (vm_page_lookup( object, tpindex)) {
1141a316d390SJohn Dyson 				startpindex = tpindex + 1;
114226f9a767SRodney W. Grimes 				break;
114326f9a767SRodney W. Grimes 			}
1144a316d390SJohn Dyson 			if (tpindex == 0)
114526f9a767SRodney W. Grimes 				break;
1146a316d390SJohn Dyson 			tpindex -= 1;
114726f9a767SRodney W. Grimes 		}
1148317205caSDavid Greenman 	} else {
1149a316d390SJohn Dyson 		startpindex = pindex;
1150317205caSDavid Greenman 	}
115126f9a767SRodney W. Grimes 
115226f9a767SRodney W. Grimes 	/*
11530d94caffSDavid Greenman 	 * scan forward for the read ahead pages -- in memory or on disk not
11540d94caffSDavid Greenman 	 * in same object
115526f9a767SRodney W. Grimes 	 */
1156a316d390SJohn Dyson 	tpindex = pindex + 1;
1157a316d390SJohn Dyson 	endpindex = pindex + (rahead + 1);
1158a316d390SJohn Dyson 	if (endpindex > object->size)
1159a316d390SJohn Dyson 		endpindex = object->size;
1160a316d390SJohn Dyson 	while (tpindex <  endpindex) {
1161a316d390SJohn Dyson 		if ( vm_page_lookup(object, tpindex)) {
116226f9a767SRodney W. Grimes 			break;
116326f9a767SRodney W. Grimes 		}
1164a316d390SJohn Dyson 		tpindex += 1;
116526f9a767SRodney W. Grimes 	}
1166a316d390SJohn Dyson 	endpindex = tpindex;
116726f9a767SRodney W. Grimes 
116826f9a767SRodney W. Grimes 	/* calculate number of bytes of pages */
1169a316d390SJohn Dyson 	size = endpindex - startpindex;
117026f9a767SRodney W. Grimes 
117126f9a767SRodney W. Grimes 	/* calculate the page offset of the required page */
1172a316d390SJohn Dyson 	treqpage = pindex - startpindex;
117326f9a767SRodney W. Grimes 
117426f9a767SRodney W. Grimes 	/* see if we have space (again) */
117522ba64e8SJohn Dyson 	if ((cnt.v_free_count + cnt.v_cache_count) >
117622ba64e8SJohn Dyson 		(cnt.v_free_reserved + size)) {
117726f9a767SRodney W. Grimes 		/*
117826f9a767SRodney W. Grimes 		 * get our pages and don't block for them
117926f9a767SRodney W. Grimes 		 */
118026f9a767SRodney W. Grimes 		for (i = 0; i < size; i++) {
1181170db9c6SJohn Dyson 			if (i != treqpage) {
1182ccbb2f72SJohn Dyson 				rtm = vm_page_alloc(object,
1183a316d390SJohn Dyson 					startpindex + i,
118422ba64e8SJohn Dyson 					VM_ALLOC_NORMAL);
1185ccbb2f72SJohn Dyson 				if (rtm == NULL) {
1186170db9c6SJohn Dyson 					if (i < treqpage) {
1187ccbb2f72SJohn Dyson 						int j;
1188ccbb2f72SJohn Dyson 						for (j = 0; j < i; j++) {
118921bf3904SJohn Dyson 							FREE_PAGE(marray[j]);
119026f9a767SRodney W. Grimes 						}
119126f9a767SRodney W. Grimes 						*reqpage = 0;
119226f9a767SRodney W. Grimes 						marray[0] = m;
119326f9a767SRodney W. Grimes 						return 1;
1194ccbb2f72SJohn Dyson 					} else {
1195ccbb2f72SJohn Dyson 						size = i;
1196ccbb2f72SJohn Dyson 						*reqpage = treqpage;
1197ccbb2f72SJohn Dyson 						return size;
1198ccbb2f72SJohn Dyson 					}
1199ccbb2f72SJohn Dyson 				}
1200ccbb2f72SJohn Dyson 				marray[i] = rtm;
1201ccbb2f72SJohn Dyson 			} else {
1202ccbb2f72SJohn Dyson 				marray[i] = m;
1203ccbb2f72SJohn Dyson 			}
120426f9a767SRodney W. Grimes 		}
1205170db9c6SJohn Dyson 
120626f9a767SRodney W. Grimes 		*reqpage = treqpage;
120726f9a767SRodney W. Grimes 		return size;
120826f9a767SRodney W. Grimes 	}
120926f9a767SRodney W. Grimes 	*reqpage = 0;
121026f9a767SRodney W. Grimes 	marray[0] = m;
121126f9a767SRodney W. Grimes 	return 1;
121226f9a767SRodney W. Grimes }
1213