1 /* $NetBSD: uvm_fault_i.h,v 1.28 2012/02/19 00:05:56 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 for (;;) { 111 /* 112 * lock map 113 */ 114 if (write_lock) { 115 vm_map_lock(ufi->map); 116 } else { 117 vm_map_lock_read(ufi->map); 118 } 119 120 /* 121 * lookup 122 */ 123 if (!uvm_map_lookup_entry(ufi->map, ufi->orig_rvaddr, 124 &ufi->entry)) { 125 uvmfault_unlockmaps(ufi, write_lock); 126 return(false); 127 } 128 129 /* 130 * reduce size if necessary 131 */ 132 if (ufi->entry->end - ufi->orig_rvaddr < ufi->size) 133 ufi->size = ufi->entry->end - ufi->orig_rvaddr; 134 135 /* 136 * submap? replace map with the submap and lookup again. 137 * note: VAs in submaps must match VAs in main map. 138 */ 139 if (UVM_ET_ISSUBMAP(ufi->entry)) { 140 tmpmap = ufi->entry->object.sub_map; 141 if (write_lock) { 142 vm_map_unlock(ufi->map); 143 } else { 144 vm_map_unlock_read(ufi->map); 145 } 146 ufi->map = tmpmap; 147 continue; 148 } 149 150 /* 151 * got it! 152 */ 153 154 ufi->mapv = ufi->map->timestamp; 155 return(true); 156 157 } /* while loop */ 158 159 /*NOTREACHED*/ 160 } 161 162 /* 163 * uvmfault_relock: attempt to relock the same version of the map 164 * 165 * => fault data structures should be unlocked before calling. 166 * => if a success (true) maps will be locked after call. 167 */ 168 169 static inline bool 170 uvmfault_relock(struct uvm_faultinfo *ufi) 171 { 172 /* 173 * ufi can be NULL when this isn't really a fault, 174 * but merely paging in anon data. 175 */ 176 177 if (ufi == NULL) { 178 return true; 179 } 180 181 uvmexp.fltrelck++; 182 183 /* 184 * relock map. fail if version mismatch (in which case nothing 185 * gets locked). 186 */ 187 188 vm_map_lock_read(ufi->map); 189 if (ufi->mapv != ufi->map->timestamp) { 190 vm_map_unlock_read(ufi->map); 191 return(false); 192 } 193 194 uvmexp.fltrelckok++; 195 return(true); 196 } 197 198 #endif /* _UVM_UVM_FAULT_I_H_ */ 199