| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: uvm_amap.c,v 1.112 2020/01/01 13:11:51 ad Exp $ */ | | 1 | /* $NetBSD: uvm_amap.c,v 1.113 2020/01/01 22:01:13 ad Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1997 Charles D. Cranor and Washington University. | | 4 | * Copyright (c) 1997 Charles D. Cranor and Washington University. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -25,27 +25,27 @@ | | | @@ -25,27 +25,27 @@ |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | | 26 | */ |
27 | | | 27 | |
28 | /* | | 28 | /* |
29 | * uvm_amap.c: amap operations | | 29 | * uvm_amap.c: amap operations |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * this file contains functions that perform operations on amaps. see | | 33 | * this file contains functions that perform operations on amaps. see |
34 | * uvm_amap.h for a brief explanation of the role of amaps in uvm. | | 34 | * uvm_amap.h for a brief explanation of the role of amaps in uvm. |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v 1.112 2020/01/01 13:11:51 ad Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v 1.113 2020/01/01 22:01:13 ad Exp $"); |
39 | | | 39 | |
40 | #include "opt_uvmhist.h" | | 40 | #include "opt_uvmhist.h" |
41 | | | 41 | |
42 | #include <sys/param.h> | | 42 | #include <sys/param.h> |
43 | #include <sys/systm.h> | | 43 | #include <sys/systm.h> |
44 | #include <sys/kernel.h> | | 44 | #include <sys/kernel.h> |
45 | #include <sys/kmem.h> | | 45 | #include <sys/kmem.h> |
46 | #include <sys/pool.h> | | 46 | #include <sys/pool.h> |
47 | #include <sys/atomic.h> | | 47 | #include <sys/atomic.h> |
48 | | | 48 | |
49 | #include <uvm/uvm.h> | | 49 | #include <uvm/uvm.h> |
50 | #include <uvm/uvm_swap.h> | | 50 | #include <uvm/uvm_swap.h> |
51 | | | 51 | |
| @@ -53,49 +53,38 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v | | | @@ -53,49 +53,38 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v |
53 | * cache for allocation of vm_map structures. note that in order to | | 53 | * cache for allocation of vm_map structures. note that in order to |
54 | * avoid an endless loop, the amap cache's allocator cannot allocate | | 54 | * avoid an endless loop, the amap cache's allocator cannot allocate |
55 | * memory from an amap (it currently goes through the kernel uobj, so | | 55 | * memory from an amap (it currently goes through the kernel uobj, so |
56 | * we are ok). | | 56 | * we are ok). |
57 | */ | | 57 | */ |
58 | static struct pool_cache uvm_amap_cache; | | 58 | static struct pool_cache uvm_amap_cache; |
59 | static kmutex_t amap_list_lock __cacheline_aligned; | | 59 | static kmutex_t amap_list_lock __cacheline_aligned; |
60 | static LIST_HEAD(, vm_amap) amap_list; | | 60 | static LIST_HEAD(, vm_amap) amap_list; |
61 | | | 61 | |
62 | /* | | 62 | /* |
63 | * local functions | | 63 | * local functions |
64 | */ | | 64 | */ |
65 | | | 65 | |
66 | static inline void | | | |
67 | amap_list_insert(struct vm_amap *amap) | | | |
68 | { | | | |
69 | | | | |
70 | mutex_enter(&amap_list_lock); | | | |
71 | LIST_INSERT_HEAD(&amap_list, amap, am_list); | | | |
72 | mutex_exit(&amap_list_lock); | | | |
73 | } | | | |
74 | | | | |
75 | static inline void | | | |
76 | amap_list_remove(struct vm_amap *amap) | | | |
77 | { | | | |
78 | | | | |
79 | mutex_enter(&amap_list_lock); | | | |
80 | LIST_REMOVE(amap, am_list); | | | |
81 | mutex_exit(&amap_list_lock); | | | |
82 | } | | | |
83 | | | | |
84 | static int | | 66 | static int |
85 | amap_roundup_slots(int slots) | | 67 | amap_roundup_slots(int slots) |
86 | { | | 68 | { |
87 | | | 69 | |
| | | 70 | #ifdef _LP64 |
| | | 71 | /* Align to cacheline boundary for best performance. */ |
| | | 72 | return roundup2((slots * sizeof(struct vm_amap *)), |
| | | 73 | COHERENCY_UNIT) / sizeof(struct vm_amap *); |
| | | 74 | #else |
| | | 75 | /* On 32-bit, KVA shortage is a concern. */ |
88 | return kmem_roundup_size(slots * sizeof(int)) / sizeof(int); | | 76 | return kmem_roundup_size(slots * sizeof(int)) / sizeof(int); |
| | | 77 | #endif |
89 | } | | 78 | } |
90 | | | 79 | |
91 | #ifdef UVM_AMAP_PPREF | | 80 | #ifdef UVM_AMAP_PPREF |
92 | /* | | 81 | /* |
93 | * what is ppref? ppref is an _optional_ amap feature which is used | | 82 | * what is ppref? ppref is an _optional_ amap feature which is used |
94 | * to keep track of reference counts on a per-page basis. it is enabled | | 83 | * to keep track of reference counts on a per-page basis. it is enabled |
95 | * when UVM_AMAP_PPREF is defined. | | 84 | * when UVM_AMAP_PPREF is defined. |
96 | * | | 85 | * |
97 | * when enabled, an array of ints is allocated for the pprefs. this | | 86 | * when enabled, an array of ints is allocated for the pprefs. this |
98 | * array is allocated only when a partial reference is added to the | | 87 | * array is allocated only when a partial reference is added to the |
99 | * map (either by unmapping part of the amap, or gaining a reference | | 88 | * map (either by unmapping part of the amap, or gaining a reference |
100 | * to only a part of an amap). if the allocation of the array fails | | 89 | * to only a part of an amap). if the allocation of the array fails |
101 | * (KM_NOSLEEP), then we set the array pointer to PPREF_NONE to indicate | | 90 | * (KM_NOSLEEP), then we set the array pointer to PPREF_NONE to indicate |
| @@ -160,66 +149,99 @@ pp_setreflen(int *ppref, int offset, int | | | @@ -160,66 +149,99 @@ pp_setreflen(int *ppref, int offset, int |
160 | #endif /* UVM_AMAP_PPREF */ | | 149 | #endif /* UVM_AMAP_PPREF */ |
161 | | | 150 | |
162 | /* | | 151 | /* |
163 | * amap_alloc1: allocate an amap, but do not initialise the overlay. | | 152 | * amap_alloc1: allocate an amap, but do not initialise the overlay. |
164 | * | | 153 | * |
165 | * => Note: lock is not set. | | 154 | * => Note: lock is not set. |
166 | */ | | 155 | */ |
167 | static struct vm_amap * | | 156 | static struct vm_amap * |
168 | amap_alloc1(int slots, int padslots, int flags) | | 157 | amap_alloc1(int slots, int padslots, int flags) |
169 | { | | 158 | { |
170 | const bool nowait = (flags & UVM_FLAG_NOWAIT) != 0; | | 159 | const bool nowait = (flags & UVM_FLAG_NOWAIT) != 0; |
171 | const km_flag_t kmflags = nowait ? KM_NOSLEEP : KM_SLEEP; | | 160 | const km_flag_t kmflags = nowait ? KM_NOSLEEP : KM_SLEEP; |
172 | struct vm_amap *amap; | | 161 | struct vm_amap *amap; |
| | | 162 | kmutex_t *newlock, *oldlock; |
173 | int totalslots; | | 163 | int totalslots; |
| | | 164 | size_t sz; |
174 | | | 165 | |
175 | amap = pool_cache_get(&uvm_amap_cache, nowait ? PR_NOWAIT : PR_WAITOK); | | 166 | amap = pool_cache_get(&uvm_amap_cache, nowait ? PR_NOWAIT : PR_WAITOK); |
176 | if (amap == NULL) { | | 167 | if (amap == NULL) { |
177 | return NULL; | | 168 | return NULL; |
178 | } | | 169 | } |
179 | totalslots = amap_roundup_slots(slots + padslots); | | 170 | KASSERT(amap->am_lock != NULL); |
180 | amap->am_lock = NULL; | | 171 | KASSERT(amap->am_nused == 0); |
| | | 172 | |
| | | 173 | /* Try to privatize the lock if currently shared. */ |
| | | 174 | if (mutex_obj_refcnt(amap->am_lock) > 1) { |
| | | 175 | newlock = mutex_obj_tryalloc(MUTEX_DEFAULT, IPL_NONE); |
| | | 176 | if (newlock != NULL) { |
| | | 177 | oldlock = amap->am_lock; |
| | | 178 | mutex_enter(&amap_list_lock); |
| | | 179 | amap->am_lock = newlock; |
| | | 180 | mutex_exit(&amap_list_lock); |
| | | 181 | mutex_obj_free(oldlock); |
| | | 182 | } |
| | | 183 | } |
| | | 184 | |
| | | 185 | totalslots = slots + padslots; |
181 | amap->am_ref = 1; | | 186 | amap->am_ref = 1; |
182 | amap->am_flags = 0; | | 187 | amap->am_flags = 0; |
183 | #ifdef UVM_AMAP_PPREF | | 188 | #ifdef UVM_AMAP_PPREF |
184 | amap->am_ppref = NULL; | | 189 | amap->am_ppref = NULL; |
185 | #endif | | 190 | #endif |
186 | amap->am_maxslot = totalslots; | | | |
187 | amap->am_nslot = slots; | | 191 | amap->am_nslot = slots; |
188 | amap->am_nused = 0; | | | |
189 | | | 192 | |
190 | /* | | 193 | /* |
191 | * Note: since allocations are likely big, we expect to reduce the | | 194 | * For small amaps use the storage in the amap structure. Otherwise |
192 | * memory fragmentation by allocating them in separate blocks. | | 195 | * go to the heap. Note: since allocations are likely big, we |
193 | */ | | 196 | * expect to reduce the memory fragmentation by allocating them in |
194 | amap->am_slots = kmem_alloc(totalslots * sizeof(int), kmflags); | | 197 | * separate blocks. |
195 | if (amap->am_slots == NULL) | | 198 | */ |
196 | goto fail1; | | 199 | if (totalslots <= UVM_AMAP_TINY) { |
197 | | | 200 | amap->am_maxslot = UVM_AMAP_TINY; |
198 | amap->am_bckptr = kmem_alloc(totalslots * sizeof(int), kmflags); | | 201 | amap->am_anon = AMAP_TINY_ANON(amap); |
199 | if (amap->am_bckptr == NULL) | | 202 | amap->am_slots = AMAP_TINY_SLOTS(amap); |
200 | goto fail2; | | 203 | amap->am_bckptr = amap->am_slots + UVM_AMAP_TINY; |
201 | | | 204 | } else if (totalslots <= UVM_AMAP_SMALL) { |
202 | amap->am_anon = kmem_alloc(totalslots * sizeof(struct vm_anon *), | | 205 | amap->am_maxslot = UVM_AMAP_SMALL; |
203 | kmflags); | | 206 | amap->am_anon = AMAP_TINY_ANON(amap); |
204 | if (amap->am_anon == NULL) | | 207 | |
205 | goto fail3; | | 208 | sz = UVM_AMAP_SMALL * sizeof(int) * 2; |
| | | 209 | sz = roundup2(sz, COHERENCY_UNIT); |
| | | 210 | amap->am_slots = kmem_alloc(sz, kmflags); |
| | | 211 | if (amap->am_slots == NULL) |
| | | 212 | goto fail1; |
| | | 213 | |
| | | 214 | amap->am_bckptr = amap->am_slots + amap->am_maxslot; |
| | | 215 | } else { |
| | | 216 | amap->am_maxslot = amap_roundup_slots(totalslots); |
| | | 217 | sz = amap->am_maxslot * sizeof(int) * 2; |
| | | 218 | KASSERT((sz & (COHERENCY_UNIT - 1)) == 0); |
| | | 219 | amap->am_slots = kmem_alloc(sz, kmflags); |
| | | 220 | if (amap->am_slots == NULL) |
| | | 221 | goto fail1; |
| | | 222 | |
| | | 223 | amap->am_bckptr = amap->am_slots + amap->am_maxslot; |
| | | 224 | |
| | | 225 | amap->am_anon = kmem_alloc(amap->am_maxslot * |
| | | 226 | sizeof(struct vm_anon *), kmflags); |
| | | 227 | if (amap->am_anon == NULL) |
| | | 228 | goto fail2; |
| | | 229 | } |
206 | | | 230 | |
207 | return amap; | | 231 | return amap; |
208 | | | 232 | |
209 | fail3: | | | |
210 | kmem_free(amap->am_bckptr, totalslots * sizeof(int)); | | | |
211 | fail2: | | 233 | fail2: |
212 | kmem_free(amap->am_slots, totalslots * sizeof(int)); | | 234 | kmem_free(amap->am_slots, amap->am_maxslot * sizeof(int)); |
213 | fail1: | | 235 | fail1: |
214 | pool_cache_put(&uvm_amap_cache, amap); | | 236 | pool_cache_put(&uvm_amap_cache, amap); |
215 | | | 237 | |
216 | /* | | 238 | /* |
217 | * XXX hack to tell the pagedaemon how many pages we need, | | 239 | * XXX hack to tell the pagedaemon how many pages we need, |
218 | * since we can need more than it would normally free. | | 240 | * since we can need more than it would normally free. |
219 | */ | | 241 | */ |
220 | if (nowait) { | | 242 | if (nowait) { |
221 | extern u_int uvm_extrapages; | | 243 | extern u_int uvm_extrapages; |
222 | atomic_add_int(&uvm_extrapages, | | 244 | atomic_add_int(&uvm_extrapages, |
223 | ((sizeof(int) * 2 + sizeof(struct vm_anon *)) * | | 245 | ((sizeof(int) * 2 + sizeof(struct vm_anon *)) * |
224 | totalslots) >> PAGE_SHIFT); | | 246 | totalslots) >> PAGE_SHIFT); |
225 | } | | 247 | } |
| @@ -238,74 +260,128 @@ struct vm_amap * | | | @@ -238,74 +260,128 @@ struct vm_amap * |
238 | amap_alloc(vaddr_t sz, vaddr_t padsz, int waitf) | | 260 | amap_alloc(vaddr_t sz, vaddr_t padsz, int waitf) |
239 | { | | 261 | { |
240 | struct vm_amap *amap; | | 262 | struct vm_amap *amap; |
241 | int slots, padslots; | | 263 | int slots, padslots; |
242 | UVMHIST_FUNC("amap_alloc"); UVMHIST_CALLED(maphist); | | 264 | UVMHIST_FUNC("amap_alloc"); UVMHIST_CALLED(maphist); |
243 | | | 265 | |
244 | AMAP_B2SLOT(slots, sz); | | 266 | AMAP_B2SLOT(slots, sz); |
245 | AMAP_B2SLOT(padslots, padsz); | | 267 | AMAP_B2SLOT(padslots, padsz); |
246 | | | 268 | |
247 | amap = amap_alloc1(slots, padslots, waitf); | | 269 | amap = amap_alloc1(slots, padslots, waitf); |
248 | if (amap) { | | 270 | if (amap) { |
249 | memset(amap->am_anon, 0, | | 271 | memset(amap->am_anon, 0, |
250 | amap->am_maxslot * sizeof(struct vm_anon *)); | | 272 | amap->am_maxslot * sizeof(struct vm_anon *)); |
251 | amap->am_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); | | | |
252 | amap_list_insert(amap); | | | |
253 | } | | 273 | } |
254 | | | 274 | |
255 | UVMHIST_LOG(maphist,"<- done, amap = 0x%#jx, sz=%jd", (uintptr_t)amap, | | 275 | UVMHIST_LOG(maphist,"<- done, amap = 0x%#jx, sz=%jd", (uintptr_t)amap, |
256 | sz, 0, 0); | | 276 | sz, 0, 0); |
257 | return(amap); | | 277 | return(amap); |
258 | } | | 278 | } |
259 | | | 279 | |
260 | /* | | 280 | /* |
| | | 281 | * amap_ctor: pool_cache constructor for new amaps |
| | | 282 | * |
| | | 283 | * => carefully synchronize with amap_swap_off() |
| | | 284 | */ |
| | | 285 | static int |
| | | 286 | amap_ctor(void *arg, void *obj, int flags) |
| | | 287 | { |
| | | 288 | struct vm_amap *amap = obj; |
| | | 289 | |
| | | 290 | if ((flags & PR_NOWAIT) != 0) { |
| | | 291 | amap->am_lock = mutex_obj_tryalloc(MUTEX_DEFAULT, IPL_NONE); |
| | | 292 | if (amap->am_lock == NULL) { |
| | | 293 | return ENOMEM; |
| | | 294 | } |
| | | 295 | } else { |
| | | 296 | amap->am_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
| | | 297 | } |
| | | 298 | amap->am_nused = 0; |
| | | 299 | amap->am_flags = 0; |
| | | 300 | |
| | | 301 | mutex_enter(&amap_list_lock); |
| | | 302 | LIST_INSERT_HEAD(&amap_list, amap, am_list); |
| | | 303 | mutex_exit(&amap_list_lock); |
| | | 304 | return 0; |
| | | 305 | } |
| | | 306 | |
| | | 307 | /* |
| | | 308 | * amap_ctor: pool_cache destructor for amaps |
| | | 309 | * |
| | | 310 | * => carefully synchronize with amap_swap_off() |
| | | 311 | */ |
| | | 312 | static void |
| | | 313 | amap_dtor(void *arg, void *obj) |
| | | 314 | { |
| | | 315 | struct vm_amap *amap = obj; |
| | | 316 | |
| | | 317 | KASSERT(amap->am_nused == 0); |
| | | 318 | |
| | | 319 | mutex_enter(&amap_list_lock); |
| | | 320 | LIST_REMOVE(amap, am_list); |
| | | 321 | mutex_exit(&amap_list_lock); |
| | | 322 | mutex_obj_free(amap->am_lock); |
| | | 323 | } |
| | | 324 | |
| | | 325 | /* |
261 | * uvm_amap_init: initialize the amap system. | | 326 | * uvm_amap_init: initialize the amap system. |
262 | */ | | 327 | */ |
263 | void | | 328 | void |
264 | uvm_amap_init(void) | | 329 | uvm_amap_init(void) |
265 | { | | 330 | { |
266 | | | 331 | |
| | | 332 | #if defined(_LP64) |
| | | 333 | /* |
| | | 334 | * Correct alignment helps performance. For 32-bit platforms, KVA |
| | | 335 | * availibility is a concern so leave them be. |
| | | 336 | */ |
| | | 337 | KASSERT((sizeof(struct vm_amap) & (COHERENCY_UNIT - 1)) == 0); |
| | | 338 | #endif |
| | | 339 | |
267 | mutex_init(&amap_list_lock, MUTEX_DEFAULT, IPL_NONE); | | 340 | mutex_init(&amap_list_lock, MUTEX_DEFAULT, IPL_NONE); |
268 | | | 341 | |
269 | pool_cache_bootstrap(&uvm_amap_cache, sizeof(struct vm_amap), 0, 0, 0, | | 342 | pool_cache_bootstrap(&uvm_amap_cache, sizeof(struct vm_amap), |
270 | "amappl", NULL, IPL_NONE, NULL, NULL, NULL); | | 343 | COHERENCY_UNIT, 0, 0, "amappl", NULL, IPL_NONE, amap_ctor, |
| | | 344 | amap_dtor, NULL); |
271 | } | | 345 | } |
272 | | | 346 | |
273 | /* | | 347 | /* |
274 | * amap_free: free an amap | | 348 | * amap_free: free an amap |
275 | * | | 349 | * |
276 | * => the amap must be unlocked | | 350 | * => the amap must be unlocked |
277 | * => the amap should have a zero reference count and be empty | | 351 | * => the amap should have a zero reference count and be empty |
278 | */ | | 352 | */ |
279 | void | | 353 | void |
280 | amap_free(struct vm_amap *amap) | | 354 | amap_free(struct vm_amap *amap) |
281 | { | | 355 | { |
282 | int slots; | | 356 | int slots; |
283 | | | 357 | |
284 | UVMHIST_FUNC("amap_free"); UVMHIST_CALLED(maphist); | | 358 | UVMHIST_FUNC("amap_free"); UVMHIST_CALLED(maphist); |
285 | | | 359 | |
286 | KASSERT(amap->am_ref == 0 && amap->am_nused == 0); | | 360 | KASSERT(amap->am_ref == 0 && amap->am_nused == 0); |
287 | KASSERT((amap->am_flags & AMAP_SWAPOFF) == 0); | | 361 | KASSERT((amap->am_flags & AMAP_SWAPOFF) == 0); |
288 | if (amap->am_lock != NULL) { | | | |
289 | KASSERT(!mutex_owned(amap->am_lock)); | | | |
290 | mutex_obj_free(amap->am_lock); | | | |
291 | } | | | |
292 | slots = amap->am_maxslot; | | 362 | slots = amap->am_maxslot; |
293 | kmem_free(amap->am_slots, slots * sizeof(*amap->am_slots)); | | 363 | if (amap->am_slots != AMAP_TINY_SLOTS(amap)) { |
294 | kmem_free(amap->am_bckptr, slots * sizeof(*amap->am_bckptr)); | | 364 | kmem_free(amap->am_slots, roundup2(slots * sizeof(int) * 2, |
295 | kmem_free(amap->am_anon, slots * sizeof(*amap->am_anon)); | | 365 | COHERENCY_UNIT)); |
| | | 366 | } |
| | | 367 | if (amap->am_anon != AMAP_TINY_ANON(amap)) { |
| | | 368 | kmem_free(amap->am_anon, slots * sizeof(*amap->am_anon)); |
| | | 369 | } |
296 | #ifdef UVM_AMAP_PPREF | | 370 | #ifdef UVM_AMAP_PPREF |
297 | if (amap->am_ppref && amap->am_ppref != PPREF_NONE) | | 371 | if (amap->am_ppref && amap->am_ppref != PPREF_NONE) { |
298 | kmem_free(amap->am_ppref, slots * sizeof(*amap->am_ppref)); | | 372 | kmem_free(amap->am_ppref, roundup2(slots * sizeof(int), |
| | | 373 | COHERENCY_UNIT)); |
| | | 374 | } |
299 | #endif | | 375 | #endif |
300 | pool_cache_put(&uvm_amap_cache, amap); | | 376 | pool_cache_put(&uvm_amap_cache, amap); |
301 | UVMHIST_LOG(maphist,"<- done, freed amap = 0x%#jx", (uintptr_t)amap, | | 377 | UVMHIST_LOG(maphist,"<- done, freed amap = 0x%#jx", (uintptr_t)amap, |
302 | 0, 0, 0); | | 378 | 0, 0, 0); |
303 | } | | 379 | } |
304 | | | 380 | |
305 | /* | | 381 | /* |
306 | * amap_extend: extend the size of an amap (if needed) | | 382 | * amap_extend: extend the size of an amap (if needed) |
307 | * | | 383 | * |
308 | * => called from uvm_map when we want to extend an amap to cover | | 384 | * => called from uvm_map when we want to extend an amap to cover |
309 | * a new mapping (rather than allocate a new one) | | 385 | * a new mapping (rather than allocate a new one) |
310 | * => amap should be unlocked (we will lock it) | | 386 | * => amap should be unlocked (we will lock it) |
311 | * => to safely extend an amap it should have a reference count of | | 387 | * => to safely extend an amap it should have a reference count of |
| @@ -336,28 +412,27 @@ amap_extend(struct vm_map_entry *entry, | | | @@ -336,28 +412,27 @@ amap_extend(struct vm_map_entry *entry, |
336 | * first, determine how many slots we need in the amap. don't | | 412 | * first, determine how many slots we need in the amap. don't |
337 | * forget that ar_pageoff could be non-zero: this means that | | 413 | * forget that ar_pageoff could be non-zero: this means that |
338 | * there are some unused slots before us in the amap. | | 414 | * there are some unused slots before us in the amap. |
339 | */ | | 415 | */ |
340 | | | 416 | |
341 | amap_lock(amap); | | 417 | amap_lock(amap); |
342 | KASSERT(amap_refs(amap) == 1); /* amap can't be shared */ | | 418 | KASSERT(amap_refs(amap) == 1); /* amap can't be shared */ |
343 | AMAP_B2SLOT(slotmapped, entry->end - entry->start); /* slots mapped */ | | 419 | AMAP_B2SLOT(slotmapped, entry->end - entry->start); /* slots mapped */ |
344 | AMAP_B2SLOT(slotadd, addsize); /* slots to add */ | | 420 | AMAP_B2SLOT(slotadd, addsize); /* slots to add */ |
345 | if (flags & AMAP_EXTEND_FORWARDS) { | | 421 | if (flags & AMAP_EXTEND_FORWARDS) { |
346 | slotneed = slotoff + slotmapped + slotadd; | | 422 | slotneed = slotoff + slotmapped + slotadd; |
347 | slotadj = 0; | | 423 | slotadj = 0; |
348 | slotarea = 0; | | 424 | slotarea = 0; |
349 | } | | 425 | } else { |
350 | else { | | | |
351 | slotneed = slotadd + slotmapped; | | 426 | slotneed = slotadd + slotmapped; |
352 | slotadj = slotadd - slotoff; | | 427 | slotadj = slotadd - slotoff; |
353 | slotarea = amap->am_maxslot - slotmapped; | | 428 | slotarea = amap->am_maxslot - slotmapped; |
354 | } | | 429 | } |
355 | tofree = NULL; | | 430 | tofree = NULL; |
356 | | | 431 | |
357 | /* | | 432 | /* |
358 | * case 1: we already have enough slots in the map and thus | | 433 | * case 1: we already have enough slots in the map and thus |
359 | * only need to bump the reference counts on the slots we are | | 434 | * only need to bump the reference counts on the slots we are |
360 | * adding. | | 435 | * adding. |
361 | */ | | 436 | */ |
362 | | | 437 | |
363 | if (flags & AMAP_EXTEND_FORWARDS) { | | 438 | if (flags & AMAP_EXTEND_FORWARDS) { |
| @@ -492,43 +567,42 @@ amap_extend(struct vm_map_entry *entry, | | | @@ -492,43 +567,42 @@ amap_extend(struct vm_map_entry *entry, |
492 | */ | | 567 | */ |
493 | | | 568 | |
494 | amap_unlock(amap); | | 569 | amap_unlock(amap); |
495 | | | 570 | |
496 | if (slotneed >= UVM_AMAP_LARGE) { | | 571 | if (slotneed >= UVM_AMAP_LARGE) { |
497 | return E2BIG; | | 572 | return E2BIG; |
498 | } | | 573 | } |
499 | | | 574 | |
500 | slotalloc = amap_roundup_slots(slotneed); | | 575 | slotalloc = amap_roundup_slots(slotneed); |
501 | #ifdef UVM_AMAP_PPREF | | 576 | #ifdef UVM_AMAP_PPREF |
502 | newppref = NULL; | | 577 | newppref = NULL; |
503 | if (amap->am_ppref && amap->am_ppref != PPREF_NONE) { | | 578 | if (amap->am_ppref && amap->am_ppref != PPREF_NONE) { |
504 | /* Will be handled later if fails. */ | | 579 | /* Will be handled later if fails. */ |
505 | newppref = kmem_alloc(slotalloc * sizeof(*newppref), kmflags); | | 580 | newppref = kmem_alloc(roundup2(slotalloc * sizeof(int), |
| | | 581 | COHERENCY_UNIT), kmflags); |
506 | } | | 582 | } |
507 | #endif | | 583 | #endif |
508 | newsl = kmem_alloc(slotalloc * sizeof(*newsl), kmflags); | | 584 | newsl = kmem_alloc(slotalloc * sizeof(*newsl) * 2, kmflags); |
509 | newbck = kmem_alloc(slotalloc * sizeof(*newbck), kmflags); | | 585 | newbck = newsl + slotalloc; |
510 | newover = kmem_alloc(slotalloc * sizeof(*newover), kmflags); | | 586 | newover = kmem_alloc(slotalloc * sizeof(*newover), kmflags); |
511 | if (newsl == NULL || newbck == NULL || newover == NULL) { | | 587 | if (newsl == NULL || newbck == NULL || newover == NULL) { |
512 | #ifdef UVM_AMAP_PPREF | | 588 | #ifdef UVM_AMAP_PPREF |
513 | if (newppref != NULL) { | | 589 | if (newppref != NULL) { |
514 | kmem_free(newppref, slotalloc * sizeof(*newppref)); | | 590 | kmem_free(newppref, roundup2(slotalloc * sizeof(int), |
| | | 591 | COHERENCY_UNIT)); |
515 | } | | 592 | } |
516 | #endif | | 593 | #endif |
517 | if (newsl != NULL) { | | 594 | if (newsl != NULL) { |
518 | kmem_free(newsl, slotalloc * sizeof(*newsl)); | | 595 | kmem_free(newsl, slotalloc * sizeof(*newsl) * 2); |
519 | } | | | |
520 | if (newbck != NULL) { | | | |
521 | kmem_free(newbck, slotalloc * sizeof(*newbck)); | | | |
522 | } | | 596 | } |
523 | if (newover != NULL) { | | 597 | if (newover != NULL) { |
524 | kmem_free(newover, slotalloc * sizeof(*newover)); | | 598 | kmem_free(newover, slotalloc * sizeof(*newover)); |
525 | } | | 599 | } |
526 | return ENOMEM; | | 600 | return ENOMEM; |
527 | } | | 601 | } |
528 | amap_lock(amap); | | 602 | amap_lock(amap); |
529 | KASSERT(amap->am_maxslot < slotneed); | | 603 | KASSERT(amap->am_maxslot < slotneed); |
530 | | | 604 | |
531 | /* | | 605 | /* |
532 | * Copy everything over to new allocated areas. | | 606 | * Copy everything over to new allocated areas. |
533 | */ | | 607 | */ |
534 | | | 608 | |
| @@ -605,32 +679,38 @@ amap_extend(struct vm_map_entry *entry, | | | @@ -605,32 +679,38 @@ amap_extend(struct vm_map_entry *entry, |
605 | | | 679 | |
606 | /* update master values */ | | 680 | /* update master values */ |
607 | if (flags & AMAP_EXTEND_FORWARDS) | | 681 | if (flags & AMAP_EXTEND_FORWARDS) |
608 | amap->am_nslot = slotneed; | | 682 | amap->am_nslot = slotneed; |
609 | else { | | 683 | else { |
610 | entry->aref.ar_pageoff = slotarea - slotadd; | | 684 | entry->aref.ar_pageoff = slotarea - slotadd; |
611 | amap->am_nslot = slotalloc; | | 685 | amap->am_nslot = slotalloc; |
612 | } | | 686 | } |
613 | oldnslots = amap->am_maxslot; | | 687 | oldnslots = amap->am_maxslot; |
614 | amap->am_maxslot = slotalloc; | | 688 | amap->am_maxslot = slotalloc; |
615 | | | 689 | |
616 | uvm_anon_freelst(amap, tofree); | | 690 | uvm_anon_freelst(amap, tofree); |
617 | | | 691 | |
618 | kmem_free(oldsl, oldnslots * sizeof(*oldsl)); | | 692 | if (oldsl != AMAP_TINY_SLOTS(amap)) { |
619 | kmem_free(oldbck, oldnslots * sizeof(*oldbck)); | | 693 | kmem_free(oldsl, roundup2(oldnslots * sizeof(int) * 2, |
620 | kmem_free(oldover, oldnslots * sizeof(*oldover)); | | 694 | COHERENCY_UNIT)); |
| | | 695 | } |
| | | 696 | if (oldover != AMAP_TINY_ANON(amap)) { |
| | | 697 | kmem_free(oldover, oldnslots * sizeof(*oldover)); |
| | | 698 | } |
621 | #ifdef UVM_AMAP_PPREF | | 699 | #ifdef UVM_AMAP_PPREF |
622 | if (oldppref && oldppref != PPREF_NONE) | | 700 | if (oldppref && oldppref != PPREF_NONE) { |
623 | kmem_free(oldppref, oldnslots * sizeof(*oldppref)); | | 701 | kmem_free(oldppref, roundup2(oldnslots * sizeof(int), |
| | | 702 | COHERENCY_UNIT)); |
| | | 703 | } |
624 | #endif | | 704 | #endif |
625 | UVMHIST_LOG(maphist,"<- done (case 3), amap = 0x%#jx, slotneed=%jd", | | 705 | UVMHIST_LOG(maphist,"<- done (case 3), amap = 0x%#jx, slotneed=%jd", |
626 | (uintptr_t)amap, slotneed, 0, 0); | | 706 | (uintptr_t)amap, slotneed, 0, 0); |
627 | return 0; | | 707 | return 0; |
628 | } | | 708 | } |
629 | | | 709 | |
630 | /* | | 710 | /* |
631 | * amap_share_protect: change protection of anons in a shared amap | | 711 | * amap_share_protect: change protection of anons in a shared amap |
632 | * | | 712 | * |
633 | * for shared amaps, given the current data structure layout, it is | | 713 | * for shared amaps, given the current data structure layout, it is |
634 | * not possible for us to directly locate all maps referencing the | | 714 | * not possible for us to directly locate all maps referencing the |
635 | * shared anon (to change the protection). in order to protect data | | 715 | * shared anon (to change the protection). in order to protect data |
636 | * in shared maps we use pmap_page_protect(). [this is useful for IPC | | 716 | * in shared maps we use pmap_page_protect(). [this is useful for IPC |
| @@ -699,27 +779,26 @@ amap_wipeout(struct vm_amap *amap) | | | @@ -699,27 +779,26 @@ amap_wipeout(struct vm_amap *amap) |
699 | UVMHIST_FUNC("amap_wipeout"); UVMHIST_CALLED(maphist); | | 779 | UVMHIST_FUNC("amap_wipeout"); UVMHIST_CALLED(maphist); |
700 | UVMHIST_LOG(maphist,"(amap=0x%#jx)", (uintptr_t)amap, 0,0,0); | | 780 | UVMHIST_LOG(maphist,"(amap=0x%#jx)", (uintptr_t)amap, 0,0,0); |
701 | | | 781 | |
702 | KASSERT(mutex_owned(amap->am_lock)); | | 782 | KASSERT(mutex_owned(amap->am_lock)); |
703 | KASSERT(amap->am_ref == 0); | | 783 | KASSERT(amap->am_ref == 0); |
704 | | | 784 | |
705 | if (__predict_false(amap->am_flags & AMAP_SWAPOFF)) { | | 785 | if (__predict_false(amap->am_flags & AMAP_SWAPOFF)) { |
706 | /* | | 786 | /* |
707 | * Note: amap_swap_off() will call us again. | | 787 | * Note: amap_swap_off() will call us again. |
708 | */ | | 788 | */ |
709 | amap_unlock(amap); | | 789 | amap_unlock(amap); |
710 | return; | | 790 | return; |
711 | } | | 791 | } |
712 | amap_list_remove(amap); | | | |
713 | | | 792 | |
714 | for (lcv = 0 ; lcv < amap->am_nused ; lcv++) { | | 793 | for (lcv = 0 ; lcv < amap->am_nused ; lcv++) { |
715 | struct vm_anon *anon; | | 794 | struct vm_anon *anon; |
716 | u_int slot; | | 795 | u_int slot; |
717 | | | 796 | |
718 | slot = amap->am_slots[lcv]; | | 797 | slot = amap->am_slots[lcv]; |
719 | anon = amap->am_anon[slot]; | | 798 | anon = amap->am_anon[slot]; |
720 | KASSERT(anon != NULL && anon->an_ref != 0); | | 799 | KASSERT(anon != NULL && anon->an_ref != 0); |
721 | | | 800 | |
722 | KASSERT(anon->an_lock == amap->am_lock); | | 801 | KASSERT(anon->an_lock == amap->am_lock); |
723 | UVMHIST_LOG(maphist," processing anon 0x%#jx, ref=%jd", | | 802 | UVMHIST_LOG(maphist," processing anon 0x%#jx, ref=%jd", |
724 | (uintptr_t)anon, anon->an_ref, 0, 0); | | 803 | (uintptr_t)anon, anon->an_ref, 0, 0); |
725 | | | 804 | |
| @@ -758,26 +837,27 @@ amap_wipeout(struct vm_amap *amap) | | | @@ -758,26 +837,27 @@ amap_wipeout(struct vm_amap *amap) |
758 | * used to limit chunking (e.g. if you have a large space that you | | 837 | * used to limit chunking (e.g. if you have a large space that you |
759 | * know you are going to need to allocate amaps for, there is no point | | 838 | * know you are going to need to allocate amaps for, there is no point |
760 | * in allowing that to be chunked) | | 839 | * in allowing that to be chunked) |
761 | */ | | 840 | */ |
762 | | | 841 | |
763 | void | | 842 | void |
764 | amap_copy(struct vm_map *map, struct vm_map_entry *entry, int flags, | | 843 | amap_copy(struct vm_map *map, struct vm_map_entry *entry, int flags, |
765 | vaddr_t startva, vaddr_t endva) | | 844 | vaddr_t startva, vaddr_t endva) |
766 | { | | 845 | { |
767 | const int waitf = (flags & AMAP_COPY_NOWAIT) ? UVM_FLAG_NOWAIT : 0; | | 846 | const int waitf = (flags & AMAP_COPY_NOWAIT) ? UVM_FLAG_NOWAIT : 0; |
768 | struct vm_amap *amap, *srcamap; | | 847 | struct vm_amap *amap, *srcamap; |
769 | struct vm_anon *tofree; | | 848 | struct vm_anon *tofree; |
770 | u_int slots, lcv; | | 849 | u_int slots, lcv; |
| | | 850 | kmutex_t *oldlock; |
771 | vsize_t len; | | 851 | vsize_t len; |
772 | | | 852 | |
773 | UVMHIST_FUNC("amap_copy"); UVMHIST_CALLED(maphist); | | 853 | UVMHIST_FUNC("amap_copy"); UVMHIST_CALLED(maphist); |
774 | UVMHIST_LOG(maphist, " (map=%#j, entry=%#j, flags=%jd)", | | 854 | UVMHIST_LOG(maphist, " (map=%#j, entry=%#j, flags=%jd)", |
775 | (uintptr_t)map, (uintptr_t)entry, flags, 0); | | 855 | (uintptr_t)map, (uintptr_t)entry, flags, 0); |
776 | | | 856 | |
777 | KASSERT(map != kernel_map); /* we use nointr pool */ | | 857 | KASSERT(map != kernel_map); /* we use nointr pool */ |
778 | | | 858 | |
779 | srcamap = entry->aref.ar_amap; | | 859 | srcamap = entry->aref.ar_amap; |
780 | len = entry->end - entry->start; | | 860 | len = entry->end - entry->start; |
781 | | | 861 | |
782 | /* | | 862 | /* |
783 | * Is there an amap to copy? If not, create one. | | 863 | * Is there an amap to copy? If not, create one. |
| @@ -842,36 +922,49 @@ amap_copy(struct vm_map *map, struct vm_ | | | @@ -842,36 +922,49 @@ amap_copy(struct vm_map *map, struct vm_ |
842 | */ | | 922 | */ |
843 | | | 923 | |
844 | if (srcamap->am_ref == 1) { | | 924 | if (srcamap->am_ref == 1) { |
845 | entry->etype &= ~UVM_ET_NEEDSCOPY; | | 925 | entry->etype &= ~UVM_ET_NEEDSCOPY; |
846 | UVMHIST_LOG(maphist, "<- done [ref cnt = 1, took it over]", | | 926 | UVMHIST_LOG(maphist, "<- done [ref cnt = 1, took it over]", |
847 | 0, 0, 0, 0); | | 927 | 0, 0, 0, 0); |
848 | return; | | 928 | return; |
849 | } | | 929 | } |
850 | | | 930 | |
851 | UVMHIST_LOG(maphist," amap=%#j, ref=%jd, must copy it", | | 931 | UVMHIST_LOG(maphist," amap=%#j, ref=%jd, must copy it", |
852 | (uintptr_t)srcamap, srcamap->am_ref, 0, 0); | | 932 | (uintptr_t)srcamap, srcamap->am_ref, 0, 0); |
853 | | | 933 | |
854 | /* | | 934 | /* |
855 | * Allocate a new amap (note: not initialised, no lock set, etc). | | 935 | * Allocate a new amap (note: not initialised, etc). |
856 | */ | | 936 | */ |
857 | | | 937 | |
858 | AMAP_B2SLOT(slots, len); | | 938 | AMAP_B2SLOT(slots, len); |
859 | amap = amap_alloc1(slots, 0, waitf); | | 939 | amap = amap_alloc1(slots, 0, waitf); |
860 | if (amap == NULL) { | | 940 | if (amap == NULL) { |
861 | UVMHIST_LOG(maphist, " amap_alloc1 failed", 0,0,0,0); | | 941 | UVMHIST_LOG(maphist, " amap_alloc1 failed", 0,0,0,0); |
862 | return; | | 942 | return; |
863 | } | | 943 | } |
864 | | | 944 | |
| | | 945 | /* |
| | | 946 | * Make the new amap share the source amap's lock, and then lock |
| | | 947 | * both. We must do this before we set am_nused != 0, otherwise |
| | | 948 | * amap_swap_off() can become interested in the amap. |
| | | 949 | */ |
| | | 950 | |
| | | 951 | oldlock = amap->am_lock; |
| | | 952 | mutex_enter(&amap_list_lock); |
| | | 953 | amap->am_lock = srcamap->am_lock; |
| | | 954 | mutex_exit(&amap_list_lock); |
| | | 955 | mutex_obj_hold(amap->am_lock); |
| | | 956 | mutex_obj_free(oldlock); |
| | | 957 | |
865 | amap_lock(srcamap); | | 958 | amap_lock(srcamap); |
866 | | | 959 | |
867 | /* | | 960 | /* |
868 | * Re-check the reference count with the lock held. If it has | | 961 | * Re-check the reference count with the lock held. If it has |
869 | * dropped to one - we can take over the existing map. | | 962 | * dropped to one - we can take over the existing map. |
870 | */ | | 963 | */ |
871 | | | 964 | |
872 | if (srcamap->am_ref == 1) { | | 965 | if (srcamap->am_ref == 1) { |
873 | /* Just take over the existing amap. */ | | 966 | /* Just take over the existing amap. */ |
874 | entry->etype &= ~UVM_ET_NEEDSCOPY; | | 967 | entry->etype &= ~UVM_ET_NEEDSCOPY; |
875 | amap_unlock(srcamap); | | 968 | amap_unlock(srcamap); |
876 | /* Destroy the new (unused) amap. */ | | 969 | /* Destroy the new (unused) amap. */ |
877 | amap->am_ref--; | | 970 | amap->am_ref--; |
| @@ -910,43 +1003,28 @@ amap_copy(struct vm_map *map, struct vm_ | | | @@ -910,43 +1003,28 @@ amap_copy(struct vm_map *map, struct vm_ |
910 | KASSERT(srcamap->am_ref > 0); | | 1003 | KASSERT(srcamap->am_ref > 0); |
911 | | | 1004 | |
912 | if (srcamap->am_ref == 1 && (srcamap->am_flags & AMAP_SHARED) != 0) { | | 1005 | if (srcamap->am_ref == 1 && (srcamap->am_flags & AMAP_SHARED) != 0) { |
913 | srcamap->am_flags &= ~AMAP_SHARED; | | 1006 | srcamap->am_flags &= ~AMAP_SHARED; |
914 | } | | 1007 | } |
915 | tofree = NULL; | | 1008 | tofree = NULL; |
916 | #ifdef UVM_AMAP_PPREF | | 1009 | #ifdef UVM_AMAP_PPREF |
917 | if (srcamap->am_ppref && srcamap->am_ppref != PPREF_NONE) { | | 1010 | if (srcamap->am_ppref && srcamap->am_ppref != PPREF_NONE) { |
918 | amap_pp_adjref(srcamap, entry->aref.ar_pageoff, | | 1011 | amap_pp_adjref(srcamap, entry->aref.ar_pageoff, |
919 | len >> PAGE_SHIFT, -1, &tofree); | | 1012 | len >> PAGE_SHIFT, -1, &tofree); |
920 | } | | 1013 | } |
921 | #endif | | 1014 | #endif |
922 | | | 1015 | |
923 | /* | | | |
924 | * If we referenced any anons, then share the source amap's lock. | | | |
925 | * Otherwise, we have nothing in common, so allocate a new one. | | | |
926 | */ | | | |
927 | | | | |
928 | KASSERT(amap->am_lock == NULL); | | | |
929 | if (amap->am_nused != 0) { | | | |
930 | amap->am_lock = srcamap->am_lock; | | | |
931 | mutex_obj_hold(amap->am_lock); | | | |
932 | } | | | |
933 | uvm_anon_freelst(srcamap, tofree); | | 1016 | uvm_anon_freelst(srcamap, tofree); |
934 | | | 1017 | |
935 | if (amap->am_lock == NULL) { | | | |
936 | amap->am_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); | | | |
937 | } | | | |
938 | amap_list_insert(amap); | | | |
939 | | | | |
940 | /* | | 1018 | /* |
941 | * Install new amap. | | 1019 | * Install new amap. |
942 | */ | | 1020 | */ |
943 | | | 1021 | |
944 | entry->aref.ar_pageoff = 0; | | 1022 | entry->aref.ar_pageoff = 0; |
945 | entry->aref.ar_amap = amap; | | 1023 | entry->aref.ar_amap = amap; |
946 | entry->etype &= ~UVM_ET_NEEDSCOPY; | | 1024 | entry->etype &= ~UVM_ET_NEEDSCOPY; |
947 | UVMHIST_LOG(maphist, "<- done",0, 0, 0, 0); | | 1025 | UVMHIST_LOG(maphist, "<- done",0, 0, 0, 0); |
948 | } | | 1026 | } |
949 | | | 1027 | |
950 | /* | | 1028 | /* |
951 | * amap_cow_now: resolve all copy-on-write faults in an amap now for fork(2) | | 1029 | * amap_cow_now: resolve all copy-on-write faults in an amap now for fork(2) |
952 | * | | 1030 | * |
| @@ -1110,27 +1188,28 @@ amap_splitref(struct vm_aref *origref, s | | | @@ -1110,27 +1188,28 @@ amap_splitref(struct vm_aref *origref, s |
1110 | amap_unlock(amap); | | 1188 | amap_unlock(amap); |
1111 | } | | 1189 | } |
1112 | | | 1190 | |
1113 | #ifdef UVM_AMAP_PPREF | | 1191 | #ifdef UVM_AMAP_PPREF |
1114 | | | 1192 | |
1115 | /* | | 1193 | /* |
1116 | * amap_pp_establish: add a ppref array to an amap, if possible. | | 1194 | * amap_pp_establish: add a ppref array to an amap, if possible. |
1117 | * | | 1195 | * |
1118 | * => amap should be locked by caller. | | 1196 | * => amap should be locked by caller. |
1119 | */ | | 1197 | */ |
1120 | void | | 1198 | void |
1121 | amap_pp_establish(struct vm_amap *amap, vaddr_t offset) | | 1199 | amap_pp_establish(struct vm_amap *amap, vaddr_t offset) |
1122 | { | | 1200 | { |
1123 | const size_t sz = amap->am_maxslot * sizeof(*amap->am_ppref); | | 1201 | const size_t sz = roundup2(amap->am_maxslot * sizeof(*amap->am_ppref), |
| | | 1202 | COHERENCY_UNIT); |
1124 | | | 1203 | |
1125 | KASSERT(mutex_owned(amap->am_lock)); | | 1204 | KASSERT(mutex_owned(amap->am_lock)); |
1126 | | | 1205 | |
1127 | amap->am_ppref = kmem_zalloc(sz, KM_NOSLEEP); | | 1206 | amap->am_ppref = kmem_zalloc(sz, KM_NOSLEEP); |
1128 | if (amap->am_ppref == NULL) { | | 1207 | if (amap->am_ppref == NULL) { |
1129 | /* Failure - just do not use ppref. */ | | 1208 | /* Failure - just do not use ppref. */ |
1130 | amap->am_ppref = PPREF_NONE; | | 1209 | amap->am_ppref = PPREF_NONE; |
1131 | return; | | 1210 | return; |
1132 | } | | 1211 | } |
1133 | pp_setreflen(amap->am_ppref, 0, 0, offset); | | 1212 | pp_setreflen(amap->am_ppref, 0, 0, offset); |
1134 | pp_setreflen(amap->am_ppref, offset, amap->am_ref, | | 1213 | pp_setreflen(amap->am_ppref, offset, amap->am_ref, |
1135 | amap->am_nslot - offset); | | 1214 | amap->am_nslot - offset); |
1136 | } | | 1215 | } |
| @@ -1311,49 +1390,44 @@ amap_swap_off(int startslot, int endslot | | | @@ -1311,49 +1390,44 @@ amap_swap_off(int startslot, int endslot |
1311 | | | 1390 | |
1312 | #if defined(DIAGNOSTIC) | | 1391 | #if defined(DIAGNOSTIC) |
1313 | memset(&marker_prev, 0, sizeof(marker_prev)); | | 1392 | memset(&marker_prev, 0, sizeof(marker_prev)); |
1314 | memset(&marker_next, 0, sizeof(marker_next)); | | 1393 | memset(&marker_next, 0, sizeof(marker_next)); |
1315 | #endif /* defined(DIAGNOSTIC) */ | | 1394 | #endif /* defined(DIAGNOSTIC) */ |
1316 | | | 1395 | |
1317 | mutex_enter(&amap_list_lock); | | 1396 | mutex_enter(&amap_list_lock); |
1318 | for (am = LIST_FIRST(&amap_list); am != NULL && !rv; am = am_next) { | | 1397 | for (am = LIST_FIRST(&amap_list); am != NULL && !rv; am = am_next) { |
1319 | int i; | | 1398 | int i; |
1320 | | | 1399 | |
1321 | LIST_INSERT_BEFORE(am, &marker_prev, am_list); | | 1400 | LIST_INSERT_BEFORE(am, &marker_prev, am_list); |
1322 | LIST_INSERT_AFTER(am, &marker_next, am_list); | | 1401 | LIST_INSERT_AFTER(am, &marker_next, am_list); |
1323 | | | 1402 | |
| | | 1403 | /* amap_list_lock prevents the lock pointer from changing. */ |
1324 | if (!amap_lock_try(am)) { | | 1404 | if (!amap_lock_try(am)) { |
1325 | mutex_exit(&amap_list_lock); | | 1405 | (void)kpause("amapswpo", false, 1, &amap_list_lock); |
1326 | preempt(); | | | |
1327 | mutex_enter(&amap_list_lock); | | | |
1328 | am_next = LIST_NEXT(&marker_prev, am_list); | | 1406 | am_next = LIST_NEXT(&marker_prev, am_list); |
1329 | if (am_next == &marker_next) { | | 1407 | if (am_next == &marker_next) { |
1330 | am_next = LIST_NEXT(am_next, am_list); | | 1408 | am_next = LIST_NEXT(am_next, am_list); |
1331 | } else { | | 1409 | } else { |
1332 | KASSERT(LIST_NEXT(am_next, am_list) == | | 1410 | KASSERT(LIST_NEXT(am_next, am_list) == |
1333 | &marker_next); | | 1411 | &marker_next); |
1334 | } | | 1412 | } |
1335 | LIST_REMOVE(&marker_prev, am_list); | | 1413 | LIST_REMOVE(&marker_prev, am_list); |
1336 | LIST_REMOVE(&marker_next, am_list); | | 1414 | LIST_REMOVE(&marker_next, am_list); |
1337 | continue; | | 1415 | continue; |
1338 | } | | 1416 | } |
1339 | | | 1417 | |
1340 | mutex_exit(&amap_list_lock); | | 1418 | mutex_exit(&amap_list_lock); |
1341 | | | 1419 | |
1342 | if (am->am_nused <= 0) { | | 1420 | /* If am_nused == 0, the amap could be free - careful. */ |
1343 | amap_unlock(am); | | | |
1344 | goto next; | | | |
1345 | } | | | |
1346 | | | | |
1347 | for (i = 0; i < am->am_nused; i++) { | | 1421 | for (i = 0; i < am->am_nused; i++) { |
1348 | int slot; | | 1422 | int slot; |
1349 | int swslot; | | 1423 | int swslot; |
1350 | struct vm_anon *anon; | | 1424 | struct vm_anon *anon; |
1351 | | | 1425 | |
1352 | slot = am->am_slots[i]; | | 1426 | slot = am->am_slots[i]; |
1353 | anon = am->am_anon[slot]; | | 1427 | anon = am->am_anon[slot]; |
1354 | KASSERT(anon->an_lock == am->am_lock); | | 1428 | KASSERT(anon->an_lock == am->am_lock); |
1355 | | | 1429 | |
1356 | swslot = anon->an_swslot; | | 1430 | swslot = anon->an_swslot; |
1357 | if (swslot < startslot || endslot <= swslot) { | | 1431 | if (swslot < startslot || endslot <= swslot) { |
1358 | continue; | | 1432 | continue; |
1359 | } | | 1433 | } |
| @@ -1369,27 +1443,26 @@ amap_swap_off(int startslot, int endslot | | | @@ -1369,27 +1443,26 @@ amap_swap_off(int startslot, int endslot |
1369 | am = NULL; | | 1443 | am = NULL; |
1370 | break; | | 1444 | break; |
1371 | } | | 1445 | } |
1372 | if (rv) { | | 1446 | if (rv) { |
1373 | break; | | 1447 | break; |
1374 | } | | 1448 | } |
1375 | i = 0; | | 1449 | i = 0; |
1376 | } | | 1450 | } |
1377 | | | 1451 | |
1378 | if (am) { | | 1452 | if (am) { |
1379 | amap_unlock(am); | | 1453 | amap_unlock(am); |
1380 | } | | 1454 | } |
1381 | | | 1455 | |
1382 | next: | | | |
1383 | mutex_enter(&amap_list_lock); | | 1456 | mutex_enter(&amap_list_lock); |
1384 | KASSERT(LIST_NEXT(&marker_prev, am_list) == &marker_next || | | 1457 | KASSERT(LIST_NEXT(&marker_prev, am_list) == &marker_next || |
1385 | LIST_NEXT(LIST_NEXT(&marker_prev, am_list), am_list) == | | 1458 | LIST_NEXT(LIST_NEXT(&marker_prev, am_list), am_list) == |
1386 | &marker_next); | | 1459 | &marker_next); |
1387 | am_next = LIST_NEXT(&marker_next, am_list); | | 1460 | am_next = LIST_NEXT(&marker_next, am_list); |
1388 | LIST_REMOVE(&marker_prev, am_list); | | 1461 | LIST_REMOVE(&marker_prev, am_list); |
1389 | LIST_REMOVE(&marker_next, am_list); | | 1462 | LIST_REMOVE(&marker_next, am_list); |
1390 | } | | 1463 | } |
1391 | mutex_exit(&amap_list_lock); | | 1464 | mutex_exit(&amap_list_lock); |
1392 | | | 1465 | |
1393 | return rv; | | 1466 | return rv; |
1394 | } | | 1467 | } |
1395 | | | 1468 | |