root/uvm/uvm_amap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. LIST_HEAD
  2. amap_list_remove
  3. pp_getreflen
  4. pp_setreflen
  5. amap_init
  6. amap_alloc1
  7. amap_alloc
  8. amap_free
  9. amap_extend
  10. amap_share_protect
  11. amap_wipeout
  12. amap_copy
  13. amap_cow_now
  14. amap_splitref
  15. amap_pp_establish
  16. amap_pp_adjref
  17. amap_wiperange
  18. amap_swap_off

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

/* [<][>][^][v][top][bottom][index][help] */