1 /* $NetBSD: uvm_fault_i.h,v 1.16 2002/11/02 07:38:42 perry Exp $ */ 2 3 /* 4 * 5 * Copyright (c) 1997 Charles D. Cranor and Washington University. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Charles D. Cranor and 19 * Washington University. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * from: Id: uvm_fault_i.h,v 1.1.6.1 1997/12/08 16:07:12 chuck Exp 35 */ 36 37 #ifndef _UVM_UVM_FAULT_I_H_ 38 #define _UVM_UVM_FAULT_I_H_ 39 40 /* 41 * uvm_fault_i.h: fault inline functions 42 */ 43 static boolean_t uvmfault_lookup __P((struct uvm_faultinfo *, boolean_t)); 44 static boolean_t uvmfault_relock __P((struct uvm_faultinfo *)); 45 static void uvmfault_unlockall __P((struct uvm_faultinfo *, struct vm_amap *, 46 struct uvm_object *, struct vm_anon *)); 47 static void uvmfault_unlockmaps __P((struct uvm_faultinfo *, boolean_t)); 48 49 /* 50 * uvmfault_unlockmaps: unlock the maps 51 */ 52 53 static __inline void 54 uvmfault_unlockmaps(ufi, write_locked) 55 struct uvm_faultinfo *ufi; 56 boolean_t write_locked; 57 { 58 /* 59 * ufi can be NULL when this isn't really a fault, 60 * but merely paging in anon data. 61 */ 62 63 if (ufi == NULL) { 64 return; 65 } 66 67 if (write_locked) { 68 vm_map_unlock(ufi->map); 69 } else { 70 vm_map_unlock_read(ufi->map); 71 } 72 } 73 74 /* 75 * uvmfault_unlockall: unlock everything passed in. 76 * 77 * => maps must be read-locked (not write-locked). 78 */ 79 80 static __inline void 81 uvmfault_unlockall(ufi, amap, uobj, anon) 82 struct uvm_faultinfo *ufi; 83 struct vm_amap *amap; 84 struct uvm_object *uobj; 85 struct vm_anon *anon; 86 { 87 88 if (anon) 89 simple_unlock(&anon->an_lock); 90 if (uobj) 91 simple_unlock(&uobj->vmobjlock); 92 if (amap) 93 amap_unlock(amap); 94 uvmfault_unlockmaps(ufi, FALSE); 95 } 96 97 /* 98 * uvmfault_lookup: lookup a virtual address in a map 99 * 100 * => caller must provide a uvm_faultinfo structure with the IN 101 * params properly filled in 102 * => we will lookup the map entry (handling submaps) as we go 103 * => if the lookup is a success we will return with the maps locked 104 * => if "write_lock" is TRUE, we write_lock the map, otherwise we only 105 * get a read lock. 106 * => note that submaps can only appear in the kernel and they are 107 * required to use the same virtual addresses as the map they 108 * are referenced by (thus address translation between the main 109 * map and the submap is unnecessary). 110 */ 111 112 static __inline boolean_t 113 uvmfault_lookup(ufi, write_lock) 114 struct uvm_faultinfo *ufi; 115 boolean_t write_lock; 116 { 117 struct vm_map *tmpmap; 118 119 /* 120 * init ufi values for lookup. 121 */ 122 123 ufi->map = ufi->orig_map; 124 ufi->size = ufi->orig_size; 125 126 /* 127 * keep going down levels until we are done. note that there can 128 * only be two levels so we won't loop very long. 129 */ 130 131 /*CONSTCOND*/ 132 while (1) { 133 /* 134 * Make sure this is not an "interrupt safe" map. 135 * Such maps are never supposed to be involved in 136 * a fault. 137 */ 138 if (ufi->map->flags & VM_MAP_INTRSAFE) 139 return (FALSE); 140 141 /* 142 * lock map 143 */ 144 if (write_lock) { 145 vm_map_lock(ufi->map); 146 } else { 147 vm_map_lock_read(ufi->map); 148 } 149 150 /* 151 * lookup 152 */ 153 if (!uvm_map_lookup_entry(ufi->map, ufi->orig_rvaddr, 154 &ufi->entry)) { 155 uvmfault_unlockmaps(ufi, write_lock); 156 return(FALSE); 157 } 158 159 /* 160 * reduce size if necessary 161 */ 162 if (ufi->entry->end - ufi->orig_rvaddr < ufi->size) 163 ufi->size = ufi->entry->end - ufi->orig_rvaddr; 164 165 /* 166 * submap? replace map with the submap and lookup again. 167 * note: VAs in submaps must match VAs in main map. 168 */ 169 if (UVM_ET_ISSUBMAP(ufi->entry)) { 170 tmpmap = ufi->entry->object.sub_map; 171 if (write_lock) { 172 vm_map_unlock(ufi->map); 173 } else { 174 vm_map_unlock_read(ufi->map); 175 } 176 ufi->map = tmpmap; 177 continue; 178 } 179 180 /* 181 * got it! 182 */ 183 184 ufi->mapv = ufi->map->timestamp; 185 return(TRUE); 186 187 } /* while loop */ 188 189 /*NOTREACHED*/ 190 } 191 192 /* 193 * uvmfault_relock: attempt to relock the same version of the map 194 * 195 * => fault data structures should be unlocked before calling. 196 * => if a success (TRUE) maps will be locked after call. 197 */ 198 199 static __inline boolean_t 200 uvmfault_relock(ufi) 201 struct uvm_faultinfo *ufi; 202 { 203 /* 204 * ufi can be NULL when this isn't really a fault, 205 * but merely paging in anon data. 206 */ 207 208 if (ufi == NULL) { 209 return TRUE; 210 } 211 212 uvmexp.fltrelck++; 213 214 /* 215 * relock map. fail if version mismatch (in which case nothing 216 * gets locked). 217 */ 218 219 vm_map_lock_read(ufi->map); 220 if (ufi->mapv != ufi->map->timestamp) { 221 vm_map_unlock_read(ufi->map); 222 return(FALSE); 223 } 224 225 uvmexp.fltrelckok++; 226 return(TRUE); 227 } 228 229 #endif /* _UVM_UVM_FAULT_I_H_ */ 230