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