1 /* $OpenBSD: uvm_amap.c,v 1.92 2023/04/11 00:45:09 jsg Exp $ */ 2 /* $NetBSD: uvm_amap.c,v 1.27 2000/11/25 06:27:59 chs Exp $ */ 3 4 /* 5 * Copyright (c) 1997 Charles D. Cranor and Washington University. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * uvm_amap.c: amap operations 31 * 32 * this file contains functions that perform operations on amaps. see 33 * uvm_amap.h for a brief explanation of the role of amaps in uvm. 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/malloc.h> 39 #include <sys/kernel.h> 40 #include <sys/pool.h> 41 #include <sys/atomic.h> 42 43 #include <uvm/uvm.h> 44 #include <uvm/uvm_swap.h> 45 46 /* 47 * pools for allocation of vm_amap structures. note that in order to 48 * avoid an endless loop, the amap pool's allocator cannot allocate 49 * memory from an amap (it currently goes through the kernel uobj, so 50 * we are ok). 51 */ 52 53 struct pool uvm_amap_pool; 54 struct pool uvm_small_amap_pool[UVM_AMAP_CHUNK]; 55 struct pool uvm_amap_chunk_pool; 56 57 LIST_HEAD(, vm_amap) amap_list; 58 struct rwlock amap_list_lock = RWLOCK_INITIALIZER("amaplstlk"); 59 #define amap_lock_list() rw_enter_write(&amap_list_lock) 60 #define amap_unlock_list() rw_exit_write(&amap_list_lock) 61 62 static char amap_small_pool_names[UVM_AMAP_CHUNK][9]; 63 64 /* 65 * local functions 66 */ 67 68 static struct vm_amap *amap_alloc1(int, int, int); 69 static inline void amap_list_insert(struct vm_amap *); 70 static inline void amap_list_remove(struct vm_amap *); 71 72 struct vm_amap_chunk *amap_chunk_get(struct vm_amap *, int, int, int); 73 void amap_chunk_free(struct vm_amap *, struct vm_amap_chunk *); 74 75 /* 76 * if we enable PPREF, then we have a couple of extra functions that 77 * we need to prototype here... 78 */ 79 80 #ifdef UVM_AMAP_PPREF 81 82 #define PPREF_NONE ((int *) -1) /* not using ppref */ 83 84 void amap_pp_adjref(struct vm_amap *, int, vsize_t, int); 85 void amap_pp_establish(struct vm_amap *); 86 void amap_wiperange_chunk(struct vm_amap *, struct vm_amap_chunk *, int, 87 int); 88 void amap_wiperange(struct vm_amap *, int, int); 89 90 #endif /* UVM_AMAP_PPREF */ 91 92 static inline void 93 amap_list_insert(struct vm_amap *amap) 94 { 95 amap_lock_list(); 96 LIST_INSERT_HEAD(&amap_list, amap, am_list); 97 amap_unlock_list(); 98 } 99 100 static inline void 101 amap_list_remove(struct vm_amap *amap) 102 { 103 amap_lock_list(); 104 LIST_REMOVE(amap, am_list); 105 amap_unlock_list(); 106 } 107 108 /* 109 * amap_chunk_get: lookup a chunk for slot. if create is non-zero, 110 * the chunk is created if it does not yet exist. 111 * 112 * => returns the chunk on success or NULL on error 113 */ 114 struct vm_amap_chunk * 115 amap_chunk_get(struct vm_amap *amap, int slot, int create, int waitf) 116 { 117 int bucket = UVM_AMAP_BUCKET(amap, slot); 118 int baseslot = AMAP_BASE_SLOT(slot); 119 int n; 120 struct vm_amap_chunk *chunk, *newchunk, *pchunk = NULL; 121 122 if (UVM_AMAP_SMALL(amap)) 123 return &amap->am_small; 124 125 for (chunk = amap->am_buckets[bucket]; chunk != NULL; 126 chunk = TAILQ_NEXT(chunk, ac_list)) { 127 if (UVM_AMAP_BUCKET(amap, chunk->ac_baseslot) != bucket) 128 break; 129 if (chunk->ac_baseslot == baseslot) 130 return chunk; 131 pchunk = chunk; 132 } 133 if (!create) 134 return NULL; 135 136 if (amap->am_nslot - baseslot >= UVM_AMAP_CHUNK) 137 n = UVM_AMAP_CHUNK; 138 else 139 n = amap->am_nslot - baseslot; 140 141 newchunk = pool_get(&uvm_amap_chunk_pool, waitf | PR_ZERO); 142 if (newchunk == NULL) 143 return NULL; 144 145 if (pchunk == NULL) { 146 TAILQ_INSERT_TAIL(&amap->am_chunks, newchunk, ac_list); 147 KASSERT(amap->am_buckets[bucket] == NULL); 148 amap->am_buckets[bucket] = newchunk; 149 } else 150 TAILQ_INSERT_AFTER(&amap->am_chunks, pchunk, newchunk, 151 ac_list); 152 153 amap->am_ncused++; 154 newchunk->ac_baseslot = baseslot; 155 newchunk->ac_nslot = n; 156 return newchunk; 157 } 158 159 void 160 amap_chunk_free(struct vm_amap *amap, struct vm_amap_chunk *chunk) 161 { 162 int bucket = UVM_AMAP_BUCKET(amap, chunk->ac_baseslot); 163 struct vm_amap_chunk *nchunk; 164 165 if (UVM_AMAP_SMALL(amap)) 166 return; 167 168 nchunk = TAILQ_NEXT(chunk, ac_list); 169 TAILQ_REMOVE(&amap->am_chunks, chunk, ac_list); 170 if (amap->am_buckets[bucket] == chunk) { 171 if (nchunk != NULL && 172 UVM_AMAP_BUCKET(amap, nchunk->ac_baseslot) == bucket) 173 amap->am_buckets[bucket] = nchunk; 174 else 175 amap->am_buckets[bucket] = NULL; 176 177 } 178 pool_put(&uvm_amap_chunk_pool, chunk); 179 amap->am_ncused--; 180 } 181 182 #ifdef UVM_AMAP_PPREF 183 /* 184 * what is ppref? ppref is an _optional_ amap feature which is used 185 * to keep track of reference counts on a per-page basis. it is enabled 186 * when UVM_AMAP_PPREF is defined. 187 * 188 * when enabled, an array of ints is allocated for the pprefs. this 189 * array is allocated only when a partial reference is added to the 190 * map (either by unmapping part of the amap, or gaining a reference 191 * to only a part of an amap). if the allocation of the array fails 192 * (M_NOWAIT), then we set the array pointer to PPREF_NONE to indicate 193 * that we tried to do ppref's but couldn't alloc the array so just 194 * give up (after all, this is an optional feature!). 195 * 196 * the array is divided into page sized "chunks." for chunks of length 1, 197 * the chunk reference count plus one is stored in that chunk's slot. 198 * for chunks of length > 1 the first slot contains (the reference count 199 * plus one) * -1. [the negative value indicates that the length is 200 * greater than one.] the second slot of the chunk contains the length 201 * of the chunk. here is an example: 202 * 203 * actual REFS: 2 2 2 2 3 1 1 0 0 0 4 4 0 1 1 1 204 * ppref: -3 4 x x 4 -2 2 -1 3 x -5 2 1 -2 3 x 205 * <----------><-><----><-------><----><-><-------> 206 * (x = don't care) 207 * 208 * this allows us to allow one int to contain the ref count for the whole 209 * chunk. note that the "plus one" part is needed because a reference 210 * count of zero is neither positive or negative (need a way to tell 211 * if we've got one zero or a bunch of them). 212 * 213 * here are some in-line functions to help us. 214 */ 215 216 /* 217 * pp_getreflen: get the reference and length for a specific offset 218 * 219 * => ppref's amap must be locked 220 */ 221 static inline void 222 pp_getreflen(int *ppref, int offset, int *refp, int *lenp) 223 { 224 225 if (ppref[offset] > 0) { /* chunk size must be 1 */ 226 *refp = ppref[offset] - 1; /* don't forget to adjust */ 227 *lenp = 1; 228 } else { 229 *refp = (ppref[offset] * -1) - 1; 230 *lenp = ppref[offset+1]; 231 } 232 } 233 234 /* 235 * pp_setreflen: set the reference and length for a specific offset 236 * 237 * => ppref's amap must be locked 238 */ 239 static inline void 240 pp_setreflen(int *ppref, int offset, int ref, int len) 241 { 242 if (len == 1) { 243 ppref[offset] = ref + 1; 244 } else { 245 ppref[offset] = (ref + 1) * -1; 246 ppref[offset+1] = len; 247 } 248 } 249 #endif /* UVM_AMAP_PPREF */ 250 251 /* 252 * amap_init: called at boot time to init global amap data structures 253 */ 254 255 void 256 amap_init(void) 257 { 258 int i; 259 size_t size; 260 261 /* Initialize the vm_amap pool. */ 262 pool_init(&uvm_amap_pool, sizeof(struct vm_amap), 263 0, IPL_MPFLOOR, PR_WAITOK, "amappl", NULL); 264 pool_sethiwat(&uvm_amap_pool, 4096); 265 266 /* initialize small amap pools */ 267 for (i = 0; i < nitems(uvm_small_amap_pool); i++) { 268 snprintf(amap_small_pool_names[i], 269 sizeof(amap_small_pool_names[0]), "amappl%d", i + 1); 270 size = offsetof(struct vm_amap, am_small.ac_anon) + 271 (i + 1) * sizeof(struct vm_anon *); 272 pool_init(&uvm_small_amap_pool[i], size, 0, IPL_MPFLOOR, 273 PR_WAITOK, amap_small_pool_names[i], NULL); 274 } 275 276 pool_init(&uvm_amap_chunk_pool, sizeof(struct vm_amap_chunk) + 277 UVM_AMAP_CHUNK * sizeof(struct vm_anon *), 278 0, IPL_MPFLOOR, PR_WAITOK, "amapchunkpl", NULL); 279 pool_sethiwat(&uvm_amap_chunk_pool, 4096); 280 } 281 282 /* 283 * amap_alloc1: allocate an amap, but do not initialise the overlay. 284 * 285 * => Note: lock is not set. 286 */ 287 static inline struct vm_amap * 288 amap_alloc1(int slots, int waitf, int lazyalloc) 289 { 290 struct vm_amap *amap; 291 struct vm_amap_chunk *chunk, *tmp; 292 int chunks, log_chunks, chunkperbucket = 1, hashshift = 0; 293 int buckets, i, n; 294 int pwaitf = (waitf & M_WAITOK) ? PR_WAITOK : PR_NOWAIT; 295 296 KASSERT(slots > 0); 297 298 /* 299 * Cast to unsigned so that rounding up cannot cause integer overflow 300 * if slots is large. 301 */ 302 chunks = roundup((unsigned int)slots, UVM_AMAP_CHUNK) / UVM_AMAP_CHUNK; 303 304 if (lazyalloc) { 305 /* 306 * Basically, the amap is a hash map where the number of 307 * buckets is fixed. We select the number of buckets using the 308 * following strategy: 309 * 310 * 1. The maximal number of entries to search in a bucket upon 311 * a collision should be less than or equal to 312 * log2(slots / UVM_AMAP_CHUNK). This is the worst-case number 313 * of lookups we would have if we could chunk the amap. The 314 * log2(n) comes from the fact that amaps are chunked by 315 * splitting up their vm_map_entries and organizing those 316 * in a binary search tree. 317 * 318 * 2. The maximal number of entries in a bucket must be a 319 * power of two. 320 * 321 * The maximal number of entries per bucket is used to hash 322 * a slot to a bucket. 323 * 324 * In the future, this strategy could be refined to make it 325 * even harder/impossible that the total amount of KVA needed 326 * for the hash buckets of all amaps to exceed the maximal 327 * amount of KVA memory reserved for amaps. 328 */ 329 for (log_chunks = 1; (chunks >> log_chunks) > 0; log_chunks++) 330 continue; 331 332 chunkperbucket = 1 << hashshift; 333 while (chunkperbucket + 1 < log_chunks) { 334 hashshift++; 335 chunkperbucket = 1 << hashshift; 336 } 337 } 338 339 if (slots > UVM_AMAP_CHUNK) 340 amap = pool_get(&uvm_amap_pool, pwaitf); 341 else 342 amap = pool_get(&uvm_small_amap_pool[slots - 1], 343 pwaitf | PR_ZERO); 344 if (amap == NULL) 345 return NULL; 346 347 amap->am_lock = NULL; 348 amap->am_ref = 1; 349 amap->am_flags = 0; 350 #ifdef UVM_AMAP_PPREF 351 amap->am_ppref = NULL; 352 #endif 353 amap->am_nslot = slots; 354 amap->am_nused = 0; 355 356 if (UVM_AMAP_SMALL(amap)) { 357 amap->am_small.ac_nslot = slots; 358 return amap; 359 } 360 361 amap->am_ncused = 0; 362 TAILQ_INIT(&amap->am_chunks); 363 amap->am_hashshift = hashshift; 364 amap->am_buckets = NULL; 365 366 buckets = howmany(chunks, chunkperbucket); 367 amap->am_buckets = mallocarray(buckets, sizeof(*amap->am_buckets), 368 M_UVMAMAP, waitf | (lazyalloc ? M_ZERO : 0)); 369 if (amap->am_buckets == NULL) 370 goto fail1; 371 amap->am_nbuckets = buckets; 372 373 if (!lazyalloc) { 374 for (i = 0; i < buckets; i++) { 375 if (i == buckets - 1) { 376 n = slots % UVM_AMAP_CHUNK; 377 if (n == 0) 378 n = UVM_AMAP_CHUNK; 379 } else 380 n = UVM_AMAP_CHUNK; 381 382 chunk = pool_get(&uvm_amap_chunk_pool, 383 PR_ZERO | pwaitf); 384 if (chunk == NULL) 385 goto fail1; 386 387 amap->am_buckets[i] = chunk; 388 amap->am_ncused++; 389 chunk->ac_baseslot = i * UVM_AMAP_CHUNK; 390 chunk->ac_nslot = n; 391 TAILQ_INSERT_TAIL(&amap->am_chunks, chunk, ac_list); 392 } 393 } 394 395 return amap; 396 397 fail1: 398 free(amap->am_buckets, M_UVMAMAP, buckets * sizeof(*amap->am_buckets)); 399 TAILQ_FOREACH_SAFE(chunk, &amap->am_chunks, ac_list, tmp) 400 pool_put(&uvm_amap_chunk_pool, chunk); 401 pool_put(&uvm_amap_pool, amap); 402 return NULL; 403 } 404 405 static void 406 amap_lock_alloc(struct vm_amap *amap) 407 { 408 rw_obj_alloc(&amap->am_lock, "amaplk"); 409 } 410 411 /* 412 * amap_alloc: allocate an amap to manage "sz" bytes of anonymous VM 413 * 414 * => caller should ensure sz is a multiple of PAGE_SIZE 415 * => reference count to new amap is set to one 416 * => new amap is returned unlocked 417 */ 418 struct vm_amap * 419 amap_alloc(vaddr_t sz, int waitf, int lazyalloc) 420 { 421 struct vm_amap *amap; 422 size_t slots; 423 424 AMAP_B2SLOT(slots, sz); /* load slots */ 425 if (slots > INT_MAX) 426 return NULL; 427 428 amap = amap_alloc1(slots, waitf, lazyalloc); 429 if (amap != NULL) { 430 amap_lock_alloc(amap); 431 amap_list_insert(amap); 432 } 433 434 return amap; 435 } 436 437 438 /* 439 * amap_free: free an amap 440 * 441 * => the amap must be unlocked 442 * => the amap should have a zero reference count and be empty 443 */ 444 void 445 amap_free(struct vm_amap *amap) 446 { 447 struct vm_amap_chunk *chunk, *tmp; 448 449 KASSERT(amap->am_ref == 0 && amap->am_nused == 0); 450 KASSERT((amap->am_flags & AMAP_SWAPOFF) == 0); 451 452 if (amap->am_lock != NULL) { 453 KASSERT(amap->am_lock == NULL || !rw_write_held(amap->am_lock)); 454 rw_obj_free(amap->am_lock); 455 } 456 457 #ifdef UVM_AMAP_PPREF 458 if (amap->am_ppref && amap->am_ppref != PPREF_NONE) 459 free(amap->am_ppref, M_UVMAMAP, amap->am_nslot * sizeof(int)); 460 #endif 461 462 if (UVM_AMAP_SMALL(amap)) 463 pool_put(&uvm_small_amap_pool[amap->am_nslot - 1], amap); 464 else { 465 TAILQ_FOREACH_SAFE(chunk, &amap->am_chunks, ac_list, tmp) 466 pool_put(&uvm_amap_chunk_pool, chunk); 467 free(amap->am_buckets, M_UVMAMAP, 468 amap->am_nbuckets * sizeof(*amap->am_buckets)); 469 pool_put(&uvm_amap_pool, amap); 470 } 471 } 472 473 /* 474 * amap_wipeout: wipeout all anon's in an amap; then free the amap! 475 * 476 * => Called from amap_unref(), when reference count drops to zero. 477 * => amap must be locked. 478 */ 479 void 480 amap_wipeout(struct vm_amap *amap) 481 { 482 int slot; 483 struct vm_anon *anon; 484 struct vm_amap_chunk *chunk; 485 struct pglist pgl; 486 487 KASSERT(rw_write_held(amap->am_lock)); 488 KASSERT(amap->am_ref == 0); 489 490 if (__predict_false((amap->am_flags & AMAP_SWAPOFF) != 0)) { 491 /* 492 * Note: amap_swap_off() will call us again. 493 */ 494 amap_unlock(amap); 495 return; 496 } 497 498 TAILQ_INIT(&pgl); 499 amap_list_remove(amap); 500 501 AMAP_CHUNK_FOREACH(chunk, amap) { 502 int i, refs, map = chunk->ac_usedmap; 503 504 for (i = ffs(map); i != 0; i = ffs(map)) { 505 slot = i - 1; 506 map ^= 1 << slot; 507 anon = chunk->ac_anon[slot]; 508 509 if (anon == NULL || anon->an_ref == 0) 510 panic("amap_wipeout: corrupt amap"); 511 KASSERT(anon->an_lock == amap->am_lock); 512 513 /* 514 * Drop the reference. 515 */ 516 refs = --anon->an_ref; 517 if (refs == 0) { 518 uvm_anfree_list(anon, &pgl); 519 } 520 } 521 } 522 /* free the pages */ 523 uvm_pglistfree(&pgl); 524 525 /* 526 * Finally, destroy the amap. 527 */ 528 amap->am_ref = 0; /* ... was one */ 529 amap->am_nused = 0; 530 amap_unlock(amap); 531 amap_free(amap); 532 } 533 534 /* 535 * amap_copy: ensure that a map entry's "needs_copy" flag is false 536 * by copying the amap if necessary. 537 * 538 * => an entry with a null amap pointer will get a new (blank) one. 539 * => the map that the map entry belongs to must be locked by caller. 540 * => the amap currently attached to "entry" (if any) must be unlocked. 541 * => if canchunk is true, then we may clip the entry into a chunk 542 * => "startva" and "endva" are used only if canchunk is true. they are 543 * used to limit chunking (e.g. if you have a large space that you 544 * know you are going to need to allocate amaps for, there is no point 545 * in allowing that to be chunked) 546 */ 547 548 void 549 amap_copy(struct vm_map *map, struct vm_map_entry *entry, int waitf, 550 boolean_t canchunk, vaddr_t startva, vaddr_t endva) 551 { 552 struct vm_amap *amap, *srcamap; 553 int slots, lcv, lazyalloc = 0; 554 vaddr_t chunksize; 555 int i, j, k, n, srcslot; 556 struct vm_amap_chunk *chunk = NULL, *srcchunk = NULL; 557 struct vm_anon *anon; 558 559 KASSERT(map != kernel_map); /* we use sleeping locks */ 560 561 /* 562 * Is there an amap to copy? If not, create one. 563 */ 564 if (entry->aref.ar_amap == NULL) { 565 /* 566 * Check to see if we have a large amap that we can 567 * chunk. We align startva/endva to chunk-sized 568 * boundaries and then clip to them. 569 * 570 * If we cannot chunk the amap, allocate it in a way 571 * that makes it grow or shrink dynamically with 572 * the number of slots. 573 */ 574 if (atop(entry->end - entry->start) >= UVM_AMAP_LARGE) { 575 if (canchunk) { 576 /* convert slots to bytes */ 577 chunksize = UVM_AMAP_CHUNK << PAGE_SHIFT; 578 startva = (startva / chunksize) * chunksize; 579 endva = roundup(endva, chunksize); 580 UVM_MAP_CLIP_START(map, entry, startva); 581 /* watch out for endva wrap-around! */ 582 if (endva >= startva) 583 UVM_MAP_CLIP_END(map, entry, endva); 584 } else 585 lazyalloc = 1; 586 } 587 588 entry->aref.ar_pageoff = 0; 589 entry->aref.ar_amap = amap_alloc(entry->end - entry->start, 590 waitf, lazyalloc); 591 if (entry->aref.ar_amap != NULL) 592 entry->etype &= ~UVM_ET_NEEDSCOPY; 593 return; 594 } 595 596 /* 597 * First check and see if we are the only map entry referencing 598 * he amap we currently have. If so, then just take it over instead 599 * of copying it. Note that we are reading am_ref without lock held 600 * as the value can only be one if we have the only reference 601 * to the amap (via our locked map). If the value is greater than 602 * one, then allocate amap and re-check the value. 603 */ 604 if (entry->aref.ar_amap->am_ref == 1) { 605 entry->etype &= ~UVM_ET_NEEDSCOPY; 606 return; 607 } 608 609 /* 610 * Allocate a new amap (note: not initialised, etc). 611 */ 612 AMAP_B2SLOT(slots, entry->end - entry->start); 613 if (!UVM_AMAP_SMALL(entry->aref.ar_amap) && 614 entry->aref.ar_amap->am_hashshift != 0) 615 lazyalloc = 1; 616 amap = amap_alloc1(slots, waitf, lazyalloc); 617 if (amap == NULL) 618 return; 619 srcamap = entry->aref.ar_amap; 620 621 /* 622 * Make the new amap share the source amap's lock, and then lock 623 * both. 624 */ 625 amap->am_lock = srcamap->am_lock; 626 rw_obj_hold(amap->am_lock); 627 628 amap_lock(srcamap); 629 630 /* 631 * Re-check the reference count with the lock held. If it has 632 * dropped to one - we can take over the existing map. 633 */ 634 if (srcamap->am_ref == 1) { 635 /* Just take over the existing amap. */ 636 entry->etype &= ~UVM_ET_NEEDSCOPY; 637 amap_unlock(srcamap); 638 /* Destroy the new (unused) amap. */ 639 amap->am_ref--; 640 amap_free(amap); 641 return; 642 } 643 644 /* 645 * Copy the slots. 646 */ 647 for (lcv = 0; lcv < slots; lcv += n) { 648 srcslot = entry->aref.ar_pageoff + lcv; 649 i = UVM_AMAP_SLOTIDX(lcv); 650 j = UVM_AMAP_SLOTIDX(srcslot); 651 n = UVM_AMAP_CHUNK; 652 if (i > j) 653 n -= i; 654 else 655 n -= j; 656 if (lcv + n > slots) 657 n = slots - lcv; 658 659 srcchunk = amap_chunk_get(srcamap, srcslot, 0, PR_NOWAIT); 660 if (srcchunk == NULL) 661 continue; 662 663 chunk = amap_chunk_get(amap, lcv, 1, PR_NOWAIT); 664 if (chunk == NULL) { 665 /* amap_wipeout() releases the lock. */ 666 amap->am_ref = 0; 667 amap_wipeout(amap); 668 return; 669 } 670 671 for (k = 0; k < n; i++, j++, k++) { 672 chunk->ac_anon[i] = anon = srcchunk->ac_anon[j]; 673 if (anon == NULL) 674 continue; 675 676 KASSERT(anon->an_lock == srcamap->am_lock); 677 KASSERT(anon->an_ref > 0); 678 chunk->ac_usedmap |= (1 << i); 679 anon->an_ref++; 680 amap->am_nused++; 681 } 682 } 683 684 /* 685 * Drop our reference to the old amap (srcamap) and unlock. 686 * Since the reference count on srcamap is greater than one, 687 * (we checked above), it cannot drop to zero while it is locked. 688 */ 689 srcamap->am_ref--; 690 KASSERT(srcamap->am_ref > 0); 691 692 if (srcamap->am_ref == 1 && (srcamap->am_flags & AMAP_SHARED) != 0) 693 srcamap->am_flags &= ~AMAP_SHARED; /* clear shared flag */ 694 #ifdef UVM_AMAP_PPREF 695 if (srcamap->am_ppref && srcamap->am_ppref != PPREF_NONE) { 696 amap_pp_adjref(srcamap, entry->aref.ar_pageoff, 697 (entry->end - entry->start) >> PAGE_SHIFT, -1); 698 } 699 #endif 700 701 /* 702 * If we referenced any anons, then share the source amap's lock. 703 * Otherwise, we have nothing in common, so allocate a new one. 704 */ 705 KASSERT(amap->am_lock == srcamap->am_lock); 706 if (amap->am_nused == 0) { 707 rw_obj_free(amap->am_lock); 708 amap->am_lock = NULL; 709 } 710 amap_unlock(srcamap); 711 712 if (amap->am_lock == NULL) 713 amap_lock_alloc(amap); 714 715 /* 716 * Install new amap. 717 */ 718 entry->aref.ar_pageoff = 0; 719 entry->aref.ar_amap = amap; 720 entry->etype &= ~UVM_ET_NEEDSCOPY; 721 722 amap_list_insert(amap); 723 } 724 725 /* 726 * amap_cow_now: resolve all copy-on-write faults in an amap now for fork(2) 727 * 728 * called during fork(2) when the parent process has a wired map 729 * entry. in that case we want to avoid write-protecting pages 730 * in the parent's map (e.g. like what you'd do for a COW page) 731 * so we resolve the COW here. 732 * 733 * => assume parent's entry was wired, thus all pages are resident. 734 * => the parent and child vm_map must both be locked. 735 * => caller passes child's map/entry in to us 736 * => XXXCDC: out of memory should cause fork to fail, but there is 737 * currently no easy way to do this (needs fix) 738 */ 739 740 void 741 amap_cow_now(struct vm_map *map, struct vm_map_entry *entry) 742 { 743 struct vm_amap *amap = entry->aref.ar_amap; 744 int slot; 745 struct vm_anon *anon, *nanon; 746 struct vm_page *pg, *npg; 747 struct vm_amap_chunk *chunk; 748 749 /* 750 * note that if we unlock the amap then we must ReStart the "lcv" for 751 * loop because some other process could reorder the anon's in the 752 * am_anon[] array on us while the lock is dropped. 753 */ 754 ReStart: 755 amap_lock(amap); 756 AMAP_CHUNK_FOREACH(chunk, amap) { 757 int i, map = chunk->ac_usedmap; 758 759 for (i = ffs(map); i != 0; i = ffs(map)) { 760 slot = i - 1; 761 map ^= 1 << slot; 762 anon = chunk->ac_anon[slot]; 763 pg = anon->an_page; 764 KASSERT(anon->an_lock == amap->am_lock); 765 766 /* 767 * The old page must be resident since the parent is 768 * wired. 769 */ 770 KASSERT(pg != NULL); 771 772 /* 773 * if the anon ref count is one, we are safe (the child 774 * has exclusive access to the page). 775 */ 776 if (anon->an_ref <= 1) 777 continue; 778 779 /* 780 * If the page is busy, then we have to unlock, wait for 781 * it and then restart. 782 */ 783 if (pg->pg_flags & PG_BUSY) { 784 uvm_pagewait(pg, amap->am_lock, "cownow"); 785 goto ReStart; 786 } 787 788 /* 789 * Perform a copy-on-write. 790 * First - get a new anon and a page. 791 */ 792 nanon = uvm_analloc(); 793 if (nanon != NULL) { 794 /* the new anon will share the amap's lock */ 795 nanon->an_lock = amap->am_lock; 796 npg = uvm_pagealloc(NULL, 0, nanon, 0); 797 } else 798 npg = NULL; /* XXX: quiet gcc warning */ 799 800 if (nanon == NULL || npg == NULL) { 801 /* out of memory */ 802 amap_unlock(amap); 803 if (nanon != NULL) { 804 nanon->an_lock = NULL; 805 nanon->an_ref--; 806 KASSERT(nanon->an_ref == 0); 807 uvm_anfree(nanon); 808 } 809 uvm_wait("cownowpage"); 810 goto ReStart; 811 } 812 813 /* 814 * Copy the data and replace anon with the new one. 815 * Also, setup its lock (share the with amap's lock). 816 */ 817 uvm_pagecopy(pg, npg); 818 anon->an_ref--; 819 KASSERT(anon->an_ref > 0); 820 chunk->ac_anon[slot] = nanon; 821 822 /* 823 * Drop PG_BUSY on new page. Since its owner was write 824 * locked all this time - it cannot be PG_RELEASED or 825 * PG_WANTED. 826 */ 827 atomic_clearbits_int(&npg->pg_flags, PG_BUSY|PG_FAKE); 828 UVM_PAGE_OWN(npg, NULL); 829 uvm_lock_pageq(); 830 uvm_pageactivate(npg); 831 uvm_unlock_pageq(); 832 } 833 } 834 amap_unlock(amap); 835 } 836 837 /* 838 * amap_splitref: split a single reference into two separate references 839 * 840 * => called from uvm_map's clip routines 841 * => origref's map should be locked 842 * => origref->ar_amap should be unlocked (we will lock) 843 */ 844 void 845 amap_splitref(struct vm_aref *origref, struct vm_aref *splitref, vaddr_t offset) 846 { 847 struct vm_amap *amap = origref->ar_amap; 848 int leftslots; 849 850 KASSERT(splitref->ar_amap == amap); 851 AMAP_B2SLOT(leftslots, offset); 852 if (leftslots == 0) 853 panic("amap_splitref: split at zero offset"); 854 855 amap_lock(amap); 856 857 if (amap->am_nslot - origref->ar_pageoff - leftslots <= 0) 858 panic("amap_splitref: map size check failed"); 859 860 #ifdef UVM_AMAP_PPREF 861 /* Establish ppref before we add a duplicate reference to the amap. */ 862 if (amap->am_ppref == NULL) 863 amap_pp_establish(amap); 864 #endif 865 866 /* Note: not a share reference. */ 867 amap->am_ref++; 868 splitref->ar_amap = amap; 869 splitref->ar_pageoff = origref->ar_pageoff + leftslots; 870 amap_unlock(amap); 871 } 872 873 #ifdef UVM_AMAP_PPREF 874 875 /* 876 * amap_pp_establish: add a ppref array to an amap, if possible. 877 * 878 * => amap should be locked by caller* => amap should be locked by caller 879 */ 880 void 881 amap_pp_establish(struct vm_amap *amap) 882 { 883 884 KASSERT(rw_write_held(amap->am_lock)); 885 amap->am_ppref = mallocarray(amap->am_nslot, sizeof(int), 886 M_UVMAMAP, M_NOWAIT|M_ZERO); 887 888 if (amap->am_ppref == NULL) { 889 /* Failure - just do not use ppref. */ 890 amap->am_ppref = PPREF_NONE; 891 return; 892 } 893 894 pp_setreflen(amap->am_ppref, 0, amap->am_ref, amap->am_nslot); 895 } 896 897 /* 898 * amap_pp_adjref: adjust reference count to a part of an amap using the 899 * per-page reference count array. 900 * 901 * => caller must check that ppref != PPREF_NONE before calling. 902 * => map and amap must be locked. 903 */ 904 void 905 amap_pp_adjref(struct vm_amap *amap, int curslot, vsize_t slotlen, int adjval) 906 { 907 int stopslot, *ppref, lcv, prevlcv; 908 int ref, len, prevref, prevlen; 909 910 KASSERT(rw_write_held(amap->am_lock)); 911 912 stopslot = curslot + slotlen; 913 ppref = amap->am_ppref; 914 prevlcv = 0; 915 916 /* 917 * Advance to the correct place in the array, fragment if needed. 918 */ 919 for (lcv = 0 ; lcv < curslot ; lcv += len) { 920 pp_getreflen(ppref, lcv, &ref, &len); 921 if (lcv + len > curslot) { /* goes past start? */ 922 pp_setreflen(ppref, lcv, ref, curslot - lcv); 923 pp_setreflen(ppref, curslot, ref, len - (curslot -lcv)); 924 len = curslot - lcv; /* new length of entry @ lcv */ 925 } 926 prevlcv = lcv; 927 } 928 if (lcv != 0) 929 pp_getreflen(ppref, prevlcv, &prevref, &prevlen); 930 else { 931 /* 932 * Ensure that the "prevref == ref" test below always 933 * fails, since we are starting from the beginning of 934 * the ppref array; that is, there is no previous chunk. 935 */ 936 prevref = -1; 937 prevlen = 0; 938 } 939 940 /* 941 * Now adjust reference counts in range. Merge the first 942 * changed entry with the last unchanged entry if possible. 943 */ 944 if (lcv != curslot) 945 panic("amap_pp_adjref: overshot target"); 946 947 for (/* lcv already set */; lcv < stopslot ; lcv += len) { 948 pp_getreflen(ppref, lcv, &ref, &len); 949 if (lcv + len > stopslot) { /* goes past end? */ 950 pp_setreflen(ppref, lcv, ref, stopslot - lcv); 951 pp_setreflen(ppref, stopslot, ref, 952 len - (stopslot - lcv)); 953 len = stopslot - lcv; 954 } 955 ref += adjval; 956 if (ref < 0) 957 panic("amap_pp_adjref: negative reference count"); 958 if (lcv == prevlcv + prevlen && ref == prevref) { 959 pp_setreflen(ppref, prevlcv, ref, prevlen + len); 960 } else { 961 pp_setreflen(ppref, lcv, ref, len); 962 } 963 if (ref == 0) 964 amap_wiperange(amap, lcv, len); 965 } 966 967 } 968 969 void 970 amap_wiperange_chunk(struct vm_amap *amap, struct vm_amap_chunk *chunk, 971 int slotoff, int slots) 972 { 973 int curslot, i, map; 974 int startbase, endbase; 975 struct vm_anon *anon; 976 977 startbase = AMAP_BASE_SLOT(slotoff); 978 endbase = AMAP_BASE_SLOT(slotoff + slots - 1); 979 980 map = chunk->ac_usedmap; 981 if (startbase == chunk->ac_baseslot) 982 map &= ~((1 << (slotoff - startbase)) - 1); 983 if (endbase == chunk->ac_baseslot) 984 map &= (1 << (slotoff + slots - endbase)) - 1; 985 986 for (i = ffs(map); i != 0; i = ffs(map)) { 987 int refs; 988 989 curslot = i - 1; 990 map ^= 1 << curslot; 991 chunk->ac_usedmap ^= 1 << curslot; 992 anon = chunk->ac_anon[curslot]; 993 KASSERT(anon->an_lock == amap->am_lock); 994 995 /* remove it from the amap */ 996 chunk->ac_anon[curslot] = NULL; 997 998 amap->am_nused--; 999 1000 /* drop anon reference count */ 1001 refs = --anon->an_ref; 1002 if (refs == 0) { 1003 uvm_anfree(anon); 1004 } 1005 1006 /* 1007 * done with this anon, next ...! 1008 */ 1009 1010 } /* end of 'for' loop */ 1011 } 1012 1013 /* 1014 * amap_wiperange: wipe out a range of an amap. 1015 * Note: different from amap_wipeout because the amap is kept intact. 1016 * 1017 * => Both map and amap must be locked by caller. 1018 */ 1019 void 1020 amap_wiperange(struct vm_amap *amap, int slotoff, int slots) 1021 { 1022 int bucket, startbucket, endbucket; 1023 struct vm_amap_chunk *chunk, *nchunk; 1024 1025 KASSERT(rw_write_held(amap->am_lock)); 1026 1027 startbucket = UVM_AMAP_BUCKET(amap, slotoff); 1028 endbucket = UVM_AMAP_BUCKET(amap, slotoff + slots - 1); 1029 1030 /* 1031 * We can either traverse the amap by am_chunks or by am_buckets. 1032 * Determine which way is less expensive. 1033 */ 1034 if (UVM_AMAP_SMALL(amap)) 1035 amap_wiperange_chunk(amap, &amap->am_small, slotoff, slots); 1036 else if (endbucket + 1 - startbucket >= amap->am_ncused) { 1037 TAILQ_FOREACH_SAFE(chunk, &amap->am_chunks, ac_list, nchunk) { 1038 if (chunk->ac_baseslot + chunk->ac_nslot <= slotoff) 1039 continue; 1040 if (chunk->ac_baseslot >= slotoff + slots) 1041 continue; 1042 1043 amap_wiperange_chunk(amap, chunk, slotoff, slots); 1044 if (chunk->ac_usedmap == 0) 1045 amap_chunk_free(amap, chunk); 1046 } 1047 } else { 1048 for (bucket = startbucket; bucket <= endbucket; bucket++) { 1049 for (chunk = amap->am_buckets[bucket]; chunk != NULL; 1050 chunk = nchunk) { 1051 nchunk = TAILQ_NEXT(chunk, ac_list); 1052 1053 if (UVM_AMAP_BUCKET(amap, chunk->ac_baseslot) != 1054 bucket) 1055 break; 1056 if (chunk->ac_baseslot + chunk->ac_nslot <= 1057 slotoff) 1058 continue; 1059 if (chunk->ac_baseslot >= slotoff + slots) 1060 continue; 1061 1062 amap_wiperange_chunk(amap, chunk, slotoff, 1063 slots); 1064 if (chunk->ac_usedmap == 0) 1065 amap_chunk_free(amap, chunk); 1066 } 1067 } 1068 } 1069 } 1070 1071 #endif 1072 1073 /* 1074 * amap_swap_off: pagein anonymous pages in amaps and drop swap slots. 1075 * 1076 * => note that we don't always traverse all anons. 1077 * eg. amaps being wiped out, released anons. 1078 * => return TRUE if failed. 1079 */ 1080 1081 boolean_t 1082 amap_swap_off(int startslot, int endslot) 1083 { 1084 struct vm_amap *am; 1085 struct vm_amap *am_next; 1086 struct vm_amap marker; 1087 boolean_t rv = FALSE; 1088 1089 amap_lock_list(); 1090 for (am = LIST_FIRST(&amap_list); am != NULL && !rv; am = am_next) { 1091 int i, map; 1092 struct vm_amap_chunk *chunk; 1093 1094 amap_lock(am); 1095 if (am->am_nused == 0) { 1096 amap_unlock(am); 1097 am_next = LIST_NEXT(am, am_list); 1098 continue; 1099 } 1100 1101 LIST_INSERT_AFTER(am, &marker, am_list); 1102 amap_unlock_list(); 1103 1104 again: 1105 AMAP_CHUNK_FOREACH(chunk, am) { 1106 map = chunk->ac_usedmap; 1107 1108 for (i = ffs(map); i != 0; i = ffs(map)) { 1109 int swslot; 1110 int slot = i - 1; 1111 struct vm_anon *anon; 1112 1113 map ^= 1 << slot; 1114 anon = chunk->ac_anon[slot]; 1115 1116 swslot = anon->an_swslot; 1117 if (swslot < startslot || endslot <= swslot) { 1118 continue; 1119 } 1120 1121 am->am_flags |= AMAP_SWAPOFF; 1122 1123 rv = uvm_anon_pagein(am, anon); 1124 amap_lock(am); 1125 1126 am->am_flags &= ~AMAP_SWAPOFF; 1127 if (amap_refs(am) == 0) { 1128 amap_wipeout(am); 1129 am = NULL; 1130 goto nextamap; 1131 } 1132 if (rv) 1133 goto nextamap; 1134 goto again; 1135 } 1136 } 1137 nextamap: 1138 if (am != NULL) 1139 amap_unlock(am); 1140 amap_lock_list(); 1141 am_next = LIST_NEXT(&marker, am_list); 1142 LIST_REMOVE(&marker, am_list); 1143 } 1144 amap_unlock_list(); 1145 1146 return rv; 1147 } 1148 1149 /* 1150 * amap_lookup: look up a page in an amap. 1151 * 1152 * => amap should be locked by caller. 1153 */ 1154 struct vm_anon * 1155 amap_lookup(struct vm_aref *aref, vaddr_t offset) 1156 { 1157 int slot; 1158 struct vm_amap *amap = aref->ar_amap; 1159 struct vm_amap_chunk *chunk; 1160 1161 AMAP_B2SLOT(slot, offset); 1162 slot += aref->ar_pageoff; 1163 KASSERT(slot < amap->am_nslot); 1164 1165 chunk = amap_chunk_get(amap, slot, 0, PR_NOWAIT); 1166 if (chunk == NULL) 1167 return NULL; 1168 1169 return chunk->ac_anon[UVM_AMAP_SLOTIDX(slot)]; 1170 } 1171 1172 /* 1173 * amap_lookups: look up a range of pages in an amap. 1174 * 1175 * => amap should be locked by caller. 1176 * => XXXCDC: this interface is biased toward array-based amaps. fix. 1177 */ 1178 void 1179 amap_lookups(struct vm_aref *aref, vaddr_t offset, 1180 struct vm_anon **anons, int npages) 1181 { 1182 int i, lcv, n, slot; 1183 struct vm_amap *amap = aref->ar_amap; 1184 struct vm_amap_chunk *chunk = NULL; 1185 1186 AMAP_B2SLOT(slot, offset); 1187 slot += aref->ar_pageoff; 1188 1189 KASSERT((slot + (npages - 1)) < amap->am_nslot); 1190 1191 for (i = 0, lcv = slot; lcv < slot + npages; i += n, lcv += n) { 1192 n = UVM_AMAP_CHUNK - UVM_AMAP_SLOTIDX(lcv); 1193 if (lcv + n > slot + npages) 1194 n = slot + npages - lcv; 1195 1196 chunk = amap_chunk_get(amap, lcv, 0, PR_NOWAIT); 1197 if (chunk == NULL) 1198 memset(&anons[i], 0, n * sizeof(*anons)); 1199 else 1200 memcpy(&anons[i], 1201 &chunk->ac_anon[UVM_AMAP_SLOTIDX(lcv)], 1202 n * sizeof(*anons)); 1203 } 1204 } 1205 1206 /* 1207 * amap_populate: ensure that the amap can store an anon for the page at 1208 * offset. This function can sleep until memory to store the anon is 1209 * available. 1210 */ 1211 void 1212 amap_populate(struct vm_aref *aref, vaddr_t offset) 1213 { 1214 int slot; 1215 struct vm_amap *amap = aref->ar_amap; 1216 struct vm_amap_chunk *chunk; 1217 1218 AMAP_B2SLOT(slot, offset); 1219 slot += aref->ar_pageoff; 1220 KASSERT(slot < amap->am_nslot); 1221 1222 chunk = amap_chunk_get(amap, slot, 1, PR_WAITOK); 1223 KASSERT(chunk != NULL); 1224 } 1225 1226 /* 1227 * amap_add: add (or replace) a page to an amap. 1228 * 1229 * => amap should be locked by caller. 1230 * => anon must have the lock associated with this amap. 1231 */ 1232 int 1233 amap_add(struct vm_aref *aref, vaddr_t offset, struct vm_anon *anon, 1234 boolean_t replace) 1235 { 1236 int slot; 1237 struct vm_amap *amap = aref->ar_amap; 1238 struct vm_amap_chunk *chunk; 1239 1240 AMAP_B2SLOT(slot, offset); 1241 slot += aref->ar_pageoff; 1242 KASSERT(slot < amap->am_nslot); 1243 1244 chunk = amap_chunk_get(amap, slot, 1, PR_NOWAIT); 1245 if (chunk == NULL) 1246 return 1; 1247 1248 slot = UVM_AMAP_SLOTIDX(slot); 1249 if (replace) { 1250 struct vm_anon *oanon = chunk->ac_anon[slot]; 1251 1252 KASSERT(oanon != NULL); 1253 if (oanon->an_page && (amap->am_flags & AMAP_SHARED) != 0) { 1254 pmap_page_protect(oanon->an_page, PROT_NONE); 1255 /* 1256 * XXX: suppose page is supposed to be wired somewhere? 1257 */ 1258 } 1259 } else { /* !replace */ 1260 if (chunk->ac_anon[slot] != NULL) 1261 panic("amap_add: slot in use"); 1262 1263 chunk->ac_usedmap |= 1 << slot; 1264 amap->am_nused++; 1265 } 1266 chunk->ac_anon[slot] = anon; 1267 1268 return 0; 1269 } 1270 1271 /* 1272 * amap_unadd: remove a page from an amap. 1273 * 1274 * => amap should be locked by caller. 1275 */ 1276 void 1277 amap_unadd(struct vm_aref *aref, vaddr_t offset) 1278 { 1279 struct vm_amap *amap = aref->ar_amap; 1280 struct vm_amap_chunk *chunk; 1281 int slot; 1282 1283 KASSERT(rw_write_held(amap->am_lock)); 1284 1285 AMAP_B2SLOT(slot, offset); 1286 slot += aref->ar_pageoff; 1287 KASSERT(slot < amap->am_nslot); 1288 chunk = amap_chunk_get(amap, slot, 0, PR_NOWAIT); 1289 KASSERT(chunk != NULL); 1290 1291 slot = UVM_AMAP_SLOTIDX(slot); 1292 KASSERT(chunk->ac_anon[slot] != NULL); 1293 1294 chunk->ac_anon[slot] = NULL; 1295 chunk->ac_usedmap &= ~(1 << slot); 1296 amap->am_nused--; 1297 1298 if (chunk->ac_usedmap == 0) 1299 amap_chunk_free(amap, chunk); 1300 } 1301 1302 /* 1303 * amap_adjref_anons: adjust the reference count(s) on amap and its anons. 1304 */ 1305 static void 1306 amap_adjref_anons(struct vm_amap *amap, vaddr_t offset, vsize_t len, 1307 int refv, boolean_t all) 1308 { 1309 #ifdef UVM_AMAP_PPREF 1310 KASSERT(rw_write_held(amap->am_lock)); 1311 1312 /* 1313 * We must establish the ppref array before changing am_ref 1314 * so that the ppref values match the current amap refcount. 1315 */ 1316 if (amap->am_ppref == NULL && !all && len != amap->am_nslot) { 1317 amap_pp_establish(amap); 1318 } 1319 #endif 1320 1321 amap->am_ref += refv; 1322 1323 #ifdef UVM_AMAP_PPREF 1324 if (amap->am_ppref && amap->am_ppref != PPREF_NONE) { 1325 if (all) { 1326 amap_pp_adjref(amap, 0, amap->am_nslot, refv); 1327 } else { 1328 amap_pp_adjref(amap, offset, len, refv); 1329 } 1330 } 1331 #endif 1332 amap_unlock(amap); 1333 } 1334 1335 /* 1336 * amap_ref: gain a reference to an amap. 1337 * 1338 * => amap must not be locked (we will lock). 1339 * => "offset" and "len" are in units of pages. 1340 * => Called at fork time to gain the child's reference. 1341 */ 1342 void 1343 amap_ref(struct vm_amap *amap, vaddr_t offset, vsize_t len, int flags) 1344 { 1345 amap_lock(amap); 1346 if (flags & AMAP_SHARED) 1347 amap->am_flags |= AMAP_SHARED; 1348 amap_adjref_anons(amap, offset, len, 1, (flags & AMAP_REFALL) != 0); 1349 } 1350 1351 /* 1352 * amap_unref: remove a reference to an amap. 1353 * 1354 * => All pmap-level references to this amap must be already removed. 1355 * => Called from uvm_unmap_detach(); entry is already removed from the map. 1356 * => We will lock amap, so it must be unlocked. 1357 */ 1358 void 1359 amap_unref(struct vm_amap *amap, vaddr_t offset, vsize_t len, boolean_t all) 1360 { 1361 amap_lock(amap); 1362 1363 KASSERT(amap->am_ref > 0); 1364 1365 if (amap->am_ref == 1) { 1366 /* 1367 * If the last reference - wipeout and destroy the amap. 1368 */ 1369 amap->am_ref--; 1370 amap_wipeout(amap); 1371 return; 1372 } 1373 1374 /* 1375 * Otherwise, drop the reference count(s) on anons. 1376 */ 1377 if (amap->am_ref == 2 && (amap->am_flags & AMAP_SHARED) != 0) { 1378 amap->am_flags &= ~AMAP_SHARED; 1379 } 1380 amap_adjref_anons(amap, offset, len, -1, all); 1381 } 1382