Wed Jan 1 22:01:14 2020 UTC ()
- Start trying to reduce the high cache miss rate observed around vm_amap.
  On _LP64, pad struct vm_amap to 128 bytes and use the additional space to
  hold the arrays for tiny amaps which are common.  Carefully size the array
  allocations to avoid false sharing, and for smaller amaps try to share
  allocated cache lines.

- Eliminate most contention due to amap_list: maintain the list in the pool
  cache constructor / destructor like we do for struct file.  Cache the
  mutexes we allocate here.

- Don't do PR_WAITOK mutex allocations when NOWAIT has been specified.


(ad)
diff -r1.112 -r1.113 src/sys/uvm/uvm_amap.c
diff -r1.37 -r1.38 src/sys/uvm/uvm_amap.h

cvs diff -r1.112 -r1.113 src/sys/uvm/uvm_amap.c (expand / switch to unified diff)

--- src/sys/uvm/uvm_amap.c 2020/01/01 13:11:51 1.112
+++ src/sys/uvm/uvm_amap.c 2020/01/01 22:01:13 1.113
@@ -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 */
58static struct pool_cache uvm_amap_cache; 58static struct pool_cache uvm_amap_cache;
59static kmutex_t amap_list_lock __cacheline_aligned; 59static kmutex_t amap_list_lock __cacheline_aligned;
60static LIST_HEAD(, vm_amap) amap_list; 60static LIST_HEAD(, vm_amap) amap_list;
61 61
62/* 62/*
63 * local functions 63 * local functions
64 */ 64 */
65 65
66static inline void 
67amap_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 
75static inline void 
76amap_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 
84static int 66static int
85amap_roundup_slots(int slots) 67amap_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 */
167static struct vm_amap * 156static struct vm_amap *
168amap_alloc1(int slots, int padslots, int flags) 157amap_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
209fail3: 
210 kmem_free(amap->am_bckptr, totalslots * sizeof(int)); 
211fail2: 233fail2:
212 kmem_free(amap->am_slots, totalslots * sizeof(int)); 234 kmem_free(amap->am_slots, amap->am_maxslot * sizeof(int));
213fail1: 235fail1:
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 *
238amap_alloc(vaddr_t sz, vaddr_t padsz, int waitf) 260amap_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 */
 285static int
 286amap_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 */
 312static void
 313amap_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 */
263void 328void
264uvm_amap_init(void) 329uvm_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 */
279void 353void
280amap_free(struct vm_amap *amap) 354amap_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
763void 842void
764amap_copy(struct vm_map *map, struct vm_map_entry *entry, int flags, 843amap_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 */
1120void 1198void
1121amap_pp_establish(struct vm_amap *amap, vaddr_t offset) 1199amap_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
1382next: 
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

cvs diff -r1.37 -r1.38 src/sys/uvm/uvm_amap.h (expand / switch to unified diff)

--- src/sys/uvm/uvm_amap.h 2011/06/12 03:36:02 1.37
+++ src/sys/uvm/uvm_amap.h 2020/01/01 22:01:13 1.38
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: uvm_amap.h,v 1.37 2011/06/12 03:36:02 rmind Exp $ */ 1/* $NetBSD: uvm_amap.h,v 1.38 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.
@@ -137,43 +137,65 @@ bool amap_swap_off @@ -137,43 +137,65 @@ bool amap_swap_off
137 * part 2: amap implementation-specific info 137 * part 2: amap implementation-specific info
138 */ 138 */
139 139
140/* 140/*
141 * we currently provide an array-based amap implementation. in this 141 * we currently provide an array-based amap implementation. in this
142 * implementation we provide the option of tracking split references 142 * implementation we provide the option of tracking split references
143 * so that we don't lose track of references during partial unmaps 143 * so that we don't lose track of references during partial unmaps
144 * ... this is enabled with the "UVM_AMAP_PPREF" define. 144 * ... this is enabled with the "UVM_AMAP_PPREF" define.
145 */ 145 */
146 146
147#define UVM_AMAP_PPREF /* track partial references */ 147#define UVM_AMAP_PPREF /* track partial references */
148 148
149/* 149/*
 150 * for amaps with fewer than UVM_AMAP_TINY slots, we allocate storage
 151 * directly in vm_amap. this should reduce pressure on the allocator and on
 152 * the CPU cache. on _LP64, the chosen value of 3 sizes the structure at
 153 * 128 bytes, a multiple of the typical cache line size, which helps us to
 154 * avoid false sharing on MULTIPROCESSOR.
 155 *
 156 * for amaps with fewer than UVM_AMAP_SMALL slots, anons are stored directly
 157 * in the vm_amap but slots and backpointers are externally allocated.
 158 */
 159
 160#define UVM_AMAP_TINY 3 /* # of slots in "tiny" amap */
 161#ifdef _LP64
 162#define UVM_AMAP_SMALL 3*2 /* # of slots if 1/2 external allocation */
 163#else
 164#define UVM_AMAP_SMALL 3*3 /* # of slots in 1/2 external allocation */
 165#endif
 166
 167#define AMAP_TINY_ANON(am) ((struct vm_anon **)&(am)->am_storage[0])
 168#define AMAP_TINY_SLOTS(am) ((int *)&((am)->am_storage[UVM_AMAP_TINY]))
 169
 170/*
150 * here is the definition of the vm_amap structure for this implementation. 171 * here is the definition of the vm_amap structure for this implementation.
151 */ 172 */
152 173
153struct vm_amap { 174struct vm_amap {
154 kmutex_t *am_lock; /* lock [locks all vm_amap fields] */ 175 kmutex_t *am_lock; /* lock [locks all vm_amap fields] */
155 int am_ref; /* reference count */ 176 int am_ref; /* reference count */
156 int am_flags; /* flags */ 177 int am_flags; /* flags */
157 int am_maxslot; /* max # of slots allocated */ 178 int am_maxslot; /* max # of slots allocated */
158 int am_nslot; /* # of slots currently in map ( <= maxslot) */ 179 int am_nslot; /* # of slots currently in map ( <= maxslot) */
159 int am_nused; /* # of slots currently in use */ 180 int am_nused; /* # of slots currently in use */
160 int *am_slots; /* contig array of active slots */ 181 int *am_slots; /* contig array of active slots */
161 int *am_bckptr; /* back pointer array to am_slots */ 182 int *am_bckptr; /* back pointer array to am_slots */
162 struct vm_anon **am_anon; /* array of anonymous pages */ 183 struct vm_anon **am_anon; /* array of anonymous pages */
163#ifdef UVM_AMAP_PPREF 184#ifdef UVM_AMAP_PPREF
164 int *am_ppref; /* per page reference count (if !NULL) */ 185 int *am_ppref; /* per page reference count (if !NULL) */
165#endif 186#endif
166 LIST_ENTRY(vm_amap) am_list; 187 LIST_ENTRY(vm_amap) am_list;
 188 uintptr_t am_storage[UVM_AMAP_SMALL];
167}; 189};
168 190
169/* 191/*
170 * note that am_slots, am_bckptr, and am_anon are arrays. this allows 192 * note that am_slots, am_bckptr, and am_anon are arrays. this allows
171 * fast lookup of pages based on their virual address at the expense of 193 * fast lookup of pages based on their virual address at the expense of
172 * some extra memory. in the future we should be smarter about memory 194 * some extra memory. in the future we should be smarter about memory
173 * usage and fall back to a non-array based implementation on systems 195 * usage and fall back to a non-array based implementation on systems
174 * that are short of memory (XXXCDC). 196 * that are short of memory (XXXCDC).
175 * 197 *
176 * the entries in the array are called slots... for example an amap that 198 * the entries in the array are called slots... for example an amap that
177 * covers four pages of virtual memory is said to have four slots. here 199 * covers four pages of virtual memory is said to have four slots. here
178 * is an example of the array usage for a four slot amap. note that only 200 * is an example of the array usage for a four slot amap. note that only
179 * slots one and three have anons assigned to them. "D/C" means that we 201 * slots one and three have anons assigned to them. "D/C" means that we