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