uvm_fault_i.h revision 1.27 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