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 /*      $NetBSD: uvm_amap.c,v 1.53.2.2 2006/01/27 22:21:01 tron Exp $   */
    2 
    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  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by Charles D. Cranor and
   19  *      Washington University.
   20  * 4. The name of the author may not be used to endorse or promote products
   21  *    derived from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 /*
   36  * uvm_amap.c: amap operations
   37  */
   38 
   39 /*
   40  * this file contains functions that perform operations on amaps.  see
   41  * uvm_amap.h for a brief explanation of the role of amaps in uvm.
   42  */
   43 
   44 #include <sys/cdefs.h>
   45 __KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v 1.53.2.2 2006/01/27 22:21:01 tron Exp $");
   46 
   47 #undef UVM_AMAP_INLINE          /* enable/disable amap inlines */
   48 
   49 #include "opt_uvmhist.h"
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/proc.h>
   54 #include <sys/malloc.h>
   55 #include <sys/kernel.h>
   56 #include <sys/pool.h>
   57 
   58 #define UVM_AMAP_C              /* ensure disabled inlines are in */
   59 #include <uvm/uvm.h>
   60 #include <uvm/uvm_swap.h>
   61 
   62 /*
   63  * pool for allocation of vm_map structures.  note that the pool has
   64  * its own simplelock for its protection.  also note that in order to
   65  * avoid an endless loop, the amap pool's allocator cannot allocate
   66  * memory from an amap (it currently goes through the kernel uobj, so
   67  * we are ok).
   68  */
   69 
   70 struct pool uvm_amap_pool;
   71 
   72 MALLOC_DEFINE(M_UVMAMAP, "UVM amap", "UVM amap and related structures");
   73 
   74 /*
   75  * local functions
   76  */
   77 
   78 static struct vm_amap *amap_alloc1(int, int, int);
   79 
   80 #ifdef UVM_AMAP_PPREF
   81 /*
   82  * what is ppref?   ppref is an _optional_ amap feature which is used
   83  * to keep track of reference counts on a per-page basis.  it is enabled
   84  * when UVM_AMAP_PPREF is defined.
   85  *
   86  * when enabled, an array of ints is allocated for the pprefs.  this
   87  * array is allocated only when a partial reference is added to the
   88  * map (either by unmapping part of the amap, or gaining a reference
   89  * to only a part of an amap).  if the malloc of the array fails
   90  * (M_NOWAIT), then we set the array pointer to PPREF_NONE to indicate
   91  * that we tried to do ppref's but couldn't alloc the array so just
   92  * give up (after all, this is an optional feature!).
   93  *
   94  * the array is divided into page sized "chunks."   for chunks of length 1,
   95  * the chunk reference count plus one is stored in that chunk's slot.
   96  * for chunks of length > 1 the first slot contains (the reference count
   97  * plus one) * -1.    [the negative value indicates that the length is
   98  * greater than one.]   the second slot of the chunk contains the length
   99  * of the chunk.   here is an example:
  100  *
  101  * actual REFS:  2  2  2  2  3  1  1  0  0  0  4  4  0  1  1  1
  102  *       ppref: -3  4  x  x  4 -2  2 -1  3  x -5  2  1 -2  3  x
  103  *              <----------><-><----><-------><----><-><------->
  104  * (x = don't care)
  105  *
  106  * this allows us to allow one int to contain the ref count for the whole
  107  * chunk.    note that the "plus one" part is needed because a reference
  108  * count of zero is neither positive or negative (need a way to tell
  109  * if we've got one zero or a bunch of them).
  110  *
  111  * here are some in-line functions to help us.
  112  */
  113 
  114 static __inline void pp_getreflen(int *, int, int *, int *);
  115 static __inline void pp_setreflen(int *, int, int, int);
  116 
  117 /*
  118  * pp_getreflen: get the reference and length for a specific offset
  119  *
  120  * => ppref's amap must be locked
  121  */
  122 static __inline void
  123 pp_getreflen(ppref, offset, refp, lenp)
  124         int *ppref, offset, *refp, *lenp;
  125 {
  126 
  127         if (ppref[offset] > 0) {                /* chunk size must be 1 */
  128                 *refp = ppref[offset] - 1;      /* don't forget to adjust */
  129                 *lenp = 1;
  130         } else {
  131                 *refp = (ppref[offset] * -1) - 1;
  132                 *lenp = ppref[offset+1];
  133         }
  134 }
  135 
  136 /*
  137  * pp_setreflen: set the reference and length for a specific offset
  138  *
  139  * => ppref's amap must be locked
  140  */
  141 static __inline void
  142 pp_setreflen(ppref, offset, ref, len)
  143         int *ppref, offset, ref, len;
  144 {
  145         if (len == 0)
  146                 return;
  147         if (len == 1) {
  148                 ppref[offset] = ref + 1;
  149         } else {
  150                 ppref[offset] = (ref + 1) * -1;
  151                 ppref[offset+1] = len;
  152         }
  153 }
  154 #endif
  155 
  156 /*
  157  * amap_init: called at boot time to init global amap data structures
  158  */
  159 
  160 void
  161 amap_init(void)
  162 {
  163 
  164         /*
  165          * Initialize the vm_amap pool.
  166          */
  167 
  168         pool_init(&uvm_amap_pool, sizeof(struct vm_amap), 0, 0, 0,
  169             "amappl", &pool_allocator_nointr);
  170 }
  171 
  172 /*
  173  * amap_alloc1: internal function that allocates an amap, but does not
  174  *      init the overlay.
  175  *
  176  * => lock on returned amap is init'd
  177  */
  178 static inline struct vm_amap *
  179 amap_alloc1(slots, padslots, waitf)
  180         int slots, padslots, waitf;
  181 {
  182         struct vm_amap *amap;
  183         int totalslots;
  184 
  185         amap = pool_get(&uvm_amap_pool, (waitf == M_WAITOK) ? PR_WAITOK : 0);
  186         if (amap == NULL)
  187                 return(NULL);
  188 
  189         totalslots = malloc_roundup((slots + padslots) * sizeof(int)) /
  190             sizeof(int);
  191         simple_lock_init(&amap->am_l);
  192         amap->am_ref = 1;
  193         amap->am_flags = 0;
  194 #ifdef UVM_AMAP_PPREF
  195         amap->am_ppref = NULL;
  196 #endif
  197         amap->am_maxslot = totalslots;
  198         amap->am_nslot = slots;
  199         amap->am_nused = 0;
  200 
  201         amap->am_slots = malloc(totalslots * sizeof(int), M_UVMAMAP,
  202             waitf);
  203         if (amap->am_slots == NULL)
  204                 goto fail1;
  205 
  206         amap->am_bckptr = malloc(totalslots * sizeof(int), M_UVMAMAP, waitf);
  207         if (amap->am_bckptr == NULL)
  208                 goto fail2;
  209 
  210         amap->am_anon = malloc(totalslots * sizeof(struct vm_anon *),
  211             M_UVMAMAP, waitf);
  212         if (amap->am_anon == NULL)
  213                 goto fail3;
  214 
  215         return(amap);
  216 
  217 fail3:
  218         free(amap->am_bckptr, M_UVMAMAP);
  219 fail2:
  220         free(amap->am_slots, M_UVMAMAP);
  221 fail1:
  222         pool_put(&uvm_amap_pool, amap);
  223 
  224         /*
  225          * XXX hack to tell the pagedaemon how many pages we need,
  226          * since we can need more than it would normally free.
  227          */
  228         if (waitf == M_NOWAIT) {
  229                 extern int uvm_extrapages;
  230                 uvm_extrapages += ((sizeof(int) * 2 +
  231                                     sizeof(struct vm_anon *)) *
  232                                    totalslots) >> PAGE_SHIFT;
  233         }
  234         return (NULL);
  235 }
  236 
  237 /*
  238  * amap_alloc: allocate an amap to manage "sz" bytes of anonymous VM
  239  *
  240  * => caller should ensure sz is a multiple of PAGE_SIZE
  241  * => reference count to new amap is set to one
  242  * => new amap is returned unlocked
  243  */
  244 
  245 struct vm_amap *
  246 amap_alloc(sz, padsz, waitf)
  247         vaddr_t sz, padsz;
  248         int waitf;
  249 {
  250         struct vm_amap *amap;
  251         int slots, padslots;
  252         UVMHIST_FUNC("amap_alloc"); UVMHIST_CALLED(maphist);
  253 
  254         AMAP_B2SLOT(slots, sz);
  255         AMAP_B2SLOT(padslots, padsz);
  256 
  257         amap = amap_alloc1(slots, padslots, waitf);
  258         if (amap)
  259                 memset(amap->am_anon, 0,
  260                     amap->am_maxslot * sizeof(struct vm_anon *));
  261 
  262         UVMHIST_LOG(maphist,"<- done, amap = 0x%x, sz=%d", amap, sz, 0, 0);
  263         return(amap);
  264 }
  265 
  266 
  267 /*
  268  * amap_free: free an amap
  269  *
  270  * => the amap must be unlocked
  271  * => the amap should have a zero reference count and be empty
  272  */
  273 void
  274 amap_free(amap)
  275         struct vm_amap *amap;
  276 {
  277         UVMHIST_FUNC("amap_free"); UVMHIST_CALLED(maphist);
  278 
  279         KASSERT(amap->am_ref == 0 && amap->am_nused == 0);
  280         LOCK_ASSERT(!simple_lock_held(&amap->am_l));
  281         free(amap->am_slots, M_UVMAMAP);
  282         free(amap->am_bckptr, M_UVMAMAP);
  283         free(amap->am_anon, M_UVMAMAP);
  284 #ifdef UVM_AMAP_PPREF
  285         if (amap->am_ppref && amap->am_ppref != PPREF_NONE)
  286                 free(amap->am_ppref, M_UVMAMAP);
  287 #endif
  288         pool_put(&uvm_amap_pool, amap);
  289         UVMHIST_LOG(maphist,"<- done, freed amap = 0x%x", amap, 0, 0, 0);
  290 }
  291 
  292 /*
  293  * amap_extend: extend the size of an amap (if needed)
  294  *
  295  * => called from uvm_map when we want to extend an amap to cover
  296  *    a new mapping (rather than allocate a new one)
  297  * => amap should be unlocked (we will lock it)
  298  * => to safely extend an amap it should have a reference count of
  299  *    one (thus it can't be shared)
  300  */
  301 int
  302 amap_extend(entry, addsize, flags)
  303         struct vm_map_entry *entry;
  304         vsize_t addsize;
  305         int flags;
  306 {
  307         struct vm_amap *amap = entry->aref.ar_amap;
  308         int slotoff = entry->aref.ar_pageoff;
  309         int slotmapped, slotadd, slotneed, slotadded, slotalloc;
  310         int slotadj, slotspace;
  311 #ifdef UVM_AMAP_PPREF
  312         int *newppref, *oldppref;
  313 #endif
  314         int i, *newsl, *newbck, *oldsl, *oldbck;
  315         struct vm_anon **newover, **oldover;
  316         int mflag = (flags & AMAP_EXTEND_NOWAIT) ? M_NOWAIT :
  317                         (M_WAITOK | M_CANFAIL);
  318 
  319         UVMHIST_FUNC("amap_extend"); UVMHIST_CALLED(maphist);
  320 
  321         UVMHIST_LOG(maphist, "  (entry=0x%x, addsize=0x%x, flags=0x%x)",
  322             entry, addsize, flags, 0);
  323 
  324         /*
  325          * first, determine how many slots we need in the amap.  don't
  326          * forget that ar_pageoff could be non-zero: this means that
  327          * there are some unused slots before us in the amap.
  328          */
  329 
  330         amap_lock(amap);
  331         AMAP_B2SLOT(slotmapped, entry->end - entry->start); /* slots mapped */
  332         AMAP_B2SLOT(slotadd, addsize);                  /* slots to add */
  333         if (flags & AMAP_EXTEND_FORWARDS) {
  334                 slotneed = slotoff + slotmapped + slotadd;
  335                 slotadj = 0;
  336                 slotspace = 0;
  337         }
  338         else {
  339                 slotneed = slotadd + slotmapped;
  340                 slotadj = slotadd - slotoff;
  341                 slotspace = amap->am_maxslot - slotmapped;
  342         }
  343 
  344         /*
  345          * case 1: we already have enough slots in the map and thus
  346          * only need to bump the reference counts on the slots we are
  347          * adding.
  348          */
  349 
  350         if (flags & AMAP_EXTEND_FORWARDS) {
  351                 if (amap->am_nslot >= slotneed) {
  352 #ifdef UVM_AMAP_PPREF
  353                         if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  354                                 amap_pp_adjref(amap, slotoff + slotmapped,
  355                                     slotadd, 1);
  356                         }
  357 #endif
  358                         amap_unlock(amap);
  359                         UVMHIST_LOG(maphist,
  360                             "<- done (case 1f), amap = 0x%x, sltneed=%d",
  361                             amap, slotneed, 0, 0);
  362                         return 0;
  363                 }
  364         } else {
  365                 if (slotadj <= 0) {
  366                         slotoff -= slotadd;
  367                         entry->aref.ar_pageoff = slotoff;
  368 #ifdef UVM_AMAP_PPREF
  369                         if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  370                                 amap_pp_adjref(amap, slotoff, slotadd, 1);
  371                         }
  372 #endif
  373                         amap_unlock(amap);
  374                         UVMHIST_LOG(maphist,
  375                             "<- done (case 1b), amap = 0x%x, sltneed=%d",
  376                             amap, slotneed, 0, 0);
  377                         return 0;
  378                 }
  379         }
  380 
  381         /*
  382          * case 2: we pre-allocated slots for use and we just need to
  383          * bump nslot up to take account for these slots.
  384          */
  385 
  386         if (amap->am_maxslot >= slotneed) {
  387                 if (flags & AMAP_EXTEND_FORWARDS) {
  388 #ifdef UVM_AMAP_PPREF
  389                         if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  390                                 if ((slotoff + slotmapped) < amap->am_nslot)
  391                                         amap_pp_adjref(amap,
  392                                             slotoff + slotmapped,
  393                                             (amap->am_nslot -
  394                                             (slotoff + slotmapped)), 1);
  395                                 pp_setreflen(amap->am_ppref, amap->am_nslot, 1,
  396                                     slotneed - amap->am_nslot);
  397                         }
  398 #endif
  399                         amap->am_nslot = slotneed;
  400                         amap_unlock(amap);
  401 
  402                         /*
  403                          * no need to zero am_anon since that was done at
  404                          * alloc time and we never shrink an allocation.
  405                          */
  406 
  407                         UVMHIST_LOG(maphist,"<- done (case 2f), amap = 0x%x, "
  408                             "slotneed=%d", amap, slotneed, 0, 0);
  409                         return 0;
  410                 } else {
  411 #ifdef UVM_AMAP_PPREF
  412                         if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  413                                 /*
  414                                  * Slide up the ref counts on the pages that
  415                                  * are actually in use.
  416                                  */
  417                                 memmove(amap->am_ppref + slotspace,
  418                                     amap->am_ppref + slotoff,
  419                                     slotmapped * sizeof(int));
  420                                 /*
  421                                  * Mark the (adjusted) gap at the front as
  422                                  * referenced/not referenced.
  423                                  */
  424                                 pp_setreflen(amap->am_ppref,
  425                                     0, 0, slotspace - slotadd);
  426                                 pp_setreflen(amap->am_ppref,
  427                                     slotspace - slotadd, 1, slotadd);
  428                         }
  429 #endif
  430 
  431                         /*
  432                          * Slide the anon pointers up and clear out
  433                          * the space we just made.
  434                          */
  435                         memmove(amap->am_anon + slotspace,
  436                             amap->am_anon + slotoff,
  437                             slotmapped * sizeof(struct vm_anon*));
  438                         memset(amap->am_anon + slotoff, 0,
  439                             (slotspace - slotoff) * sizeof(struct vm_anon *));
  440 
  441                         /*
  442                          * Slide the backpointers up, but don't bother
  443                          * wiping out the old slots.
  444                          */
  445                         memmove(amap->am_bckptr + slotspace,
  446                             amap->am_bckptr + slotoff,
  447                             slotmapped * sizeof(int));
  448 
  449                         /*
  450                          * Adjust all the useful active slot numbers.
  451                          */
  452                         for (i = 0; i < amap->am_nused; i++)
  453                                 amap->am_slots[i] += (slotspace - slotoff);
  454 
  455                         /*
  456                          * We just filled all the empty space in the
  457                          * front of the amap by activating a few new
  458                          * slots.
  459                          */
  460                         amap->am_nslot = amap->am_maxslot;
  461                         entry->aref.ar_pageoff = slotspace - slotadd;
  462                         amap_unlock(amap);
  463 
  464                         UVMHIST_LOG(maphist,"<- done (case 2b), amap = 0x%x, "
  465                             "slotneed=%d", amap, slotneed, 0, 0);
  466                         return 0;
  467                 }
  468         }
  469 
  470         /*
  471          * case 3: we need to malloc a new amap and copy all the amap
  472          * data over from old amap to the new one.
  473          *
  474          * note that the use of a kernel realloc() probably would not
  475          * help here, since we wish to abort cleanly if one of the
  476          * three (or four) mallocs fails.
  477          */
  478 
  479         amap_unlock(amap);      /* unlock in case we sleep in malloc */
  480         slotalloc = malloc_roundup(slotneed * sizeof(int)) / sizeof(int);
  481 #ifdef UVM_AMAP_PPREF
  482         newppref = NULL;
  483         if (amap->am_ppref && amap->am_ppref != PPREF_NONE)
  484                 newppref = malloc(slotalloc * sizeof(int), M_UVMAMAP, mflag);
  485 #endif
  486         newsl = malloc(slotalloc * sizeof(int), M_UVMAMAP, mflag);
  487         newbck = malloc(slotalloc * sizeof(int), M_UVMAMAP, mflag);
  488         newover = malloc(slotalloc * sizeof(struct vm_anon *), M_UVMAMAP,
  489                     mflag);
  490         if (newsl == NULL || newbck == NULL || newover == NULL) {
  491 #ifdef UVM_AMAP_PPREF
  492                 if (newppref != NULL) {
  493                         free(newppref, M_UVMAMAP);
  494                 }
  495 #endif
  496                 if (newsl != NULL) {
  497                         free(newsl, M_UVMAMAP);
  498                 }
  499                 if (newbck != NULL) {
  500                         free(newbck, M_UVMAMAP);
  501                 }
  502                 if (newover != NULL) {
  503                         free(newover, M_UVMAMAP);
  504                 }
  505                 return ENOMEM;
  506         }
  507         amap_lock(amap);
  508         KASSERT(amap->am_maxslot < slotneed);
  509 
  510         /*
  511          * now copy everything over to new malloc'd areas...
  512          */
  513 
  514         slotadded = slotalloc - amap->am_nslot;
  515         if (!(flags & AMAP_EXTEND_FORWARDS))
  516                 slotspace = slotalloc - slotmapped;
  517 
  518         /* do am_slots */
  519         oldsl = amap->am_slots;
  520         if (flags & AMAP_EXTEND_FORWARDS)
  521                 memcpy(newsl, oldsl, sizeof(int) * amap->am_nused);
  522         else
  523                 for (i = 0; i < amap->am_nused; i++)
  524                         newsl[i] = oldsl[i] + slotspace - slotoff;
  525         amap->am_slots = newsl;
  526 
  527         /* do am_anon */
  528         oldover = amap->am_anon;
  529         if (flags & AMAP_EXTEND_FORWARDS) {
  530                 memcpy(newover, oldover,
  531                     sizeof(struct vm_anon *) * amap->am_nslot);
  532                 memset(newover + amap->am_nslot, 0,
  533                     sizeof(struct vm_anon *) * slotadded);
  534         } else {
  535                 memcpy(newover + slotspace, oldover + slotoff,
  536                     sizeof(struct vm_anon *) * slotmapped);
  537                 memset(newover, 0,
  538                     sizeof(struct vm_anon *) * slotspace);
  539         }
  540         amap->am_anon = newover;
  541 
  542         /* do am_bckptr */
  543         oldbck = amap->am_bckptr;
  544         if (flags & AMAP_EXTEND_FORWARDS)
  545                 memcpy(newbck, oldbck, sizeof(int) * amap->am_nslot);
  546         else
  547                 memcpy(newbck + slotspace, oldbck + slotoff,
  548                     sizeof(int) * slotmapped);
  549         amap->am_bckptr = newbck;
  550 
  551 #ifdef UVM_AMAP_PPREF
  552         /* do ppref */
  553         oldppref = amap->am_ppref;
  554         if (newppref) {
  555                 if (flags & AMAP_EXTEND_FORWARDS) {
  556                         memcpy(newppref, oldppref,
  557                             sizeof(int) * amap->am_nslot);
  558                         memset(newppref + amap->am_nslot, 0,
  559                             sizeof(int) * slotadded);
  560                 } else {
  561                         memcpy(newppref + slotspace, oldppref + slotoff,
  562                             sizeof(int) * slotmapped);
  563                 }
  564                 amap->am_ppref = newppref;
  565                 if ((flags & AMAP_EXTEND_FORWARDS) &&
  566                     (slotoff + slotmapped) < amap->am_nslot)
  567                         amap_pp_adjref(amap, slotoff + slotmapped,
  568                             (amap->am_nslot - (slotoff + slotmapped)), 1);
  569                 if (flags & AMAP_EXTEND_FORWARDS)
  570                         pp_setreflen(newppref, amap->am_nslot, 1,
  571                             slotneed - amap->am_nslot);
  572                 else {
  573                         pp_setreflen(newppref, 0, 0,
  574                             slotalloc - slotneed);
  575                         pp_setreflen(newppref, slotalloc - slotneed, 1,
  576                             slotneed - slotmapped);
  577                 }
  578         } else {
  579                 if (amap->am_ppref)
  580                         amap->am_ppref = PPREF_NONE;
  581         }
  582 #endif
  583 
  584         /* update master values */
  585         if (flags & AMAP_EXTEND_FORWARDS)
  586                 amap->am_nslot = slotneed;
  587         else {
  588                 entry->aref.ar_pageoff = slotspace - slotadd;
  589                 amap->am_nslot = slotalloc;
  590         }
  591         amap->am_maxslot = slotalloc;
  592 
  593         amap_unlock(amap);
  594         free(oldsl, M_UVMAMAP);
  595         free(oldbck, M_UVMAMAP);
  596         free(oldover, M_UVMAMAP);
  597 #ifdef UVM_AMAP_PPREF
  598         if (oldppref && oldppref != PPREF_NONE)
  599                 free(oldppref, M_UVMAMAP);
  600 #endif
  601         UVMHIST_LOG(maphist,"<- done (case 3), amap = 0x%x, slotneed=%d",
  602             amap, slotneed, 0, 0);
  603         return 0;
  604 }
  605 
  606 /*
  607  * amap_share_protect: change protection of anons in a shared amap
  608  *
  609  * for shared amaps, given the current data structure layout, it is
  610  * not possible for us to directly locate all maps referencing the
  611  * shared anon (to change the protection).  in order to protect data
  612  * in shared maps we use pmap_page_protect().  [this is useful for IPC
  613  * mechanisms like map entry passing that may want to write-protect
  614  * all mappings of a shared amap.]  we traverse am_anon or am_slots
  615  * depending on the current state of the amap.
  616  *
  617  * => entry's map and amap must be locked by the caller
  618  */
  619 void
  620 amap_share_protect(entry, prot)
  621         struct vm_map_entry *entry;
  622         vm_prot_t prot;
  623 {
  624         struct vm_amap *amap = entry->aref.ar_amap;
  625         int slots, lcv, slot, stop;
  626 
  627         LOCK_ASSERT(simple_lock_held(&amap->am_l));
  628 
  629         AMAP_B2SLOT(slots, (entry->end - entry->start));
  630         stop = entry->aref.ar_pageoff + slots;
  631 
  632         if (slots < amap->am_nused) {
  633                 /* cheaper to traverse am_anon */
  634                 for (lcv = entry->aref.ar_pageoff ; lcv < stop ; lcv++) {
  635                         if (amap->am_anon[lcv] == NULL)
  636                                 continue;
  637                         if (amap->am_anon[lcv]->u.an_page != NULL)
  638                                 pmap_page_protect(amap->am_anon[lcv]->u.an_page,
  639                                                   prot);
  640                 }
  641                 return;
  642         }
  643 
  644         /* cheaper to traverse am_slots */
  645         for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
  646                 slot = amap->am_slots[lcv];
  647                 if (slot < entry->aref.ar_pageoff || slot >= stop)
  648                         continue;
  649                 if (amap->am_anon[slot]->u.an_page != NULL)
  650                         pmap_page_protect(amap->am_anon[slot]->u.an_page, prot);
  651         }
  652 }
  653 
  654 /*
  655  * amap_wipeout: wipeout all anon's in an amap; then free the amap!
  656  *
  657  * => called from amap_unref when the final reference to an amap is
  658  *      discarded (i.e. when reference count == 1)
  659  * => the amap should be locked (by the caller)
  660  */
  661 
  662 void
  663 amap_wipeout(amap)
  664         struct vm_amap *amap;
  665 {
  666         int lcv, slot;
  667         struct vm_anon *anon;
  668         UVMHIST_FUNC("amap_wipeout"); UVMHIST_CALLED(maphist);
  669         UVMHIST_LOG(maphist,"(amap=0x%x)", amap, 0,0,0);
  670 
  671         amap_unlock(amap);
  672         for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
  673                 int refs;
  674 
  675                 slot = amap->am_slots[lcv];
  676                 anon = amap->am_anon[slot];
  677 
  678                 if (anon == NULL || anon->an_ref == 0)
  679                         panic("amap_wipeout: corrupt amap");
  680 
  681                 simple_lock(&anon->an_lock);
  682                 UVMHIST_LOG(maphist,"  processing anon 0x%x, ref=%d", anon,
  683                     anon->an_ref, 0, 0);
  684                 refs = --anon->an_ref;
  685                 simple_unlock(&anon->an_lock);
  686                 if (refs == 0) {
  687 
  688                         /*
  689                          * we had the last reference to a vm_anon. free it.
  690                          */
  691 
  692                         uvm_anfree(anon);
  693                 }
  694 
  695                 /*
  696                  * XXX
  697                  * releasing the swap space held by an N anons is an O(N^2)
  698                  * operation because of the implementation of extents.
  699                  * if there are many anons, tearing down an exiting process'
  700                  * address space can take many seconds, which causes very
  701                  * annoying pauses.  we yield here to give other processes
  702                  * a chance to run.  this should be removed once the performance
  703                  * of swap space management is improved.
  704                  */
  705 
  706                 if (curlwp->l_cpu->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
  707                         preempt(1);
  708         }
  709 
  710         /*
  711          * now we free the map
  712          */
  713 
  714         amap->am_ref = 0;       /* ... was one */
  715         amap->am_nused = 0;
  716         amap_free(amap);        /* will unlock and free amap */
  717         UVMHIST_LOG(maphist,"<- done!", 0,0,0,0);
  718 }
  719 
  720 /*
  721  * amap_copy: ensure that a map entry's "needs_copy" flag is false
  722  *      by copying the amap if necessary.
  723  *
  724  * => an entry with a null amap pointer will get a new (blank) one.
  725  * => the map that the map entry belongs to must be locked by caller.
  726  * => the amap currently attached to "entry" (if any) must be unlocked.
  727  * => if canchunk is true, then we may clip the entry into a chunk
  728  * => "startva" and "endva" are used only if canchunk is true.  they are
  729  *     used to limit chunking (e.g. if you have a large space that you
  730  *     know you are going to need to allocate amaps for, there is no point
  731  *     in allowing that to be chunked)
  732  */
  733 
  734 void
  735 amap_copy(map, entry, waitf, canchunk, startva, endva)
  736         struct vm_map *map;
  737         struct vm_map_entry *entry;
  738         int waitf;
  739         boolean_t canchunk;
  740         vaddr_t startva, endva;
  741 {
  742         struct vm_amap *amap, *srcamap;
  743         int slots, lcv;
  744         vaddr_t chunksize;
  745         UVMHIST_FUNC("amap_copy"); UVMHIST_CALLED(maphist);
  746         UVMHIST_LOG(maphist, "  (map=%p, entry=%p, waitf=%d)",
  747                     map, entry, waitf, 0);
  748 
  749         /*
  750          * is there a map to copy?   if not, create one from scratch.
  751          */
  752 
  753         if (entry->aref.ar_amap == NULL) {
  754 
  755                 /*
  756                  * check to see if we have a large amap that we can
  757                  * chunk.  we align startva/endva to chunk-sized
  758                  * boundaries and then clip to them.
  759                  */
  760 
  761                 if (canchunk && atop(entry->end - entry->start) >=
  762                     UVM_AMAP_LARGE) {
  763                         /* convert slots to bytes */
  764                         chunksize = UVM_AMAP_CHUNK << PAGE_SHIFT;
  765                         startva = (startva / chunksize) * chunksize;
  766                         endva = roundup(endva, chunksize);
  767                         UVMHIST_LOG(maphist, "  chunk amap ==> clip 0x%x->0x%x"
  768                             "to 0x%x->0x%x", entry->start, entry->end, startva,
  769                             endva);
  770                         UVM_MAP_CLIP_START(map, entry, startva);
  771                         /* watch out for endva wrap-around! */
  772                         if (endva >= startva)
  773                                 UVM_MAP_CLIP_END(map, entry, endva);
  774                 }
  775 
  776                 UVMHIST_LOG(maphist, "<- done [creating new amap 0x%x->0x%x]",
  777                 entry->start, entry->end, 0, 0);
  778                 entry->aref.ar_pageoff = 0;
  779                 entry->aref.ar_amap = amap_alloc(entry->end - entry->start, 0,
  780                     waitf);
  781                 if (entry->aref.ar_amap != NULL)
  782                         entry->etype &= ~UVM_ET_NEEDSCOPY;
  783                 return;
  784         }
  785 
  786         /*
  787          * first check and see if we are the only map entry
  788          * referencing the amap we currently have.  if so, then we can
  789          * just take it over rather than copying it.  note that we are
  790          * reading am_ref with the amap unlocked... the value can only
  791          * be one if we have the only reference to the amap (via our
  792          * locked map).  if we are greater than one we fall through to
  793          * the next case (where we double check the value).
  794          */
  795 
  796         if (entry->aref.ar_amap->am_ref == 1) {
  797                 entry->etype &= ~UVM_ET_NEEDSCOPY;
  798                 UVMHIST_LOG(maphist, "<- done [ref cnt = 1, took it over]",
  799                     0, 0, 0, 0);
  800                 return;
  801         }
  802 
  803         /*
  804          * looks like we need to copy the map.
  805          */
  806 
  807         UVMHIST_LOG(maphist,"  amap=%p, ref=%d, must copy it",
  808             entry->aref.ar_amap, entry->aref.ar_amap->am_ref, 0, 0);
  809         AMAP_B2SLOT(slots, entry->end - entry->start);
  810         amap = amap_alloc1(slots, 0, waitf);
  811         if (amap == NULL) {
  812                 UVMHIST_LOG(maphist, "  amap_alloc1 failed", 0,0,0,0);
  813                 return;
  814         }
  815         srcamap = entry->aref.ar_amap;
  816         amap_lock(srcamap);
  817 
  818         /*
  819          * need to double check reference count now that we've got the
  820          * src amap locked down.  the reference count could have
  821          * changed while we were in malloc.  if the reference count
  822          * dropped down to one we take over the old map rather than
  823          * copying the amap.
  824          */
  825 
  826         if (srcamap->am_ref == 1) {             /* take it over? */
  827                 entry->etype &= ~UVM_ET_NEEDSCOPY;
  828                 amap->am_ref--;         /* drop final reference to map */
  829                 amap_free(amap);        /* dispose of new (unused) amap */
  830                 amap_unlock(srcamap);
  831                 return;
  832         }
  833 
  834         /*
  835          * we must copy it now.
  836          */
  837 
  838         UVMHIST_LOG(maphist, "  copying amap now",0, 0, 0, 0);
  839         for (lcv = 0 ; lcv < slots; lcv++) {
  840                 amap->am_anon[lcv] =
  841                     srcamap->am_anon[entry->aref.ar_pageoff + lcv];
  842                 if (amap->am_anon[lcv] == NULL)
  843                         continue;
  844                 simple_lock(&amap->am_anon[lcv]->an_lock);
  845                 amap->am_anon[lcv]->an_ref++;
  846                 simple_unlock(&amap->am_anon[lcv]->an_lock);
  847                 amap->am_bckptr[lcv] = amap->am_nused;
  848                 amap->am_slots[amap->am_nused] = lcv;
  849                 amap->am_nused++;
  850         }
  851         memset(&amap->am_anon[lcv], 0,
  852             (amap->am_maxslot - lcv) * sizeof(struct vm_anon *));
  853 
  854         /*
  855          * drop our reference to the old amap (srcamap) and unlock.
  856          * we know that the reference count on srcamap is greater than
  857          * one (we checked above), so there is no way we could drop
  858          * the count to zero.  [and no need to worry about freeing it]
  859          */
  860 
  861         srcamap->am_ref--;
  862         if (srcamap->am_ref == 1 && (srcamap->am_flags & AMAP_SHARED) != 0)
  863                 srcamap->am_flags &= ~AMAP_SHARED;   /* clear shared flag */
  864 #ifdef UVM_AMAP_PPREF
  865         if (srcamap->am_ppref && srcamap->am_ppref != PPREF_NONE) {
  866                 amap_pp_adjref(srcamap, entry->aref.ar_pageoff,
  867                     (entry->end - entry->start) >> PAGE_SHIFT, -1);
  868         }
  869 #endif
  870 
  871         amap_unlock(srcamap);
  872 
  873         /*
  874          * install new amap.
  875          */
  876 
  877         entry->aref.ar_pageoff = 0;
  878         entry->aref.ar_amap = amap;
  879         entry->etype &= ~UVM_ET_NEEDSCOPY;
  880         UVMHIST_LOG(maphist, "<- done",0, 0, 0, 0);
  881 }
  882 
  883 /*
  884  * amap_cow_now: resolve all copy-on-write faults in an amap now for fork(2)
  885  *
  886  *      called during fork(2) when the parent process has a wired map
  887  *      entry.   in that case we want to avoid write-protecting pages
  888  *      in the parent's map (e.g. like what you'd do for a COW page)
  889  *      so we resolve the COW here.
  890  *
  891  * => assume parent's entry was wired, thus all pages are resident.
  892  * => assume pages that are loaned out (loan_count) are already mapped
  893  *      read-only in all maps, and thus no need for us to worry about them
  894  * => assume both parent and child vm_map's are locked
  895  * => caller passes child's map/entry in to us
  896  * => if we run out of memory we will unlock the amap and sleep _with_ the
  897  *      parent and child vm_map's locked(!).    we have to do this since
  898  *      we are in the middle of a fork(2) and we can't let the parent
  899  *      map change until we are done copying all the map entrys.
  900  * => XXXCDC: out of memory should cause fork to fail, but there is
  901  *      currently no easy way to do this (needs fix)
  902  * => page queues must be unlocked (we may lock them)
  903  */
  904 
  905 void
  906 amap_cow_now(map, entry)
  907         struct vm_map *map;
  908         struct vm_map_entry *entry;
  909 {
  910         struct vm_amap *amap = entry->aref.ar_amap;
  911         int lcv, slot;
  912         struct vm_anon *anon, *nanon;
  913         struct vm_page *pg, *npg;
  914 
  915         /*
  916          * note that if we unlock the amap then we must ReStart the "lcv" for
  917          * loop because some other process could reorder the anon's in the
  918          * am_anon[] array on us while the lock is dropped.
  919          */
  920 
  921 ReStart:
  922         amap_lock(amap);
  923         for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
  924 
  925                 /*
  926                  * get the page
  927                  */
  928 
  929                 slot = amap->am_slots[lcv];
  930                 anon = amap->am_anon[slot];
  931                 simple_lock(&anon->an_lock);
  932 
  933                 /*
  934                  * If the anon has only one ref, we must have already copied it.
  935                  * This can happen if we needed to sleep waiting for memory
  936                  * in a previous run through this loop.  The new page might
  937                  * even have been paged out, since the new page is not wired.
  938                  */
  939 
  940                 if (anon->an_ref == 1) {
  941                         KASSERT(anon->u.an_page != NULL ||
  942                                 anon->an_swslot != 0);
  943                         simple_unlock(&anon->an_lock);
  944                         continue;
  945                 }
  946 
  947                 /*
  948                  * The old page must be resident since the parent is wired.
  949                  */
  950 
  951                 pg = anon->u.an_page;
  952                 KASSERT(pg != NULL);
  953                 KASSERT(pg->wire_count > 0);
  954 
  955                 /*
  956                  * If the page is loaned then it must already be mapped
  957                  * read-only and we don't need to copy it.
  958                  */
  959 
  960                 if (pg->loan_count != 0) {
  961                         simple_unlock(&anon->an_lock);
  962                         continue;
  963                 }
  964                 KASSERT(pg->uanon == anon && pg->uobject == NULL);
  965 
  966                 /*
  967                  * if the page is busy then we have to unlock, wait for
  968                  * it and then restart.
  969                  */
  970 
  971                 if (pg->flags & PG_BUSY) {
  972                         pg->flags |= PG_WANTED;
  973                         amap_unlock(amap);
  974                         UVM_UNLOCK_AND_WAIT(pg, &anon->an_lock, FALSE,
  975                             "cownow", 0);
  976                         goto ReStart;
  977                 }
  978 
  979                 /*
  980                  * ok, time to do a copy-on-write to a new anon
  981                  */
  982 
  983                 nanon = uvm_analloc();
  984                 if (nanon) {
  985                         npg = uvm_pagealloc(NULL, 0, nanon, 0);
  986                 } else
  987                         npg = NULL;     /* XXX: quiet gcc warning */
  988                 if (nanon == NULL || npg == NULL) {
  989 
  990                         /*
  991                          * XXXCDC: we should cause fork to fail, but we can't.
  992                          */
  993 
  994                         if (nanon) {
  995                                 nanon->an_ref--;
  996                                 simple_unlock(&nanon->an_lock);
  997                                 uvm_anfree(nanon);
  998                         }
  999                         simple_unlock(&anon->an_lock);
 1000                         amap_unlock(amap);
 1001                         uvm_wait("cownowpage");
 1002                         goto ReStart;
 1003                 }
 1004 
 1005                 /*
 1006                  * got it... now we can copy the data and replace anon
 1007                  * with our new one...
 1008                  */
 1009 
 1010                 uvm_pagecopy(pg, npg);          /* old -> new */
 1011                 anon->an_ref--;                 /* can't drop to zero */
 1012                 amap->am_anon[slot] = nanon;    /* replace */
 1013 
 1014                 /*
 1015                  * drop PG_BUSY on new page ... since we have had its owner
 1016                  * locked the whole time it can't be PG_RELEASED or PG_WANTED.
 1017                  */
 1018 
 1019                 uvm_lock_pageq();
 1020                 uvm_pageactivate(npg);
 1021                 uvm_unlock_pageq();
 1022                 npg->flags &= ~(PG_BUSY|PG_FAKE);
 1023                 UVM_PAGE_OWN(npg, NULL);
 1024                 simple_unlock(&nanon->an_lock);
 1025                 simple_unlock(&anon->an_lock);
 1026         }
 1027         amap_unlock(amap);
 1028 }
 1029 
 1030 /*
 1031  * amap_splitref: split a single reference into two separate references
 1032  *
 1033  * => called from uvm_map's clip routines
 1034  * => origref's map should be locked
 1035  * => origref->ar_amap should be unlocked (we will lock)
 1036  */
 1037 void
 1038 amap_splitref(origref, splitref, offset)
 1039         struct vm_aref *origref, *splitref;
 1040         vaddr_t offset;
 1041 {
 1042         int leftslots;
 1043 
 1044         AMAP_B2SLOT(leftslots, offset);
 1045         if (leftslots == 0)
 1046                 panic("amap_splitref: split at zero offset");
 1047 
 1048         amap_lock(origref->ar_amap);
 1049 
 1050         /*
 1051          * now: amap is locked and we have a valid am_mapped array.
 1052          */
 1053 
 1054         if (origref->ar_amap->am_nslot - origref->ar_pageoff - leftslots <= 0)
 1055                 panic("amap_splitref: map size check failed");
 1056 
 1057 #ifdef UVM_AMAP_PPREF
 1058         /*
 1059          * establish ppref before we add a duplicate reference to the amap
 1060          */
 1061         if (origref->ar_amap->am_ppref == NULL)
 1062                 amap_pp_establish(origref->ar_amap, origref->ar_pageoff);
 1063 #endif
 1064 
 1065         splitref->ar_amap = origref->ar_amap;
 1066         splitref->ar_amap->am_ref++;            /* not a share reference */
 1067         splitref->ar_pageoff = origref->ar_pageoff + leftslots;
 1068 
 1069         amap_unlock(origref->ar_amap);
 1070 }
 1071 
 1072 #ifdef UVM_AMAP_PPREF
 1073 
 1074 /*
 1075  * amap_pp_establish: add a ppref array to an amap, if possible
 1076  *
 1077  * => amap locked by caller
 1078  */
 1079 void
 1080 amap_pp_establish(amap, offset)
 1081         struct vm_amap *amap;
 1082         vaddr_t offset;
 1083 {
 1084         amap->am_ppref = malloc(sizeof(int) * amap->am_maxslot,
 1085             M_UVMAMAP, M_NOWAIT);
 1086 
 1087         /*
 1088          * if we fail then we just won't use ppref for this amap
 1089          */
 1090 
 1091         if (amap->am_ppref == NULL) {
 1092                 amap->am_ppref = PPREF_NONE;    /* not using it */
 1093                 return;
 1094         }
 1095         memset(amap->am_ppref, 0, sizeof(int) * amap->am_maxslot);
 1096         pp_setreflen(amap->am_ppref, 0, 0, offset);
 1097         pp_setreflen(amap->am_ppref, offset, amap->am_ref,
 1098             amap->am_nslot - offset);
 1099         return;
 1100 }
 1101 
 1102 /*
 1103  * amap_pp_adjref: adjust reference count to a part of an amap using the
 1104  * per-page reference count array.
 1105  *
 1106  * => map and amap locked by caller
 1107  * => caller must check that ppref != PPREF_NONE before calling
 1108  */
 1109 void
 1110 amap_pp_adjref(amap, curslot, slotlen, adjval)
 1111         struct vm_amap *amap;
 1112         int curslot;
 1113         vsize_t slotlen;
 1114         int adjval;
 1115 {
 1116         int stopslot, *ppref, lcv, prevlcv;
 1117         int ref, len, prevref, prevlen;
 1118 
 1119         stopslot = curslot + slotlen;
 1120         ppref = amap->am_ppref;
 1121         prevlcv = 0;
 1122 
 1123         /*
 1124          * first advance to the correct place in the ppref array,
 1125          * fragment if needed.
 1126          */
 1127 
 1128         for (lcv = 0 ; lcv < curslot ; lcv += len) {
 1129                 pp_getreflen(ppref, lcv, &ref, &len);
 1130                 if (lcv + len > curslot) {     /* goes past start? */
 1131                         pp_setreflen(ppref, lcv, ref, curslot - lcv);
 1132                         pp_setreflen(ppref, curslot, ref, len - (curslot -lcv));
 1133                         len = curslot - lcv;   /* new length of entry @ lcv */
 1134                 }
 1135                 prevlcv = lcv;
 1136         }
 1137         if (lcv != 0)
 1138                 pp_getreflen(ppref, prevlcv, &prevref, &prevlen);
 1139         else {
 1140                 /* Ensure that the "prevref == ref" test below always
 1141                  * fails, since we're starting from the beginning of
 1142                  * the ppref array; that is, there is no previous
 1143                  * chunk.
 1144                  */
 1145                 prevref = -1;
 1146                 prevlen = 0;
 1147         }
 1148 
 1149         /*
 1150          * now adjust reference counts in range.  merge the first
 1151          * changed entry with the last unchanged entry if possible.
 1152          */
 1153 
 1154         if (lcv != curslot)
 1155                 panic("amap_pp_adjref: overshot target");
 1156 
 1157         for (/* lcv already set */; lcv < stopslot ; lcv += len) {
 1158                 pp_getreflen(ppref, lcv, &ref, &len);
 1159                 if (lcv + len > stopslot) {     /* goes past end? */
 1160                         pp_setreflen(ppref, lcv, ref, stopslot - lcv);
 1161                         pp_setreflen(ppref, stopslot, ref,
 1162                             len - (stopslot - lcv));
 1163                         len = stopslot - lcv;
 1164                 }
 1165                 ref += adjval;
 1166                 if (ref < 0)
 1167                         panic("amap_pp_adjref: negative reference count");
 1168                 if (lcv == prevlcv + prevlen && ref == prevref) {
 1169                         pp_setreflen(ppref, prevlcv, ref, prevlen + len);
 1170                 } else {
 1171                         pp_setreflen(ppref, lcv, ref, len);
 1172                 }
 1173                 if (ref == 0)
 1174                         amap_wiperange(amap, lcv, len);
 1175         }
 1176 
 1177 }
 1178 
 1179 /*
 1180  * amap_wiperange: wipe out a range of an amap
 1181  * [different from amap_wipeout because the amap is kept intact]
 1182  *
 1183  * => both map and amap must be locked by caller.
 1184  */
 1185 void
 1186 amap_wiperange(amap, slotoff, slots)
 1187         struct vm_amap *amap;
 1188         int slotoff, slots;
 1189 {
 1190         int byanon, lcv, stop, curslot, ptr, slotend;
 1191         struct vm_anon *anon;
 1192 
 1193         /*
 1194          * we can either traverse the amap by am_anon or by am_slots depending
 1195          * on which is cheaper.    decide now.
 1196          */
 1197 
 1198         if (slots < amap->am_nused) {
 1199                 byanon = TRUE;
 1200                 lcv = slotoff;
 1201                 stop = slotoff + slots;
 1202                 slotend = 0;
 1203         } else {
 1204                 byanon = FALSE;
 1205                 lcv = 0;
 1206                 stop = amap->am_nused;
 1207                 slotend = slotoff + slots;
 1208         }
 1209 
 1210         while (lcv < stop) {
 1211                 int refs;
 1212 
 1213                 if (byanon) {
 1214                         curslot = lcv++;        /* lcv advances here */
 1215                         if (amap->am_anon[curslot] == NULL)
 1216                                 continue;
 1217                 } else {
 1218                         curslot = amap->am_slots[lcv];
 1219                         if (curslot < slotoff || curslot >= slotend) {
 1220                                 lcv++;          /* lcv advances here */
 1221                                 continue;
 1222                         }
 1223                         stop--; /* drop stop, since anon will be removed */
 1224                 }
 1225                 anon = amap->am_anon[curslot];
 1226 
 1227                 /*
 1228                  * remove it from the amap
 1229                  */
 1230 
 1231                 amap->am_anon[curslot] = NULL;
 1232                 ptr = amap->am_bckptr[curslot];
 1233                 if (ptr != (amap->am_nused - 1)) {
 1234                         amap->am_slots[ptr] =
 1235                             amap->am_slots[amap->am_nused - 1];
 1236                         amap->am_bckptr[amap->am_slots[ptr]] =
 1237                             ptr;    /* back ptr. */
 1238                 }
 1239                 amap->am_nused--;
 1240 
 1241                 /*
 1242                  * drop anon reference count
 1243                  */
 1244 
 1245                 simple_lock(&anon->an_lock);
 1246                 refs = --anon->an_ref;
 1247                 simple_unlock(&anon->an_lock);
 1248                 if (refs == 0) {
 1249 
 1250                         /*
 1251                          * we just eliminated the last reference to an anon.
 1252                          * free it.
 1253                          */
 1254 
 1255                         uvm_anfree(anon);
 1256                 }
 1257         }
 1258 }
 1259 
 1260 #endif

Cache object: 0029347613e3d0761a71499b6cea7abf


[ 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.