1 /* $NetBSD: uvm_fault_i.h,v 1.27 2011/06/12 03:36:03 rmind 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) 69 { 70 71 if (uobj) 72 mutex_exit(uobj->vmobjlock); 73 if (amap) 74 amap_unlock(amap); 75 uvmfault_unlockmaps(ufi, false); 76 } 77 78 /* 79 * uvmfault_lookup: lookup a virtual address in a map 80 * 81 * => caller must provide a uvm_faultinfo structure with the IN 82 * params properly filled in 83 * => we will lookup the map entry (handling submaps) as we go 84 * => if the lookup is a success we will return with the maps locked 85 * => if "write_lock" is true, we write_lock the map, otherwise we only 86 * get a read lock. 87 * => note that submaps can only appear in the kernel and they are 88 * required to use the same virtual addresses as the map they 89 * are referenced by (thus address translation between the main 90 * map and the submap is unnecessary). 91 */ 92 93 static inline bool 94 uvmfault_lookup(struct uvm_faultinfo *ufi, bool write_lock) 95 { 96 struct vm_map *tmpmap; 97 98 /* 99 * init ufi values for lookup. 100 */ 101 102 ufi->map = ufi->orig_map; 103 ufi->size = ufi->orig_size; 104 105 /* 106 * keep going down levels until we are done. note that there can 107 * only be two levels so we won't loop very long. 108 */ 109 110 /*CONSTCOND*/ 111 while (1) { 112 /* 113 * Make sure this is not an "interrupt safe" map. 114 * Such maps are never supposed to be involved in 115 * a fault. 116 */ 117 if (ufi->map->flags & VM_MAP_INTRSAFE) 118 return (false); 119 120 /* 121 * lock map 122 */ 123 if (write_lock) { 124 vm_map_lock(ufi->map); 125 } else { 126 vm_map_lock_read(ufi->map); 127 } 128 129 /* 130 * lookup 131 */ 132 if (!uvm_map_lookup_entry(ufi->map, ufi->orig_rvaddr, 133 &ufi->entry)) { 134 uvmfault_unlockmaps(ufi, write_lock); 135 return(false); 136 } 137 138 /* 139 * reduce size if necessary 140 */ 141 if (ufi->entry->end - ufi->orig_rvaddr < ufi->size) 142 ufi->size = ufi->entry->end - ufi->orig_rvaddr; 143 144 /* 145 * submap? replace map with the submap and lookup again. 146 * note: VAs in submaps must match VAs in main map. 147 */ 148 if (UVM_ET_ISSUBMAP(ufi->entry)) { 149 tmpmap = ufi->entry->object.sub_map; 150 if (write_lock) { 151 vm_map_unlock(ufi->map); 152 } else { 153 vm_map_unlock_read(ufi->map); 154 } 155 ufi->map = tmpmap; 156 continue; 157 } 158 159 /* 160 * got it! 161 */ 162 163 ufi->mapv = ufi->map->timestamp; 164 return(true); 165 166 } /* while loop */ 167 168 /*NOTREACHED*/ 169 } 170 171 /* 172 * uvmfault_relock: attempt to relock the same version of the map 173 * 174 * => fault data structures should be unlocked before calling. 175 * => if a success (true) maps will be locked after call. 176 */ 177 178 static inline bool 179 uvmfault_relock(struct uvm_faultinfo *ufi) 180 { 181 /* 182 * ufi can be NULL when this isn't really a fault, 183 * but merely paging in anon data. 184 */ 185 186 if (ufi == NULL) { 187 return true; 188 } 189 190 uvmexp.fltrelck++; 191 192 /* 193 * relock map. fail if version mismatch (in which case nothing 194 * gets locked). 195 */ 196 197 vm_map_lock_read(ufi->map); 198 if (ufi->mapv != ufi->map->timestamp) { 199 vm_map_unlock_read(ufi->map); 200 return(false); 201 } 202 203 uvmexp.fltrelckok++; 204 return(true); 205 } 206 207 #endif /* _UVM_UVM_FAULT_I_H_ */ 208