xref: /freebsd/sys/vm/vm_fault.c (revision b8d95f16241c071e8ef92742e4a0ee83de8f1804)
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  *
69b8d95f16SDavid Greenman  * $Id: vm_fault.c,v 1.7 1994/10/09 01:52:07 phk 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>
7905f0fdd2SPoul-Henning Kamp #include <sys/resource.h>
8005f0fdd2SPoul-Henning Kamp #include <sys/signalvar.h>
8126f9a767SRodney W. Grimes #include <sys/resourcevar.h>
82df8bae1dSRodney W. Grimes 
83df8bae1dSRodney W. Grimes #include <vm/vm.h>
84df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
85df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h>
86df8bae1dSRodney W. Grimes 
8705f0fdd2SPoul-Henning Kamp int	vm_fault_additional_pages __P((vm_object_t, vm_offset_t, vm_page_t, int, int, vm_page_t *, int *));
8826f9a767SRodney W. Grimes 
8926f9a767SRodney W. Grimes #define VM_FAULT_READ_AHEAD 4
9026f9a767SRodney W. Grimes #define VM_FAULT_READ_AHEAD_MIN 1
9126f9a767SRodney W. Grimes #define VM_FAULT_READ_BEHIND 3
9226f9a767SRodney W. Grimes #define VM_FAULT_READ (VM_FAULT_READ_AHEAD+VM_FAULT_READ_BEHIND+1)
9326f9a767SRodney W. Grimes extern int swap_pager_full;
9426f9a767SRodney W. Grimes extern int vm_pageout_proc_limit;
9526f9a767SRodney W. Grimes 
96df8bae1dSRodney W. Grimes /*
97df8bae1dSRodney W. Grimes  *	vm_fault:
98df8bae1dSRodney W. Grimes  *
99df8bae1dSRodney W. Grimes  *	Handle a page fault occuring at the given address,
100df8bae1dSRodney W. Grimes  *	requiring the given permissions, in the map specified.
101df8bae1dSRodney W. Grimes  *	If successful, the page is inserted into the
102df8bae1dSRodney W. Grimes  *	associated physical map.
103df8bae1dSRodney W. Grimes  *
104df8bae1dSRodney W. Grimes  *	NOTE: the given address should be truncated to the
105df8bae1dSRodney W. Grimes  *	proper page address.
106df8bae1dSRodney W. Grimes  *
107df8bae1dSRodney W. Grimes  *	KERN_SUCCESS is returned if the page fault is handled; otherwise,
108df8bae1dSRodney W. Grimes  *	a standard error specifying why the fault is fatal is returned.
109df8bae1dSRodney W. Grimes  *
110df8bae1dSRodney W. Grimes  *
111df8bae1dSRodney W. Grimes  *	The map in question must be referenced, and remains so.
112df8bae1dSRodney W. Grimes  *	Caller may hold no locks.
113df8bae1dSRodney W. Grimes  */
114df8bae1dSRodney W. Grimes int
115df8bae1dSRodney W. Grimes vm_fault(map, vaddr, fault_type, change_wiring)
116df8bae1dSRodney W. Grimes 	vm_map_t	map;
117df8bae1dSRodney W. Grimes 	vm_offset_t	vaddr;
118df8bae1dSRodney W. Grimes 	vm_prot_t	fault_type;
119df8bae1dSRodney W. Grimes 	boolean_t	change_wiring;
120df8bae1dSRodney W. Grimes {
121df8bae1dSRodney W. Grimes 	vm_object_t		first_object;
122df8bae1dSRodney W. Grimes 	vm_offset_t		first_offset;
123df8bae1dSRodney W. Grimes 	vm_map_entry_t		entry;
124df8bae1dSRodney W. Grimes 	register vm_object_t	object;
125df8bae1dSRodney W. Grimes 	register vm_offset_t	offset;
12626f9a767SRodney W. Grimes 	vm_page_t	m;
127df8bae1dSRodney W. Grimes 	vm_page_t		first_m;
128df8bae1dSRodney W. Grimes 	vm_prot_t		prot;
129df8bae1dSRodney W. Grimes 	int			result;
130df8bae1dSRodney W. Grimes 	boolean_t		wired;
131df8bae1dSRodney W. Grimes 	boolean_t		su;
132df8bae1dSRodney W. Grimes 	boolean_t		lookup_still_valid;
133df8bae1dSRodney W. Grimes 	boolean_t		page_exists;
134df8bae1dSRodney W. Grimes 	vm_page_t		old_m;
135df8bae1dSRodney W. Grimes 	vm_object_t		next_object;
13626f9a767SRodney W. Grimes 	vm_page_t		marray[VM_FAULT_READ];
13726f9a767SRodney W. Grimes 	int			spl;
13826f9a767SRodney W. Grimes 	int			hardfault=0;
139df8bae1dSRodney W. Grimes 
140b8d95f16SDavid Greenman 	cnt.v_vm_faults++;		/* needs lock XXX */
141df8bae1dSRodney W. Grimes /*
142df8bae1dSRodney W. Grimes  *	Recovery actions
143df8bae1dSRodney W. Grimes  */
144df8bae1dSRodney W. Grimes #define	FREE_PAGE(m)	{				\
145df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);					\
146df8bae1dSRodney W. Grimes 	vm_page_lock_queues();				\
147df8bae1dSRodney W. Grimes 	vm_page_free(m);				\
148df8bae1dSRodney W. Grimes 	vm_page_unlock_queues();			\
149df8bae1dSRodney W. Grimes }
150df8bae1dSRodney W. Grimes 
151df8bae1dSRodney W. Grimes #define	RELEASE_PAGE(m)	{				\
152df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);					\
153df8bae1dSRodney W. Grimes 	vm_page_lock_queues();				\
154df8bae1dSRodney W. Grimes 	vm_page_activate(m);				\
155df8bae1dSRodney W. Grimes 	vm_page_unlock_queues();			\
156df8bae1dSRodney W. Grimes }
157df8bae1dSRodney W. Grimes 
158df8bae1dSRodney W. Grimes #define	UNLOCK_MAP	{				\
159df8bae1dSRodney W. Grimes 	if (lookup_still_valid) {			\
160df8bae1dSRodney W. Grimes 		vm_map_lookup_done(map, entry);		\
161df8bae1dSRodney W. Grimes 		lookup_still_valid = FALSE;		\
162df8bae1dSRodney W. Grimes 	}						\
163df8bae1dSRodney W. Grimes }
164df8bae1dSRodney W. Grimes 
165df8bae1dSRodney W. Grimes #define	UNLOCK_THINGS	{				\
166df8bae1dSRodney W. Grimes 	object->paging_in_progress--;			\
16726f9a767SRodney W. Grimes 	if (object->paging_in_progress == 0)		\
16826f9a767SRodney W. Grimes 		wakeup((caddr_t)object);		\
169df8bae1dSRodney W. Grimes 	vm_object_unlock(object);			\
170df8bae1dSRodney W. Grimes 	if (object != first_object) {			\
171df8bae1dSRodney W. Grimes 		vm_object_lock(first_object);		\
172df8bae1dSRodney W. Grimes 		FREE_PAGE(first_m);			\
173df8bae1dSRodney W. Grimes 		first_object->paging_in_progress--;	\
17426f9a767SRodney W. Grimes 		if (first_object->paging_in_progress == 0) \
17526f9a767SRodney W. Grimes 			wakeup((caddr_t)first_object);	\
176df8bae1dSRodney W. Grimes 		vm_object_unlock(first_object);		\
177df8bae1dSRodney W. Grimes 	}						\
178df8bae1dSRodney W. Grimes 	UNLOCK_MAP;					\
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 	/*
190df8bae1dSRodney W. Grimes 	 *	Find the backing store object and offset into
191df8bae1dSRodney W. Grimes 	 *	it to begin the search.
192df8bae1dSRodney W. Grimes 	 */
193df8bae1dSRodney W. Grimes 
194df8bae1dSRodney W. Grimes 	if ((result = vm_map_lookup(&map, vaddr, fault_type, &entry,
195df8bae1dSRodney W. Grimes 	    &first_object, &first_offset,
196df8bae1dSRodney W. Grimes 	    &prot, &wired, &su)) != KERN_SUCCESS) {
197df8bae1dSRodney W. Grimes 		return(result);
198df8bae1dSRodney W. Grimes 	}
199df8bae1dSRodney W. Grimes 	lookup_still_valid = TRUE;
200df8bae1dSRodney W. Grimes 
201df8bae1dSRodney W. Grimes 	if (wired)
202df8bae1dSRodney W. Grimes 		fault_type = prot;
203df8bae1dSRodney W. Grimes 
204df8bae1dSRodney W. Grimes 	first_m = NULL;
205df8bae1dSRodney W. Grimes 
206df8bae1dSRodney W. Grimes    	/*
207df8bae1dSRodney W. Grimes 	 *	Make a reference to this object to
208df8bae1dSRodney W. Grimes 	 *	prevent its disposal while we are messing with
209df8bae1dSRodney W. Grimes 	 *	it.  Once we have the reference, the map is free
210df8bae1dSRodney W. Grimes 	 *	to be diddled.  Since objects reference their
211df8bae1dSRodney W. Grimes 	 *	shadows (and copies), they will stay around as well.
212df8bae1dSRodney W. Grimes 	 */
213df8bae1dSRodney W. Grimes 
214df8bae1dSRodney W. Grimes 	vm_object_lock(first_object);
215df8bae1dSRodney W. Grimes 
216df8bae1dSRodney W. Grimes 	first_object->ref_count++;
217df8bae1dSRodney W. Grimes 	first_object->paging_in_progress++;
218df8bae1dSRodney W. Grimes 
219df8bae1dSRodney W. Grimes 	/*
220df8bae1dSRodney W. Grimes 	 *	INVARIANTS (through entire routine):
221df8bae1dSRodney W. Grimes 	 *
222df8bae1dSRodney W. Grimes 	 *	1)	At all times, we must either have the object
223df8bae1dSRodney W. Grimes 	 *		lock or a busy page in some object to prevent
224df8bae1dSRodney W. Grimes 	 *		some other thread from trying to bring in
225df8bae1dSRodney W. Grimes 	 *		the same page.
226df8bae1dSRodney W. Grimes 	 *
227df8bae1dSRodney W. Grimes 	 *		Note that we cannot hold any locks during the
228df8bae1dSRodney W. Grimes 	 *		pager access or when waiting for memory, so
229df8bae1dSRodney W. Grimes 	 *		we use a busy page then.
230df8bae1dSRodney W. Grimes 	 *
231df8bae1dSRodney W. Grimes 	 *		Note also that we aren't as concerned about
232df8bae1dSRodney W. Grimes 	 *		more than one thead attempting to pager_data_unlock
233df8bae1dSRodney W. Grimes 	 *		the same page at once, so we don't hold the page
234df8bae1dSRodney W. Grimes 	 *		as busy then, but do record the highest unlock
235df8bae1dSRodney W. Grimes 	 *		value so far.  [Unlock requests may also be delivered
236df8bae1dSRodney W. Grimes 	 *		out of order.]
237df8bae1dSRodney W. Grimes 	 *
238df8bae1dSRodney W. Grimes 	 *	2)	Once we have a busy page, we must remove it from
239df8bae1dSRodney W. Grimes 	 *		the pageout queues, so that the pageout daemon
240df8bae1dSRodney W. Grimes 	 *		will not grab it away.
241df8bae1dSRodney W. Grimes 	 *
242df8bae1dSRodney W. Grimes 	 *	3)	To prevent another thread from racing us down the
243df8bae1dSRodney W. Grimes 	 *		shadow chain and entering a new page in the top
244df8bae1dSRodney W. Grimes 	 *		object before we do, we must keep a busy page in
245df8bae1dSRodney W. Grimes 	 *		the top object while following the shadow chain.
246df8bae1dSRodney W. Grimes 	 *
247df8bae1dSRodney W. Grimes 	 *	4)	We must increment paging_in_progress on any object
248df8bae1dSRodney W. Grimes 	 *		for which we have a busy page, to prevent
249df8bae1dSRodney W. Grimes 	 *		vm_object_collapse from removing the busy page
250df8bae1dSRodney W. Grimes 	 *		without our noticing.
251df8bae1dSRodney W. Grimes 	 */
252df8bae1dSRodney W. Grimes 
253df8bae1dSRodney W. Grimes 	/*
254df8bae1dSRodney W. Grimes 	 *	Search for the page at object/offset.
255df8bae1dSRodney W. Grimes 	 */
256df8bae1dSRodney W. Grimes 
257df8bae1dSRodney W. Grimes 	object = first_object;
258df8bae1dSRodney W. Grimes 	offset = first_offset;
259df8bae1dSRodney W. Grimes 
260df8bae1dSRodney W. Grimes 	/*
261df8bae1dSRodney W. Grimes 	 *	See whether this page is resident
262df8bae1dSRodney W. Grimes 	 */
263df8bae1dSRodney W. Grimes 
264df8bae1dSRodney W. Grimes 	while (TRUE) {
265df8bae1dSRodney W. Grimes 		m = vm_page_lookup(object, offset);
266df8bae1dSRodney W. Grimes 		if (m != NULL) {
267df8bae1dSRodney W. Grimes 			/*
268df8bae1dSRodney W. Grimes 			 *	If the page is being brought in,
269df8bae1dSRodney W. Grimes 			 *	wait for it and then retry.
270df8bae1dSRodney W. Grimes 			 */
2718e58bf68SDavid Greenman 			if (m->flags & (PG_BUSY|PG_VMIO)) {
27216f62314SDavid Greenman 				int s;
273df8bae1dSRodney W. Grimes 				UNLOCK_THINGS;
27416f62314SDavid Greenman 				s = splhigh();
2758e58bf68SDavid Greenman 				if (m->flags & (PG_BUSY|PG_VMIO)) {
27626f9a767SRodney W. Grimes 					m->flags |= PG_WANTED;
27726f9a767SRodney W. Grimes 					tsleep((caddr_t)m,PSWP,"vmpfw",0);
27826f9a767SRodney W. Grimes 				}
27916f62314SDavid Greenman 				splx(s);
280df8bae1dSRodney W. Grimes 				vm_object_deallocate(first_object);
281df8bae1dSRodney W. Grimes 				goto RetryFault;
282df8bae1dSRodney W. Grimes 			}
283df8bae1dSRodney W. Grimes 
284df8bae1dSRodney W. Grimes 			/*
285df8bae1dSRodney W. Grimes 			 *	Remove the page from the pageout daemon's
286df8bae1dSRodney W. Grimes 			 *	reach while we play with it.
287df8bae1dSRodney W. Grimes 			 */
288df8bae1dSRodney W. Grimes 
289df8bae1dSRodney W. Grimes 			vm_page_lock_queues();
29016f62314SDavid Greenman 			spl = splhigh();
291df8bae1dSRodney W. Grimes 			if (m->flags & PG_INACTIVE) {
292df8bae1dSRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq);
293df8bae1dSRodney W. Grimes 				m->flags &= ~PG_INACTIVE;
294df8bae1dSRodney W. Grimes 				cnt.v_inactive_count--;
295df8bae1dSRodney W. Grimes 				cnt.v_reactivated++;
296df8bae1dSRodney W. Grimes 			}
297df8bae1dSRodney W. Grimes 
298df8bae1dSRodney W. Grimes 			if (m->flags & PG_ACTIVE) {
299df8bae1dSRodney W. Grimes 				TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
300df8bae1dSRodney W. Grimes 				m->flags &= ~PG_ACTIVE;
301df8bae1dSRodney W. Grimes 				cnt.v_active_count--;
302df8bae1dSRodney W. Grimes 			}
30326f9a767SRodney W. Grimes 			splx(spl);
304df8bae1dSRodney W. Grimes 			vm_page_unlock_queues();
305df8bae1dSRodney W. Grimes 
306df8bae1dSRodney W. Grimes 			/*
307df8bae1dSRodney W. Grimes 			 *	Mark page busy for other threads.
308df8bae1dSRodney W. Grimes 			 */
309df8bae1dSRodney W. Grimes 			m->flags |= PG_BUSY;
310df8bae1dSRodney W. Grimes 			break;
311df8bae1dSRodney W. Grimes 		}
312df8bae1dSRodney W. Grimes 
313df8bae1dSRodney W. Grimes 		if (((object->pager != NULL) &&
314df8bae1dSRodney W. Grimes 		    (!change_wiring || wired))
315df8bae1dSRodney W. Grimes 		    || (object == first_object)) {
316df8bae1dSRodney W. Grimes 
31726f9a767SRodney W. Grimes #if 0
31826f9a767SRodney W. Grimes 			if (curproc && (vaddr < VM_MAXUSER_ADDRESS) &&
31926f9a767SRodney W. Grimes 				(curproc->p_rlimit[RLIMIT_RSS].rlim_max <
32026f9a767SRodney W. Grimes 			    curproc->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG)) {
32126f9a767SRodney W. Grimes 				UNLOCK_AND_DEALLOCATE;
32226f9a767SRodney W. Grimes 				vm_fault_free_pages(curproc);
32326f9a767SRodney W. Grimes 				goto RetryFault;
32426f9a767SRodney W. Grimes 			}
32526f9a767SRodney W. Grimes #endif
32626f9a767SRodney W. Grimes 
32726f9a767SRodney W. Grimes 			if (swap_pager_full && !object->shadow && (!object->pager ||
32826f9a767SRodney W. Grimes 				(object->pager && object->pager->pg_type == PG_SWAP &&
32926f9a767SRodney W. Grimes 				!vm_pager_has_page(object->pager, offset+object->paging_offset)))) {
33026f9a767SRodney W. Grimes 				if (vaddr < VM_MAXUSER_ADDRESS && curproc && curproc->p_pid >= 48) /* XXX */ {
33105f0fdd2SPoul-Henning Kamp 					printf("Process %lu killed by vm_fault -- out of swap\n", (u_long)curproc->p_pid);
33226f9a767SRodney W. Grimes 					psignal(curproc, SIGKILL);
33326f9a767SRodney W. Grimes 					curproc->p_estcpu = 0;
33426f9a767SRodney W. Grimes 					curproc->p_nice = PRIO_MIN;
335da8b3304SDavid Greenman 					resetpriority(curproc);
33626f9a767SRodney W. Grimes 				}
33726f9a767SRodney W. Grimes 			}
33826f9a767SRodney W. Grimes 
339df8bae1dSRodney W. Grimes 			/*
340df8bae1dSRodney W. Grimes 			 *	Allocate a new page for this object/offset
341df8bae1dSRodney W. Grimes 			 *	pair.
342df8bae1dSRodney W. Grimes 			 */
343df8bae1dSRodney W. Grimes 
344df8bae1dSRodney W. Grimes 			m = vm_page_alloc(object, offset);
345df8bae1dSRodney W. Grimes 
346df8bae1dSRodney W. Grimes 			if (m == NULL) {
347df8bae1dSRodney W. Grimes 				UNLOCK_AND_DEALLOCATE;
348df8bae1dSRodney W. Grimes 				VM_WAIT;
349df8bae1dSRodney W. Grimes 				goto RetryFault;
350df8bae1dSRodney W. Grimes 			}
351df8bae1dSRodney W. Grimes 		}
352df8bae1dSRodney W. Grimes 
353df8bae1dSRodney W. Grimes 		if (object->pager != NULL && (!change_wiring || wired)) {
354df8bae1dSRodney W. Grimes 			int rv;
35526f9a767SRodney W. Grimes 			int faultcount;
35626f9a767SRodney W. Grimes 			int reqpage;
357df8bae1dSRodney W. Grimes 
358df8bae1dSRodney W. Grimes 			/*
359df8bae1dSRodney W. Grimes 			 *	Now that we have a busy page, we can
360df8bae1dSRodney W. Grimes 			 *	release the object lock.
361df8bae1dSRodney W. Grimes 			 */
362df8bae1dSRodney W. Grimes 			vm_object_unlock(object);
36326f9a767SRodney W. Grimes 			/*
36426f9a767SRodney W. Grimes 			 * now we find out if any other pages should
36526f9a767SRodney W. Grimes 			 * be paged in at this time
36626f9a767SRodney W. Grimes 			 * this routine checks to see if the pages surrounding this fault
36726f9a767SRodney W. Grimes 			 * reside in the same object as the page for this fault.  If
36826f9a767SRodney W. Grimes 			 * they do, then they are faulted in also into the
36926f9a767SRodney W. Grimes 			 * object.  The array "marray" returned contains an array of
37026f9a767SRodney W. Grimes 			 * vm_page_t structs where one of them is the vm_page_t passed to
37126f9a767SRodney W. Grimes 			 * the routine.  The reqpage return value is the index into the
37226f9a767SRodney W. Grimes 			 * marray for the vm_page_t passed to the routine.
37326f9a767SRodney W. Grimes 			 */
37426f9a767SRodney W. Grimes 			cnt.v_pageins++;
37505f0fdd2SPoul-Henning Kamp 			faultcount = vm_fault_additional_pages(
37605f0fdd2SPoul-Henning Kamp 				first_object, first_offset,
37705f0fdd2SPoul-Henning Kamp 				m, VM_FAULT_READ_BEHIND, VM_FAULT_READ_AHEAD,
37805f0fdd2SPoul-Henning Kamp 				marray, &reqpage);
379df8bae1dSRodney W. Grimes 
380df8bae1dSRodney W. Grimes 			/*
381df8bae1dSRodney W. Grimes 			 *	Call the pager to retrieve the data, if any,
382df8bae1dSRodney W. Grimes 			 *	after releasing the lock on the map.
383df8bae1dSRodney W. Grimes 			 */
384df8bae1dSRodney W. Grimes 			UNLOCK_MAP;
385df8bae1dSRodney W. Grimes 
38626f9a767SRodney W. Grimes 			rv = faultcount ?
38726f9a767SRodney W. Grimes 			    vm_pager_get_pages(object->pager,
38826f9a767SRodney W. Grimes 				marray, faultcount, reqpage, TRUE): VM_PAGER_FAIL;
38926f9a767SRodney W. Grimes 			if (rv == VM_PAGER_OK) {
390df8bae1dSRodney W. Grimes 				/*
391df8bae1dSRodney W. Grimes 				 *	Found the page.
392df8bae1dSRodney W. Grimes 				 *	Leave it busy while we play with it.
393df8bae1dSRodney W. Grimes 				 */
39426f9a767SRodney W. Grimes 				vm_object_lock(object);
39526f9a767SRodney W. Grimes 
396df8bae1dSRodney W. Grimes 				/*
397df8bae1dSRodney W. Grimes 				 *	Relookup in case pager changed page.
398df8bae1dSRodney W. Grimes 				 *	Pager is responsible for disposition
399df8bae1dSRodney W. Grimes 				 *	of old page if moved.
400df8bae1dSRodney W. Grimes 				 */
401df8bae1dSRodney W. Grimes 				m = vm_page_lookup(object, offset);
402df8bae1dSRodney W. Grimes 
403df8bae1dSRodney W. Grimes 				cnt.v_pgpgin++;
404df8bae1dSRodney W. Grimes 				m->flags &= ~PG_FAKE;
405df8bae1dSRodney W. Grimes 				pmap_clear_modify(VM_PAGE_TO_PHYS(m));
40626f9a767SRodney W. Grimes 				hardfault++;
407df8bae1dSRodney W. Grimes 				break;
408df8bae1dSRodney W. Grimes 			}
409df8bae1dSRodney W. Grimes 
410df8bae1dSRodney W. Grimes 			/*
41126f9a767SRodney W. Grimes 			 *	Remove the bogus page (which does not
41226f9a767SRodney W. Grimes 			 *	exist at this object/offset); before
41326f9a767SRodney W. Grimes 			 *	doing so, we must get back our object
41426f9a767SRodney W. Grimes 			 *	lock to preserve our invariant.
415df8bae1dSRodney W. Grimes 			 *
41626f9a767SRodney W. Grimes 			 *	Also wake up any other thread that may want
41726f9a767SRodney W. Grimes 			 *	to bring in this page.
418df8bae1dSRodney W. Grimes 			 *
419df8bae1dSRodney W. Grimes 			 *	If this is the top-level object, we must
420df8bae1dSRodney W. Grimes 			 *	leave the busy page to prevent another
421df8bae1dSRodney W. Grimes 			 *	thread from rushing past us, and inserting
422df8bae1dSRodney W. Grimes 			 *	the page in that object at the same time
423df8bae1dSRodney W. Grimes 			 *	that we are.
424df8bae1dSRodney W. Grimes 			 */
42526f9a767SRodney W. Grimes 
42626f9a767SRodney W. Grimes 			vm_object_lock(object);
42726f9a767SRodney W. Grimes 			/*
42826f9a767SRodney W. Grimes 			 * Data outside the range of the pager; an error
42926f9a767SRodney W. Grimes 			 */
43026f9a767SRodney W. Grimes 			if ((rv == VM_PAGER_ERROR) || (rv == VM_PAGER_BAD)) {
43126f9a767SRodney W. Grimes 				FREE_PAGE(m);
43226f9a767SRodney W. Grimes 				UNLOCK_AND_DEALLOCATE;
43326f9a767SRodney W. Grimes 				return(KERN_PROTECTION_FAILURE); /* XXX */
43426f9a767SRodney W. Grimes 			}
435df8bae1dSRodney W. Grimes 			if (object != first_object) {
436df8bae1dSRodney W. Grimes 				FREE_PAGE(m);
43726f9a767SRodney W. Grimes 				/*
43826f9a767SRodney W. Grimes 				 * XXX - we cannot just fall out at this
43926f9a767SRodney W. Grimes 				 * point, m has been freed and is invalid!
44026f9a767SRodney W. Grimes 				 */
441df8bae1dSRodney W. Grimes 			}
442df8bae1dSRodney W. Grimes 		}
443df8bae1dSRodney W. Grimes 
444df8bae1dSRodney W. Grimes 		/*
445df8bae1dSRodney W. Grimes 		 * We get here if the object has no pager (or unwiring)
446df8bae1dSRodney W. Grimes 		 * or the pager doesn't have the page.
447df8bae1dSRodney W. Grimes 		 */
448df8bae1dSRodney W. Grimes 		if (object == first_object)
449df8bae1dSRodney W. Grimes 			first_m = m;
450df8bae1dSRodney W. Grimes 
451df8bae1dSRodney W. Grimes 		/*
452df8bae1dSRodney W. Grimes 		 *	Move on to the next object.  Lock the next
453df8bae1dSRodney W. Grimes 		 *	object before unlocking the current one.
454df8bae1dSRodney W. Grimes 		 */
455df8bae1dSRodney W. Grimes 
456df8bae1dSRodney W. Grimes 		offset += object->shadow_offset;
457df8bae1dSRodney W. Grimes 		next_object = object->shadow;
458df8bae1dSRodney W. Grimes 		if (next_object == NULL) {
459df8bae1dSRodney W. Grimes 			/*
460df8bae1dSRodney W. Grimes 			 *	If there's no object left, fill the page
461df8bae1dSRodney W. Grimes 			 *	in the top object with zeros.
462df8bae1dSRodney W. Grimes 			 */
463df8bae1dSRodney W. Grimes 			if (object != first_object) {
464df8bae1dSRodney W. Grimes 				object->paging_in_progress--;
46526f9a767SRodney W. Grimes 				if (object->paging_in_progress == 0)
46626f9a767SRodney W. Grimes 					wakeup((caddr_t) object);
467df8bae1dSRodney W. Grimes 				vm_object_unlock(object);
468df8bae1dSRodney W. Grimes 
469df8bae1dSRodney W. Grimes 				object = first_object;
470df8bae1dSRodney W. Grimes 				offset = first_offset;
471df8bae1dSRodney W. Grimes 				m = first_m;
472df8bae1dSRodney W. Grimes 				vm_object_lock(object);
473df8bae1dSRodney W. Grimes 			}
474df8bae1dSRodney W. Grimes 			first_m = NULL;
475df8bae1dSRodney W. Grimes 
476df8bae1dSRodney W. Grimes 			vm_page_zero_fill(m);
477df8bae1dSRodney W. Grimes 			cnt.v_zfod++;
478df8bae1dSRodney W. Grimes 			m->flags &= ~PG_FAKE;
479df8bae1dSRodney W. Grimes 			break;
480df8bae1dSRodney W. Grimes 		}
481df8bae1dSRodney W. Grimes 		else {
482df8bae1dSRodney W. Grimes 			vm_object_lock(next_object);
48326f9a767SRodney W. Grimes 			if (object != first_object) {
484df8bae1dSRodney W. Grimes 				object->paging_in_progress--;
48526f9a767SRodney W. Grimes 				if (object->paging_in_progress == 0)
48626f9a767SRodney W. Grimes 					wakeup((caddr_t) object);
48726f9a767SRodney W. Grimes 			}
488df8bae1dSRodney W. Grimes 			vm_object_unlock(object);
489df8bae1dSRodney W. Grimes 			object = next_object;
490df8bae1dSRodney W. Grimes 			object->paging_in_progress++;
491df8bae1dSRodney W. Grimes 		}
492df8bae1dSRodney W. Grimes 	}
493df8bae1dSRodney W. Grimes 
49426f9a767SRodney W. Grimes 	if ((m->flags & (PG_ACTIVE|PG_INACTIVE) != 0) ||
49526f9a767SRodney W. Grimes 		(m->flags & PG_BUSY) == 0)
49626f9a767SRodney W. Grimes 		panic("vm_fault: absent or active or inactive or not busy after main loop");
497df8bae1dSRodney W. Grimes 
498df8bae1dSRodney W. Grimes 	/*
499df8bae1dSRodney W. Grimes 	 *	PAGE HAS BEEN FOUND.
500df8bae1dSRodney W. Grimes 	 *	[Loop invariant still holds -- the object lock
501df8bae1dSRodney W. Grimes 	 *	is held.]
502df8bae1dSRodney W. Grimes 	 */
503df8bae1dSRodney W. Grimes 
504df8bae1dSRodney W. Grimes 	old_m = m;	/* save page that would be copied */
505df8bae1dSRodney W. Grimes 
506df8bae1dSRodney W. Grimes 	/*
507df8bae1dSRodney W. Grimes 	 *	If the page is being written, but isn't
508df8bae1dSRodney W. Grimes 	 *	already owned by the top-level object,
509df8bae1dSRodney W. Grimes 	 *	we have to copy it into a new page owned
510df8bae1dSRodney W. Grimes 	 *	by the top-level object.
511df8bae1dSRodney W. Grimes 	 */
512df8bae1dSRodney W. Grimes 
513df8bae1dSRodney W. Grimes 	if (object != first_object) {
514df8bae1dSRodney W. Grimes 	    	/*
515df8bae1dSRodney W. Grimes 		 *	We only really need to copy if we
516df8bae1dSRodney W. Grimes 		 *	want to write it.
517df8bae1dSRodney W. Grimes 		 */
518df8bae1dSRodney W. Grimes 
519df8bae1dSRodney W. Grimes 	    	if (fault_type & VM_PROT_WRITE) {
520df8bae1dSRodney W. Grimes 
521df8bae1dSRodney W. Grimes 			/*
522df8bae1dSRodney W. Grimes 			 *	If we try to collapse first_object at this
523df8bae1dSRodney W. Grimes 			 *	point, we may deadlock when we try to get
524df8bae1dSRodney W. Grimes 			 *	the lock on an intermediate object (since we
525df8bae1dSRodney W. Grimes 			 *	have the bottom object locked).  We can't
526df8bae1dSRodney W. Grimes 			 *	unlock the bottom object, because the page
527df8bae1dSRodney W. Grimes 			 *	we found may move (by collapse) if we do.
528df8bae1dSRodney W. Grimes 			 *
529df8bae1dSRodney W. Grimes 			 *	Instead, we first copy the page.  Then, when
530df8bae1dSRodney W. Grimes 			 *	we have no more use for the bottom object,
531df8bae1dSRodney W. Grimes 			 *	we unlock it and try to collapse.
532df8bae1dSRodney W. Grimes 			 *
533df8bae1dSRodney W. Grimes 			 *	Note that we copy the page even if we didn't
534df8bae1dSRodney W. Grimes 			 *	need to... that's the breaks.
535df8bae1dSRodney W. Grimes 			 */
536df8bae1dSRodney W. Grimes 
537df8bae1dSRodney W. Grimes 		    	/*
538df8bae1dSRodney W. Grimes 			 *	We already have an empty page in
539df8bae1dSRodney W. Grimes 			 *	first_object - use it.
540df8bae1dSRodney W. Grimes 			 */
541df8bae1dSRodney W. Grimes 
542df8bae1dSRodney W. Grimes 			vm_page_copy(m, first_m);
543df8bae1dSRodney W. Grimes 			first_m->flags &= ~PG_FAKE;
544df8bae1dSRodney W. Grimes 
545df8bae1dSRodney W. Grimes 			/*
546df8bae1dSRodney W. Grimes 			 *	If another map is truly sharing this
547df8bae1dSRodney W. Grimes 			 *	page with us, we have to flush all
548df8bae1dSRodney W. Grimes 			 *	uses of the original page, since we
549df8bae1dSRodney W. Grimes 			 *	can't distinguish those which want the
550df8bae1dSRodney W. Grimes 			 *	original from those which need the
551df8bae1dSRodney W. Grimes 			 *	new copy.
552df8bae1dSRodney W. Grimes 			 *
553df8bae1dSRodney W. Grimes 			 *	XXX If we know that only one map has
554df8bae1dSRodney W. Grimes 			 *	access to this page, then we could
555df8bae1dSRodney W. Grimes 			 *	avoid the pmap_page_protect() call.
556df8bae1dSRodney W. Grimes 			 */
557df8bae1dSRodney W. Grimes 
558df8bae1dSRodney W. Grimes 			vm_page_lock_queues();
55926f9a767SRodney W. Grimes 
560df8bae1dSRodney W. Grimes 			vm_page_activate(m);
561df8bae1dSRodney W. Grimes 			pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE);
56226f9a767SRodney W. Grimes 			if ((m->flags & PG_CLEAN) == 0)
56326f9a767SRodney W. Grimes 				m->flags |= PG_LAUNDRY;
564df8bae1dSRodney W. Grimes 			vm_page_unlock_queues();
565df8bae1dSRodney W. Grimes 
566df8bae1dSRodney W. Grimes 			/*
567df8bae1dSRodney W. Grimes 			 *	We no longer need the old page or object.
568df8bae1dSRodney W. Grimes 			 */
569df8bae1dSRodney W. Grimes 			PAGE_WAKEUP(m);
570df8bae1dSRodney W. Grimes 			object->paging_in_progress--;
57126f9a767SRodney W. Grimes 			if (object->paging_in_progress == 0)
57226f9a767SRodney W. Grimes 				wakeup((caddr_t) object);
573df8bae1dSRodney W. Grimes 			vm_object_unlock(object);
574df8bae1dSRodney W. Grimes 
575df8bae1dSRodney W. Grimes 			/*
576df8bae1dSRodney W. Grimes 			 *	Only use the new page below...
577df8bae1dSRodney W. Grimes 			 */
578df8bae1dSRodney W. Grimes 
579df8bae1dSRodney W. Grimes 			cnt.v_cow_faults++;
580df8bae1dSRodney W. Grimes 			m = first_m;
581df8bae1dSRodney W. Grimes 			object = first_object;
582df8bae1dSRodney W. Grimes 			offset = first_offset;
583df8bae1dSRodney W. Grimes 
584df8bae1dSRodney W. Grimes 			/*
585df8bae1dSRodney W. Grimes 			 *	Now that we've gotten the copy out of the
586df8bae1dSRodney W. Grimes 			 *	way, let's try to collapse the top object.
587df8bae1dSRodney W. Grimes 			 */
588df8bae1dSRodney W. Grimes 			vm_object_lock(object);
589df8bae1dSRodney W. Grimes 			/*
590df8bae1dSRodney W. Grimes 			 *	But we have to play ugly games with
591df8bae1dSRodney W. Grimes 			 *	paging_in_progress to do that...
592df8bae1dSRodney W. Grimes 			 */
593df8bae1dSRodney W. Grimes 			object->paging_in_progress--;
59426f9a767SRodney W. Grimes 			if (object->paging_in_progress == 0)
59526f9a767SRodney W. Grimes 				wakeup((caddr_t) object);
596df8bae1dSRodney W. Grimes 			vm_object_collapse(object);
597df8bae1dSRodney W. Grimes 			object->paging_in_progress++;
598df8bae1dSRodney W. Grimes 		}
599df8bae1dSRodney W. Grimes 		else {
600df8bae1dSRodney W. Grimes 		    	prot &= ~VM_PROT_WRITE;
601df8bae1dSRodney W. Grimes 			m->flags |= PG_COPYONWRITE;
602df8bae1dSRodney W. Grimes 		}
603df8bae1dSRodney W. Grimes 	}
604df8bae1dSRodney W. Grimes 
605df8bae1dSRodney W. Grimes 	if (m->flags & (PG_ACTIVE|PG_INACTIVE))
606df8bae1dSRodney W. Grimes 		panic("vm_fault: active or inactive before copy object handling");
607df8bae1dSRodney W. Grimes 
608df8bae1dSRodney W. Grimes 	/*
609df8bae1dSRodney W. Grimes 	 *	If the page is being written, but hasn't been
610df8bae1dSRodney W. Grimes 	 *	copied to the copy-object, we have to copy it there.
611df8bae1dSRodney W. Grimes 	 */
612df8bae1dSRodney W. Grimes     RetryCopy:
613df8bae1dSRodney W. Grimes 	if (first_object->copy != NULL) {
614df8bae1dSRodney W. Grimes 		vm_object_t copy_object = first_object->copy;
615df8bae1dSRodney W. Grimes 		vm_offset_t copy_offset;
616df8bae1dSRodney W. Grimes 		vm_page_t copy_m;
617df8bae1dSRodney W. Grimes 
618df8bae1dSRodney W. Grimes 		/*
619df8bae1dSRodney W. Grimes 		 *	We only need to copy if we want to write it.
620df8bae1dSRodney W. Grimes 		 */
621df8bae1dSRodney W. Grimes 		if ((fault_type & VM_PROT_WRITE) == 0) {
622df8bae1dSRodney W. Grimes 			prot &= ~VM_PROT_WRITE;
623df8bae1dSRodney W. Grimes 			m->flags |= PG_COPYONWRITE;
624df8bae1dSRodney W. Grimes 		}
625df8bae1dSRodney W. Grimes 		else {
626df8bae1dSRodney W. Grimes 			/*
627df8bae1dSRodney W. Grimes 			 *	Try to get the lock on the copy_object.
628df8bae1dSRodney W. Grimes 			 */
629df8bae1dSRodney W. Grimes 			if (!vm_object_lock_try(copy_object)) {
630df8bae1dSRodney W. Grimes 				vm_object_unlock(object);
631df8bae1dSRodney W. Grimes 				/* should spin a bit here... */
632df8bae1dSRodney W. Grimes 				vm_object_lock(object);
633df8bae1dSRodney W. Grimes 				goto RetryCopy;
634df8bae1dSRodney W. Grimes 			}
635df8bae1dSRodney W. Grimes 
636df8bae1dSRodney W. Grimes 			/*
637df8bae1dSRodney W. Grimes 			 *	Make another reference to the copy-object,
638df8bae1dSRodney W. Grimes 			 *	to keep it from disappearing during the
639df8bae1dSRodney W. Grimes 			 *	copy.
640df8bae1dSRodney W. Grimes 			 */
641df8bae1dSRodney W. Grimes 			copy_object->ref_count++;
642df8bae1dSRodney W. Grimes 
643df8bae1dSRodney W. Grimes 			/*
644df8bae1dSRodney W. Grimes 			 *	Does the page exist in the copy?
645df8bae1dSRodney W. Grimes 			 */
646df8bae1dSRodney W. Grimes 			copy_offset = first_offset
647df8bae1dSRodney W. Grimes 				- copy_object->shadow_offset;
648df8bae1dSRodney W. Grimes 			copy_m = vm_page_lookup(copy_object, copy_offset);
64905f0fdd2SPoul-Henning Kamp 			page_exists = (copy_m != NULL);
65005f0fdd2SPoul-Henning Kamp 			if (page_exists) {
6518e58bf68SDavid Greenman 				if (copy_m->flags & (PG_BUSY|PG_VMIO)) {
652df8bae1dSRodney W. Grimes 					/*
653df8bae1dSRodney W. Grimes 					 *	If the page is being brought
654df8bae1dSRodney W. Grimes 					 *	in, wait for it and then retry.
655df8bae1dSRodney W. Grimes 					 */
656df8bae1dSRodney W. Grimes 					PAGE_ASSERT_WAIT(copy_m, !change_wiring);
657df8bae1dSRodney W. Grimes 					RELEASE_PAGE(m);
658df8bae1dSRodney W. Grimes 					copy_object->ref_count--;
659df8bae1dSRodney W. Grimes 					vm_object_unlock(copy_object);
660df8bae1dSRodney W. Grimes 					UNLOCK_THINGS;
66126f9a767SRodney W. Grimes 					thread_block("fltcpy");
662df8bae1dSRodney W. Grimes 					vm_object_deallocate(first_object);
663df8bae1dSRodney W. Grimes 					goto RetryFault;
664df8bae1dSRodney W. Grimes 				}
665df8bae1dSRodney W. Grimes 			}
666df8bae1dSRodney W. Grimes 
667df8bae1dSRodney W. Grimes 			/*
668df8bae1dSRodney W. Grimes 			 *	If the page is not in memory (in the object)
669df8bae1dSRodney W. Grimes 			 *	and the object has a pager, we have to check
670df8bae1dSRodney W. Grimes 			 *	if the pager has the data in secondary
671df8bae1dSRodney W. Grimes 			 *	storage.
672df8bae1dSRodney W. Grimes 			 */
673df8bae1dSRodney W. Grimes 			if (!page_exists) {
674df8bae1dSRodney W. Grimes 
675df8bae1dSRodney W. Grimes 				/*
676df8bae1dSRodney W. Grimes 				 *	If we don't allocate a (blank) page
677df8bae1dSRodney W. Grimes 				 *	here... another thread could try
678df8bae1dSRodney W. Grimes 				 *	to page it in, allocate a page, and
679df8bae1dSRodney W. Grimes 				 *	then block on the busy page in its
680df8bae1dSRodney W. Grimes 				 *	shadow (first_object).  Then we'd
681df8bae1dSRodney W. Grimes 				 *	trip over the busy page after we
682df8bae1dSRodney W. Grimes 				 *	found that the copy_object's pager
683df8bae1dSRodney W. Grimes 				 *	doesn't have the page...
684df8bae1dSRodney W. Grimes 				 */
68526f9a767SRodney W. Grimes 				copy_m = vm_page_alloc(copy_object, copy_offset);
686df8bae1dSRodney W. Grimes 				if (copy_m == NULL) {
687df8bae1dSRodney W. Grimes 					/*
688df8bae1dSRodney W. Grimes 					 *	Wait for a page, then retry.
689df8bae1dSRodney W. Grimes 					 */
690df8bae1dSRodney W. Grimes 					RELEASE_PAGE(m);
691df8bae1dSRodney W. Grimes 					copy_object->ref_count--;
692df8bae1dSRodney W. Grimes 					vm_object_unlock(copy_object);
693df8bae1dSRodney W. Grimes 					UNLOCK_AND_DEALLOCATE;
694df8bae1dSRodney W. Grimes 					VM_WAIT;
695df8bae1dSRodney W. Grimes 					goto RetryFault;
696df8bae1dSRodney W. Grimes 				}
697df8bae1dSRodney W. Grimes 
698df8bae1dSRodney W. Grimes 			 	if (copy_object->pager != NULL) {
699df8bae1dSRodney W. Grimes 					vm_object_unlock(object);
700df8bae1dSRodney W. Grimes 					vm_object_unlock(copy_object);
701df8bae1dSRodney W. Grimes 					UNLOCK_MAP;
702df8bae1dSRodney W. Grimes 
703df8bae1dSRodney W. Grimes 					page_exists = vm_pager_has_page(
704df8bae1dSRodney W. Grimes 							copy_object->pager,
705df8bae1dSRodney W. Grimes 							(copy_offset + copy_object->paging_offset));
706df8bae1dSRodney W. Grimes 
707df8bae1dSRodney W. Grimes 					vm_object_lock(copy_object);
708df8bae1dSRodney W. Grimes 
709df8bae1dSRodney W. Grimes 					/*
710df8bae1dSRodney W. Grimes 					 * Since the map is unlocked, someone
711df8bae1dSRodney W. Grimes 					 * else could have copied this object
712df8bae1dSRodney W. Grimes 					 * and put a different copy_object
713df8bae1dSRodney W. Grimes 					 * between the two.  Or, the last
714df8bae1dSRodney W. Grimes 					 * reference to the copy-object (other
715df8bae1dSRodney W. Grimes 					 * than the one we have) may have
716df8bae1dSRodney W. Grimes 					 * disappeared - if that has happened,
717df8bae1dSRodney W. Grimes 					 * we don't need to make the copy.
718df8bae1dSRodney W. Grimes 					 */
719df8bae1dSRodney W. Grimes 					if (copy_object->shadow != object ||
720df8bae1dSRodney W. Grimes 					    copy_object->ref_count == 1) {
721df8bae1dSRodney W. Grimes 						/*
722df8bae1dSRodney W. Grimes 						 *	Gaah... start over!
723df8bae1dSRodney W. Grimes 						 */
724df8bae1dSRodney W. Grimes 						FREE_PAGE(copy_m);
725df8bae1dSRodney W. Grimes 						vm_object_unlock(copy_object);
726df8bae1dSRodney W. Grimes 						vm_object_deallocate(copy_object);
727df8bae1dSRodney W. Grimes 							/* may block */
728df8bae1dSRodney W. Grimes 						vm_object_lock(object);
729df8bae1dSRodney W. Grimes 						goto RetryCopy;
730df8bae1dSRodney W. Grimes 					}
731df8bae1dSRodney W. Grimes 					vm_object_lock(object);
732df8bae1dSRodney W. Grimes 
733df8bae1dSRodney W. Grimes 					if (page_exists) {
734df8bae1dSRodney W. Grimes 						/*
735df8bae1dSRodney W. Grimes 						 *	We didn't need the page
736df8bae1dSRodney W. Grimes 						 */
737df8bae1dSRodney W. Grimes 						FREE_PAGE(copy_m);
738df8bae1dSRodney W. Grimes 					}
739df8bae1dSRodney W. Grimes 				}
740df8bae1dSRodney W. Grimes 			}
741df8bae1dSRodney W. Grimes 			if (!page_exists) {
742df8bae1dSRodney W. Grimes 				/*
743df8bae1dSRodney W. Grimes 				 *	Must copy page into copy-object.
744df8bae1dSRodney W. Grimes 				 */
745df8bae1dSRodney W. Grimes 				vm_page_copy(m, copy_m);
746df8bae1dSRodney W. Grimes 				copy_m->flags &= ~PG_FAKE;
747df8bae1dSRodney W. Grimes 
748df8bae1dSRodney W. Grimes 				/*
749df8bae1dSRodney W. Grimes 				 * Things to remember:
750df8bae1dSRodney W. Grimes 				 * 1. The copied page must be marked 'dirty'
751df8bae1dSRodney W. Grimes 				 *    so it will be paged out to the copy
752df8bae1dSRodney W. Grimes 				 *    object.
753df8bae1dSRodney W. Grimes 				 * 2. If the old page was in use by any users
754df8bae1dSRodney W. Grimes 				 *    of the copy-object, it must be removed
755df8bae1dSRodney W. Grimes 				 *    from all pmaps.  (We can't know which
756df8bae1dSRodney W. Grimes 				 *    pmaps use it.)
757df8bae1dSRodney W. Grimes 				 */
758df8bae1dSRodney W. Grimes 				vm_page_lock_queues();
75926f9a767SRodney W. Grimes 
76026f9a767SRodney W. Grimes 				vm_page_activate(old_m);
76126f9a767SRodney W. Grimes 
76226f9a767SRodney W. Grimes 
763df8bae1dSRodney W. Grimes 				pmap_page_protect(VM_PAGE_TO_PHYS(old_m),
764df8bae1dSRodney W. Grimes 						  VM_PROT_NONE);
76526f9a767SRodney W. Grimes 				if ((old_m->flags & PG_CLEAN) == 0)
76626f9a767SRodney W. Grimes 					old_m->flags |= PG_LAUNDRY;
767df8bae1dSRodney W. Grimes 				copy_m->flags &= ~PG_CLEAN;
76826f9a767SRodney W. Grimes 				vm_page_activate(copy_m);
769df8bae1dSRodney W. Grimes 				vm_page_unlock_queues();
770df8bae1dSRodney W. Grimes 
771df8bae1dSRodney W. Grimes 				PAGE_WAKEUP(copy_m);
772df8bae1dSRodney W. Grimes 			}
773df8bae1dSRodney W. Grimes 			/*
774df8bae1dSRodney W. Grimes 			 *	The reference count on copy_object must be
775df8bae1dSRodney W. Grimes 			 *	at least 2: one for our extra reference,
776df8bae1dSRodney W. Grimes 			 *	and at least one from the outside world
777df8bae1dSRodney W. Grimes 			 *	(we checked that when we last locked
778df8bae1dSRodney W. Grimes 			 *	copy_object).
779df8bae1dSRodney W. Grimes 			 */
780df8bae1dSRodney W. Grimes 			copy_object->ref_count--;
781df8bae1dSRodney W. Grimes 			vm_object_unlock(copy_object);
782df8bae1dSRodney W. Grimes 			m->flags &= ~PG_COPYONWRITE;
783df8bae1dSRodney W. Grimes 		}
784df8bae1dSRodney W. Grimes 	}
785df8bae1dSRodney W. Grimes 
786df8bae1dSRodney W. Grimes 	if (m->flags & (PG_ACTIVE | PG_INACTIVE))
787df8bae1dSRodney W. Grimes 		panic("vm_fault: active or inactive before retrying lookup");
788df8bae1dSRodney W. Grimes 
789df8bae1dSRodney W. Grimes 	/*
790df8bae1dSRodney W. Grimes 	 *	We must verify that the maps have not changed
791df8bae1dSRodney W. Grimes 	 *	since our last lookup.
792df8bae1dSRodney W. Grimes 	 */
793df8bae1dSRodney W. Grimes 
794df8bae1dSRodney W. Grimes 	if (!lookup_still_valid) {
795df8bae1dSRodney W. Grimes 		vm_object_t	retry_object;
796df8bae1dSRodney W. Grimes 		vm_offset_t	retry_offset;
797df8bae1dSRodney W. Grimes 		vm_prot_t	retry_prot;
798df8bae1dSRodney W. Grimes 
799df8bae1dSRodney W. Grimes 		/*
800df8bae1dSRodney W. Grimes 		 *	Since map entries may be pageable, make sure we can
801df8bae1dSRodney W. Grimes 		 *	take a page fault on them.
802df8bae1dSRodney W. Grimes 		 */
803df8bae1dSRodney W. Grimes 		vm_object_unlock(object);
804df8bae1dSRodney W. Grimes 
805df8bae1dSRodney W. Grimes 		/*
806df8bae1dSRodney W. Grimes 		 *	To avoid trying to write_lock the map while another
807df8bae1dSRodney W. Grimes 		 *	thread has it read_locked (in vm_map_pageable), we
808df8bae1dSRodney W. Grimes 		 *	do not try for write permission.  If the page is
809df8bae1dSRodney W. Grimes 		 *	still writable, we will get write permission.  If it
810df8bae1dSRodney W. Grimes 		 *	is not, or has been marked needs_copy, we enter the
811df8bae1dSRodney W. Grimes 		 *	mapping without write permission, and will merely
812df8bae1dSRodney W. Grimes 		 *	take another fault.
813df8bae1dSRodney W. Grimes 		 */
814df8bae1dSRodney W. Grimes 		result = vm_map_lookup(&map, vaddr,
815df8bae1dSRodney W. Grimes 				fault_type & ~VM_PROT_WRITE, &entry,
816df8bae1dSRodney W. Grimes 				&retry_object, &retry_offset, &retry_prot,
817df8bae1dSRodney W. Grimes 				&wired, &su);
818df8bae1dSRodney W. Grimes 
819df8bae1dSRodney W. Grimes 		vm_object_lock(object);
820df8bae1dSRodney W. Grimes 
821df8bae1dSRodney W. Grimes 		/*
822df8bae1dSRodney W. Grimes 		 *	If we don't need the page any longer, put it on the
823df8bae1dSRodney W. Grimes 		 *	active list (the easiest thing to do here).  If no
824df8bae1dSRodney W. Grimes 		 *	one needs it, pageout will grab it eventually.
825df8bae1dSRodney W. Grimes 		 */
826df8bae1dSRodney W. Grimes 
827df8bae1dSRodney W. Grimes 		if (result != KERN_SUCCESS) {
828df8bae1dSRodney W. Grimes 			RELEASE_PAGE(m);
829df8bae1dSRodney W. Grimes 			UNLOCK_AND_DEALLOCATE;
830df8bae1dSRodney W. Grimes 			return(result);
831df8bae1dSRodney W. Grimes 		}
832df8bae1dSRodney W. Grimes 
833df8bae1dSRodney W. Grimes 		lookup_still_valid = TRUE;
834df8bae1dSRodney W. Grimes 
835df8bae1dSRodney W. Grimes 		if ((retry_object != first_object) ||
836df8bae1dSRodney W. Grimes 				(retry_offset != first_offset)) {
837df8bae1dSRodney W. Grimes 			RELEASE_PAGE(m);
838df8bae1dSRodney W. Grimes 			UNLOCK_AND_DEALLOCATE;
839df8bae1dSRodney W. Grimes 			goto RetryFault;
840df8bae1dSRodney W. Grimes 		}
841df8bae1dSRodney W. Grimes 
842df8bae1dSRodney W. Grimes 		/*
843df8bae1dSRodney W. Grimes 		 *	Check whether the protection has changed or the object
844df8bae1dSRodney W. Grimes 		 *	has been copied while we left the map unlocked.
845df8bae1dSRodney W. Grimes 		 *	Changing from read to write permission is OK - we leave
846df8bae1dSRodney W. Grimes 		 *	the page write-protected, and catch the write fault.
847df8bae1dSRodney W. Grimes 		 *	Changing from write to read permission means that we
848df8bae1dSRodney W. Grimes 		 *	can't mark the page write-enabled after all.
849df8bae1dSRodney W. Grimes 		 */
850df8bae1dSRodney W. Grimes 		prot &= retry_prot;
851df8bae1dSRodney W. Grimes 		if (m->flags & PG_COPYONWRITE)
852df8bae1dSRodney W. Grimes 			prot &= ~VM_PROT_WRITE;
853df8bae1dSRodney W. Grimes 	}
854df8bae1dSRodney W. Grimes 
855df8bae1dSRodney W. Grimes 	/*
856df8bae1dSRodney W. Grimes 	 * (the various bits we're fiddling with here are locked by
857df8bae1dSRodney W. Grimes 	 * the object's lock)
858df8bae1dSRodney W. Grimes 	 */
859df8bae1dSRodney W. Grimes 
860df8bae1dSRodney W. Grimes 	/* XXX This distorts the meaning of the copy_on_write bit */
861df8bae1dSRodney W. Grimes 
862df8bae1dSRodney W. Grimes 	if (prot & VM_PROT_WRITE)
863df8bae1dSRodney W. Grimes 		m->flags &= ~PG_COPYONWRITE;
864df8bae1dSRodney W. Grimes 
865df8bae1dSRodney W. Grimes 	/*
866df8bae1dSRodney W. Grimes 	 *	It's critically important that a wired-down page be faulted
867df8bae1dSRodney W. Grimes 	 *	only once in each map for which it is wired.
868df8bae1dSRodney W. Grimes 	 */
869df8bae1dSRodney W. Grimes 
870df8bae1dSRodney W. Grimes 	if (m->flags & (PG_ACTIVE | PG_INACTIVE))
871df8bae1dSRodney W. Grimes 		panic("vm_fault: active or inactive before pmap_enter");
872df8bae1dSRodney W. Grimes 
873df8bae1dSRodney W. Grimes 	vm_object_unlock(object);
874df8bae1dSRodney W. Grimes 
875df8bae1dSRodney W. Grimes 	/*
876df8bae1dSRodney W. Grimes 	 *	Put this page into the physical map.
877df8bae1dSRodney W. Grimes 	 *	We had to do the unlock above because pmap_enter
878df8bae1dSRodney W. Grimes 	 *	may cause other faults.   We don't put the
879df8bae1dSRodney W. Grimes 	 *	page back on the active queue until later so
880df8bae1dSRodney W. Grimes 	 *	that the page-out daemon won't find us (yet).
881df8bae1dSRodney W. Grimes 	 */
882df8bae1dSRodney W. Grimes 
883df8bae1dSRodney W. Grimes 	pmap_enter(map->pmap, vaddr, VM_PAGE_TO_PHYS(m), prot, wired);
884df8bae1dSRodney W. Grimes 
885df8bae1dSRodney W. Grimes 	/*
886df8bae1dSRodney W. Grimes 	 *	If the page is not wired down, then put it where the
887df8bae1dSRodney W. Grimes 	 *	pageout daemon can find it.
888df8bae1dSRodney W. Grimes 	 */
889df8bae1dSRodney W. Grimes 	vm_object_lock(object);
890df8bae1dSRodney W. Grimes 	vm_page_lock_queues();
891df8bae1dSRodney W. Grimes 	if (change_wiring) {
892df8bae1dSRodney W. Grimes 		if (wired)
893df8bae1dSRodney W. Grimes 			vm_page_wire(m);
894df8bae1dSRodney W. Grimes 		else
895df8bae1dSRodney W. Grimes 			vm_page_unwire(m);
896df8bae1dSRodney W. Grimes 	}
89726f9a767SRodney W. Grimes 	else {
898df8bae1dSRodney W. Grimes 		vm_page_activate(m);
89926f9a767SRodney W. Grimes 	}
90026f9a767SRodney W. Grimes 
90126f9a767SRodney W. Grimes 	if( curproc && curproc->p_stats) {
90226f9a767SRodney W. Grimes 		if (hardfault) {
90326f9a767SRodney W. Grimes 			curproc->p_stats->p_ru.ru_majflt++;
90426f9a767SRodney W. Grimes 		} else {
90526f9a767SRodney W. Grimes 			curproc->p_stats->p_ru.ru_minflt++;
90626f9a767SRodney W. Grimes 		}
90726f9a767SRodney W. Grimes 	}
90826f9a767SRodney W. Grimes 
909df8bae1dSRodney W. Grimes 	vm_page_unlock_queues();
910df8bae1dSRodney W. Grimes 
911df8bae1dSRodney W. Grimes 	/*
912df8bae1dSRodney W. Grimes 	 *	Unlock everything, and return
913df8bae1dSRodney W. Grimes 	 */
914df8bae1dSRodney W. Grimes 
915df8bae1dSRodney W. Grimes 	PAGE_WAKEUP(m);
916df8bae1dSRodney W. Grimes 	UNLOCK_AND_DEALLOCATE;
917df8bae1dSRodney W. Grimes 
918df8bae1dSRodney W. Grimes 	return(KERN_SUCCESS);
919df8bae1dSRodney W. Grimes 
920df8bae1dSRodney W. Grimes }
921df8bae1dSRodney W. Grimes 
922df8bae1dSRodney W. Grimes /*
923df8bae1dSRodney W. Grimes  *	vm_fault_wire:
924df8bae1dSRodney W. Grimes  *
925df8bae1dSRodney W. Grimes  *	Wire down a range of virtual addresses in a map.
926df8bae1dSRodney W. Grimes  */
927df8bae1dSRodney W. Grimes int
928df8bae1dSRodney W. Grimes vm_fault_wire(map, start, end)
929df8bae1dSRodney W. Grimes 	vm_map_t	map;
930df8bae1dSRodney W. Grimes 	vm_offset_t	start, end;
931df8bae1dSRodney W. Grimes {
93226f9a767SRodney W. Grimes 
933df8bae1dSRodney W. Grimes 	register vm_offset_t	va;
934df8bae1dSRodney W. Grimes 	register pmap_t		pmap;
935df8bae1dSRodney W. Grimes 	int rv;
936df8bae1dSRodney W. Grimes 
937df8bae1dSRodney W. Grimes 	pmap = vm_map_pmap(map);
938df8bae1dSRodney W. Grimes 
939df8bae1dSRodney W. Grimes 	/*
940df8bae1dSRodney W. Grimes 	 *	Inform the physical mapping system that the
941df8bae1dSRodney W. Grimes 	 *	range of addresses may not fault, so that
942df8bae1dSRodney W. Grimes 	 *	page tables and such can be locked down as well.
943df8bae1dSRodney W. Grimes 	 */
944df8bae1dSRodney W. Grimes 
945df8bae1dSRodney W. Grimes 	pmap_pageable(pmap, start, end, FALSE);
946df8bae1dSRodney W. Grimes 
947df8bae1dSRodney W. Grimes 	/*
948df8bae1dSRodney W. Grimes 	 *	We simulate a fault to get the page and enter it
949df8bae1dSRodney W. Grimes 	 *	in the physical map.
950df8bae1dSRodney W. Grimes 	 */
951df8bae1dSRodney W. Grimes 
952df8bae1dSRodney W. Grimes 	for (va = start; va < end; va += PAGE_SIZE) {
953df8bae1dSRodney W. Grimes 		rv = vm_fault(map, va, VM_PROT_NONE, TRUE);
954df8bae1dSRodney W. Grimes 		if (rv) {
955df8bae1dSRodney W. Grimes 			if (va != start)
956df8bae1dSRodney W. Grimes 				vm_fault_unwire(map, start, va);
957df8bae1dSRodney W. Grimes 			return(rv);
958df8bae1dSRodney W. Grimes 		}
959df8bae1dSRodney W. Grimes 	}
960df8bae1dSRodney W. Grimes 	return(KERN_SUCCESS);
961df8bae1dSRodney W. Grimes }
962df8bae1dSRodney W. Grimes 
963df8bae1dSRodney W. Grimes 
964df8bae1dSRodney W. Grimes /*
965df8bae1dSRodney W. Grimes  *	vm_fault_unwire:
966df8bae1dSRodney W. Grimes  *
967df8bae1dSRodney W. Grimes  *	Unwire a range of virtual addresses in a map.
968df8bae1dSRodney W. Grimes  */
96926f9a767SRodney W. Grimes void
97026f9a767SRodney W. Grimes vm_fault_unwire(map, start, end)
971df8bae1dSRodney W. Grimes 	vm_map_t	map;
972df8bae1dSRodney W. Grimes 	vm_offset_t	start, end;
973df8bae1dSRodney W. Grimes {
974df8bae1dSRodney W. Grimes 
975df8bae1dSRodney W. Grimes 	register vm_offset_t	va, pa;
976df8bae1dSRodney W. Grimes 	register pmap_t		pmap;
977df8bae1dSRodney W. Grimes 
978df8bae1dSRodney W. Grimes 	pmap = vm_map_pmap(map);
979df8bae1dSRodney W. Grimes 
980df8bae1dSRodney W. Grimes 	/*
981df8bae1dSRodney W. Grimes 	 *	Since the pages are wired down, we must be able to
982df8bae1dSRodney W. Grimes 	 *	get their mappings from the physical map system.
983df8bae1dSRodney W. Grimes 	 */
984df8bae1dSRodney W. Grimes 
985df8bae1dSRodney W. Grimes 	vm_page_lock_queues();
986df8bae1dSRodney W. Grimes 
987df8bae1dSRodney W. Grimes 	for (va = start; va < end; va += PAGE_SIZE) {
988df8bae1dSRodney W. Grimes 		pa = pmap_extract(pmap, va);
989df8bae1dSRodney W. Grimes 		if (pa == (vm_offset_t) 0) {
990df8bae1dSRodney W. Grimes 			panic("unwire: page not in pmap");
991df8bae1dSRodney W. Grimes 		}
992df8bae1dSRodney W. Grimes 		pmap_change_wiring(pmap, va, FALSE);
993df8bae1dSRodney W. Grimes 		vm_page_unwire(PHYS_TO_VM_PAGE(pa));
994df8bae1dSRodney W. Grimes 	}
995df8bae1dSRodney W. Grimes 	vm_page_unlock_queues();
996df8bae1dSRodney W. Grimes 
997df8bae1dSRodney W. Grimes 	/*
998df8bae1dSRodney W. Grimes 	 *	Inform the physical mapping system that the range
999df8bae1dSRodney W. Grimes 	 *	of addresses may fault, so that page tables and
1000df8bae1dSRodney W. Grimes 	 *	such may be unwired themselves.
1001df8bae1dSRodney W. Grimes 	 */
1002df8bae1dSRodney W. Grimes 
1003df8bae1dSRodney W. Grimes 	pmap_pageable(pmap, start, end, TRUE);
1004df8bae1dSRodney W. Grimes 
1005df8bae1dSRodney W. Grimes }
1006df8bae1dSRodney W. Grimes 
1007df8bae1dSRodney W. Grimes /*
1008df8bae1dSRodney W. Grimes  *	Routine:
1009df8bae1dSRodney W. Grimes  *		vm_fault_copy_entry
1010df8bae1dSRodney W. Grimes  *	Function:
1011df8bae1dSRodney W. Grimes  *		Copy all of the pages from a wired-down map entry to another.
1012df8bae1dSRodney W. Grimes  *
1013df8bae1dSRodney W. Grimes  *	In/out conditions:
1014df8bae1dSRodney W. Grimes  *		The source and destination maps must be locked for write.
1015df8bae1dSRodney W. Grimes  *		The source map entry must be wired down (or be a sharing map
1016df8bae1dSRodney W. Grimes  *		entry corresponding to a main map entry that is wired down).
1017df8bae1dSRodney W. Grimes  */
1018df8bae1dSRodney W. Grimes 
101926f9a767SRodney W. Grimes void
102026f9a767SRodney W. Grimes vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry)
1021df8bae1dSRodney W. Grimes 	vm_map_t	dst_map;
1022df8bae1dSRodney W. Grimes 	vm_map_t	src_map;
1023df8bae1dSRodney W. Grimes 	vm_map_entry_t	dst_entry;
1024df8bae1dSRodney W. Grimes 	vm_map_entry_t	src_entry;
1025df8bae1dSRodney W. Grimes {
1026df8bae1dSRodney W. Grimes 	vm_object_t	dst_object;
1027df8bae1dSRodney W. Grimes 	vm_object_t	src_object;
1028df8bae1dSRodney W. Grimes 	vm_offset_t	dst_offset;
1029df8bae1dSRodney W. Grimes 	vm_offset_t	src_offset;
1030df8bae1dSRodney W. Grimes 	vm_prot_t	prot;
1031df8bae1dSRodney W. Grimes 	vm_offset_t	vaddr;
1032df8bae1dSRodney W. Grimes 	vm_page_t	dst_m;
1033df8bae1dSRodney W. Grimes 	vm_page_t	src_m;
1034df8bae1dSRodney W. Grimes 
1035df8bae1dSRodney W. Grimes #ifdef	lint
1036df8bae1dSRodney W. Grimes 	src_map++;
103726f9a767SRodney W. Grimes #endif	lint
1038df8bae1dSRodney W. Grimes 
1039df8bae1dSRodney W. Grimes 	src_object = src_entry->object.vm_object;
1040df8bae1dSRodney W. Grimes 	src_offset = src_entry->offset;
1041df8bae1dSRodney W. Grimes 
1042df8bae1dSRodney W. Grimes 	/*
1043df8bae1dSRodney W. Grimes 	 *	Create the top-level object for the destination entry.
1044df8bae1dSRodney W. Grimes 	 *	(Doesn't actually shadow anything - we copy the pages
1045df8bae1dSRodney W. Grimes 	 *	directly.)
1046df8bae1dSRodney W. Grimes 	 */
1047df8bae1dSRodney W. Grimes 	dst_object = vm_object_allocate(
1048df8bae1dSRodney W. Grimes 			(vm_size_t) (dst_entry->end - dst_entry->start));
1049df8bae1dSRodney W. Grimes 
1050df8bae1dSRodney W. Grimes 	dst_entry->object.vm_object = dst_object;
1051df8bae1dSRodney W. Grimes 	dst_entry->offset = 0;
1052df8bae1dSRodney W. Grimes 
1053df8bae1dSRodney W. Grimes 	prot  = dst_entry->max_protection;
1054df8bae1dSRodney W. Grimes 
1055df8bae1dSRodney W. Grimes 	/*
1056df8bae1dSRodney W. Grimes 	 *	Loop through all of the pages in the entry's range, copying
1057df8bae1dSRodney W. Grimes 	 *	each one from the source object (it should be there) to the
1058df8bae1dSRodney W. Grimes 	 *	destination object.
1059df8bae1dSRodney W. Grimes 	 */
1060df8bae1dSRodney W. Grimes 	for (vaddr = dst_entry->start, dst_offset = 0;
1061df8bae1dSRodney W. Grimes 	     vaddr < dst_entry->end;
1062df8bae1dSRodney W. Grimes 	     vaddr += PAGE_SIZE, dst_offset += PAGE_SIZE) {
1063df8bae1dSRodney W. Grimes 
1064df8bae1dSRodney W. Grimes 		/*
1065df8bae1dSRodney W. Grimes 		 *	Allocate a page in the destination object
1066df8bae1dSRodney W. Grimes 		 */
1067df8bae1dSRodney W. Grimes 		vm_object_lock(dst_object);
1068df8bae1dSRodney W. Grimes 		do {
1069df8bae1dSRodney W. Grimes 			dst_m = vm_page_alloc(dst_object, dst_offset);
1070df8bae1dSRodney W. Grimes 			if (dst_m == NULL) {
1071df8bae1dSRodney W. Grimes 				vm_object_unlock(dst_object);
1072df8bae1dSRodney W. Grimes 				VM_WAIT;
1073df8bae1dSRodney W. Grimes 				vm_object_lock(dst_object);
1074df8bae1dSRodney W. Grimes 			}
1075df8bae1dSRodney W. Grimes 		} while (dst_m == NULL);
1076df8bae1dSRodney W. Grimes 
1077df8bae1dSRodney W. Grimes 		/*
1078df8bae1dSRodney W. Grimes 		 *	Find the page in the source object, and copy it in.
1079df8bae1dSRodney W. Grimes 		 *	(Because the source is wired down, the page will be
1080df8bae1dSRodney W. Grimes 		 *	in memory.)
1081df8bae1dSRodney W. Grimes 		 */
1082df8bae1dSRodney W. Grimes 		vm_object_lock(src_object);
1083df8bae1dSRodney W. Grimes 		src_m = vm_page_lookup(src_object, dst_offset + src_offset);
1084df8bae1dSRodney W. Grimes 		if (src_m == NULL)
1085df8bae1dSRodney W. Grimes 			panic("vm_fault_copy_wired: page missing");
1086df8bae1dSRodney W. Grimes 
1087df8bae1dSRodney W. Grimes 		vm_page_copy(src_m, dst_m);
1088df8bae1dSRodney W. Grimes 
1089df8bae1dSRodney W. Grimes 		/*
1090df8bae1dSRodney W. Grimes 		 *	Enter it in the pmap...
1091df8bae1dSRodney W. Grimes 		 */
1092df8bae1dSRodney W. Grimes 		vm_object_unlock(src_object);
1093df8bae1dSRodney W. Grimes 		vm_object_unlock(dst_object);
1094df8bae1dSRodney W. Grimes 
1095df8bae1dSRodney W. Grimes 		pmap_enter(dst_map->pmap, vaddr, VM_PAGE_TO_PHYS(dst_m),
1096df8bae1dSRodney W. Grimes 				prot, FALSE);
1097df8bae1dSRodney W. Grimes 
1098df8bae1dSRodney W. Grimes 		/*
1099df8bae1dSRodney W. Grimes 		 *	Mark it no longer busy, and put it on the active list.
1100df8bae1dSRodney W. Grimes 		 */
1101df8bae1dSRodney W. Grimes 		vm_object_lock(dst_object);
1102df8bae1dSRodney W. Grimes 		vm_page_lock_queues();
1103df8bae1dSRodney W. Grimes 		vm_page_activate(dst_m);
1104df8bae1dSRodney W. Grimes 		vm_page_unlock_queues();
1105df8bae1dSRodney W. Grimes 		PAGE_WAKEUP(dst_m);
1106df8bae1dSRodney W. Grimes 		vm_object_unlock(dst_object);
1107df8bae1dSRodney W. Grimes 	}
1108df8bae1dSRodney W. Grimes }
110926f9a767SRodney W. Grimes 
111026f9a767SRodney W. Grimes 
111126f9a767SRodney W. Grimes /*
111226f9a767SRodney W. Grimes  * looks page up in shadow chain
111326f9a767SRodney W. Grimes  */
111426f9a767SRodney W. Grimes 
111526f9a767SRodney W. Grimes int
111626f9a767SRodney W. Grimes vm_fault_page_lookup(object, offset, rtobject, rtoffset, rtm)
111726f9a767SRodney W. Grimes 	vm_object_t object;
111826f9a767SRodney W. Grimes 	vm_offset_t offset;
111926f9a767SRodney W. Grimes 	vm_object_t *rtobject;
112026f9a767SRodney W. Grimes 	vm_offset_t *rtoffset;
112126f9a767SRodney W. Grimes 	vm_page_t *rtm;
112226f9a767SRodney W. Grimes {
112326f9a767SRodney W. Grimes 	vm_page_t m;
112426f9a767SRodney W. Grimes 
112526f9a767SRodney W. Grimes 	*rtm = 0;
112626f9a767SRodney W. Grimes 	*rtobject = 0;
112726f9a767SRodney W. Grimes 	*rtoffset = 0;
112826f9a767SRodney W. Grimes 
112926f9a767SRodney W. Grimes 
113026f9a767SRodney W. Grimes 	while (!(m=vm_page_lookup(object, offset))) {
113126f9a767SRodney W. Grimes 		if (object->pager) {
113226f9a767SRodney W. Grimes 			if (vm_pager_has_page(object->pager, object->paging_offset+offset)) {
113326f9a767SRodney W. Grimes 				*rtobject = object;
113426f9a767SRodney W. Grimes 				*rtoffset = offset;
113526f9a767SRodney W. Grimes 				return 1;
113626f9a767SRodney W. Grimes 			}
113726f9a767SRodney W. Grimes 		}
113826f9a767SRodney W. Grimes 
113926f9a767SRodney W. Grimes 		if (!object->shadow)
114026f9a767SRodney W. Grimes 			return 0;
114126f9a767SRodney W. Grimes 		else {
114226f9a767SRodney W. Grimes 			offset += object->shadow_offset;
114326f9a767SRodney W. Grimes 			object = object->shadow;
114426f9a767SRodney W. Grimes 		}
114526f9a767SRodney W. Grimes 	}
114626f9a767SRodney W. Grimes 	*rtobject = object;
114726f9a767SRodney W. Grimes 	*rtoffset = offset;
114826f9a767SRodney W. Grimes 	*rtm = m;
114926f9a767SRodney W. Grimes 	return 1;
115026f9a767SRodney W. Grimes }
115126f9a767SRodney W. Grimes 
115226f9a767SRodney W. Grimes /*
115326f9a767SRodney W. Grimes  * This routine checks around the requested page for other pages that
115426f9a767SRodney W. Grimes  * might be able to be faulted in.
115526f9a767SRodney W. Grimes  *
115626f9a767SRodney W. Grimes  * Inputs:
115726f9a767SRodney W. Grimes  *	first_object, first_offset, m, rbehind, rahead
115826f9a767SRodney W. Grimes  *
115926f9a767SRodney W. Grimes  * Outputs:
116026f9a767SRodney W. Grimes  *  marray (array of vm_page_t), reqpage (index of requested page)
116126f9a767SRodney W. Grimes  *
116226f9a767SRodney W. Grimes  * Return value:
116326f9a767SRodney W. Grimes  *  number of pages in marray
116426f9a767SRodney W. Grimes  */
116526f9a767SRodney W. Grimes int
116626f9a767SRodney W. Grimes vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marray, reqpage)
116726f9a767SRodney W. Grimes 	vm_object_t first_object;
116826f9a767SRodney W. Grimes 	vm_offset_t first_offset;
116926f9a767SRodney W. Grimes 	vm_page_t m;
117026f9a767SRodney W. Grimes 	int rbehind;
117126f9a767SRodney W. Grimes 	int raheada;
117226f9a767SRodney W. Grimes 	vm_page_t *marray;
117326f9a767SRodney W. Grimes 	int *reqpage;
117426f9a767SRodney W. Grimes {
117526f9a767SRodney W. Grimes 	int i;
117626f9a767SRodney W. Grimes 	vm_object_t object;
117726f9a767SRodney W. Grimes 	vm_offset_t offset, startoffset, endoffset, toffset, size;
117826f9a767SRodney W. Grimes 	vm_object_t rtobject;
117926f9a767SRodney W. Grimes 	vm_page_t rtm;
118026f9a767SRodney W. Grimes 	vm_offset_t rtoffset;
118126f9a767SRodney W. Grimes 	vm_offset_t offsetdiff;
118226f9a767SRodney W. Grimes 	int rahead;
118326f9a767SRodney W. Grimes 	int treqpage;
118426f9a767SRodney W. Grimes 
118526f9a767SRodney W. Grimes 	object = m->object;
118626f9a767SRodney W. Grimes 	offset = m->offset;
118726f9a767SRodney W. Grimes 
118826f9a767SRodney W. Grimes 	offsetdiff = offset - first_offset;
118926f9a767SRodney W. Grimes 
119026f9a767SRodney W. Grimes 	/*
119126f9a767SRodney W. Grimes 	 * if the requested page is not available, then give up now
119226f9a767SRodney W. Grimes 	 */
119326f9a767SRodney W. Grimes 
119426f9a767SRodney W. Grimes 	if (!vm_pager_has_page(object->pager, object->paging_offset+offset))
119526f9a767SRodney W. Grimes 		return 0;
119626f9a767SRodney W. Grimes 
119726f9a767SRodney W. Grimes 	/*
119826f9a767SRodney W. Grimes 	 * if there is no getmulti routine for this pager, then just allow
119926f9a767SRodney W. Grimes 	 * one page to be read.
120026f9a767SRodney W. Grimes 	 */
120126f9a767SRodney W. Grimes /*
120226f9a767SRodney W. Grimes 	if (!object->pager->pg_ops->pgo_getpages) {
120326f9a767SRodney W. Grimes 		*reqpage = 0;
120426f9a767SRodney W. Grimes 		marray[0] = m;
120526f9a767SRodney W. Grimes 		return 1;
120626f9a767SRodney W. Grimes 	}
120726f9a767SRodney W. Grimes */
120826f9a767SRodney W. Grimes 
120926f9a767SRodney W. Grimes 	/*
121026f9a767SRodney W. Grimes 	 * try to do any readahead that we might have free pages for.
121126f9a767SRodney W. Grimes 	 */
121226f9a767SRodney W. Grimes 	rahead = raheada;
121326f9a767SRodney W. Grimes 	if (rahead > (cnt.v_free_count - cnt.v_free_reserved)) {
121426f9a767SRodney W. Grimes 		rahead = cnt.v_free_count - cnt.v_free_reserved;
121526f9a767SRodney W. Grimes 		rbehind = 0;
121626f9a767SRodney W. Grimes 	}
121726f9a767SRodney W. Grimes 
121826f9a767SRodney W. Grimes 	if (cnt.v_free_count < cnt.v_free_min) {
121926f9a767SRodney W. Grimes 		if (rahead > VM_FAULT_READ_AHEAD_MIN)
122026f9a767SRodney W. Grimes 			rahead = VM_FAULT_READ_AHEAD_MIN;
122126f9a767SRodney W. Grimes 		rbehind = 0;
122226f9a767SRodney W. Grimes 	}
122326f9a767SRodney W. Grimes 
122426f9a767SRodney W. Grimes 	/*
122526f9a767SRodney W. Grimes 	 * if we don't have any free pages, then just read one page.
122626f9a767SRodney W. Grimes 	 */
122726f9a767SRodney W. Grimes 	if (rahead <= 0) {
122826f9a767SRodney W. Grimes 		*reqpage = 0;
122926f9a767SRodney W. Grimes 		marray[0] = m;
123026f9a767SRodney W. Grimes 		return 1;
123126f9a767SRodney W. Grimes 	}
123226f9a767SRodney W. Grimes 
123326f9a767SRodney W. Grimes 	/*
123426f9a767SRodney W. Grimes 	 * scan backward for the read behind pages --
123526f9a767SRodney W. Grimes 	 * in memory or on disk not in same object
123626f9a767SRodney W. Grimes 	 */
123726f9a767SRodney W. Grimes 	toffset = offset - NBPG;
123826f9a767SRodney W. Grimes 	if( rbehind*NBPG > offset)
123926f9a767SRodney W. Grimes 		rbehind = offset / NBPG;
124026f9a767SRodney W. Grimes 	startoffset = offset - rbehind*NBPG;
124126f9a767SRodney W. Grimes 	while (toffset >= startoffset) {
124226f9a767SRodney W. Grimes 		if (!vm_fault_page_lookup(first_object, toffset - offsetdiff, &rtobject, &rtoffset, &rtm) ||
124326f9a767SRodney W. Grimes 		    rtm != 0 || rtobject != object) {
124426f9a767SRodney W. Grimes 			startoffset = toffset + NBPG;
124526f9a767SRodney W. Grimes 			break;
124626f9a767SRodney W. Grimes 		}
124726f9a767SRodney W. Grimes 		if( toffset == 0)
124826f9a767SRodney W. Grimes 			break;
124926f9a767SRodney W. Grimes 		toffset -= NBPG;
125026f9a767SRodney W. Grimes 	}
125126f9a767SRodney W. Grimes 
125226f9a767SRodney W. Grimes 	/*
125326f9a767SRodney W. Grimes 	 * scan forward for the read ahead pages --
125426f9a767SRodney W. Grimes 	 * in memory or on disk not in same object
125526f9a767SRodney W. Grimes 	 */
125626f9a767SRodney W. Grimes 	toffset = offset + NBPG;
125726f9a767SRodney W. Grimes 	endoffset = offset + (rahead+1)*NBPG;
125826f9a767SRodney W. Grimes 	while (toffset < object->size && toffset < endoffset) {
125926f9a767SRodney W. Grimes 		if (!vm_fault_page_lookup(first_object, toffset - offsetdiff, &rtobject, &rtoffset, &rtm) ||
126026f9a767SRodney W. Grimes 		    rtm != 0 || rtobject != object) {
126126f9a767SRodney W. Grimes 			break;
126226f9a767SRodney W. Grimes 		}
126326f9a767SRodney W. Grimes 		toffset += NBPG;
126426f9a767SRodney W. Grimes 	}
126526f9a767SRodney W. Grimes 	endoffset = toffset;
126626f9a767SRodney W. Grimes 
126726f9a767SRodney W. Grimes 	/* calculate number of bytes of pages */
126826f9a767SRodney W. Grimes 	size = (endoffset - startoffset) / NBPG;
126926f9a767SRodney W. Grimes 
127026f9a767SRodney W. Grimes 	/* calculate the page offset of the required page */
127126f9a767SRodney W. Grimes 	treqpage = (offset - startoffset) / NBPG;
127226f9a767SRodney W. Grimes 
127326f9a767SRodney W. Grimes 	/* see if we have space (again) */
127426f9a767SRodney W. Grimes 	if (cnt.v_free_count >= cnt.v_free_reserved + size) {
127526f9a767SRodney W. Grimes 		bzero(marray, (rahead + rbehind + 1) * sizeof(vm_page_t));
127626f9a767SRodney W. Grimes 		/*
127726f9a767SRodney W. Grimes 		 * get our pages and don't block for them
127826f9a767SRodney W. Grimes 		 */
127926f9a767SRodney W. Grimes 		for (i = 0; i < size; i++) {
128026f9a767SRodney W. Grimes 			if (i != treqpage)
128126f9a767SRodney W. Grimes 				rtm  = vm_page_alloc(object, startoffset + i * NBPG);
128226f9a767SRodney W. Grimes 			else
128326f9a767SRodney W. Grimes 				rtm = m;
128426f9a767SRodney W. Grimes 			marray[i] = rtm;
128526f9a767SRodney W. Grimes 		}
128626f9a767SRodney W. Grimes 
128726f9a767SRodney W. Grimes 		for (i = 0; i < size; i++) {
128826f9a767SRodney W. Grimes 			if (marray[i] == 0)
128926f9a767SRodney W. Grimes 				break;
129026f9a767SRodney W. Grimes 		}
129126f9a767SRodney W. Grimes 
129226f9a767SRodney W. Grimes 		/*
129326f9a767SRodney W. Grimes 		 * if we could not get our block of pages, then
129426f9a767SRodney W. Grimes 		 * free the readahead/readbehind pages.
129526f9a767SRodney W. Grimes 		 */
129626f9a767SRodney W. Grimes 		if (i < size) {
129726f9a767SRodney W. Grimes 			for (i = 0; i < size; i++) {
129826f9a767SRodney W. Grimes 				if (i != treqpage && marray[i])
129926f9a767SRodney W. Grimes 					FREE_PAGE(marray[i]);
130026f9a767SRodney W. Grimes 			}
130126f9a767SRodney W. Grimes 			*reqpage = 0;
130226f9a767SRodney W. Grimes 			marray[0] = m;
130326f9a767SRodney W. Grimes 			return 1;
130426f9a767SRodney W. Grimes 		}
130526f9a767SRodney W. Grimes 
130626f9a767SRodney W. Grimes 		*reqpage = treqpage;
130726f9a767SRodney W. Grimes 		return size;
130826f9a767SRodney W. Grimes 	}
130926f9a767SRodney W. Grimes 	*reqpage = 0;
131026f9a767SRodney W. Grimes 	marray[0] = m;
131126f9a767SRodney W. Grimes 	return 1;
131226f9a767SRodney W. Grimes }
131326f9a767SRodney W. Grimes 
1314