The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/uvm/uvm_amap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: uvm_amap.c,v 1.91 2022/08/01 14:15:46 mpi 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 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 }

Cache object: 5fae8415b92f12af57467b30fac74f64


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.