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  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 9efe17ddffd8e9699eab73a671f73f7b


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