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_anon.c

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

    1 /*      $NetBSD: uvm_anon.c,v 1.41 2006/11/01 10:18:27 yamt 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_anon.c: uvm anon ops
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: uvm_anon.c,v 1.41 2006/11/01 10:18:27 yamt Exp $");
   41 
   42 #include "opt_uvmhist.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/proc.h>
   47 #include <sys/malloc.h>
   48 #include <sys/pool.h>
   49 #include <sys/kernel.h>
   50 
   51 #include <uvm/uvm.h>
   52 #include <uvm/uvm_swap.h>
   53 #include <uvm/uvm_pdpolicy.h>
   54 
   55 static POOL_INIT(uvm_anon_pool, sizeof(struct vm_anon), 0, 0, 0, "anonpl",
   56     &pool_allocator_nointr);
   57 static struct pool_cache uvm_anon_pool_cache;
   58 
   59 static int uvm_anon_ctor(void *, void *, int);
   60 
   61 /*
   62  * allocate anons
   63  */
   64 void
   65 uvm_anon_init(void)
   66 {
   67 
   68         pool_cache_init(&uvm_anon_pool_cache, &uvm_anon_pool,
   69             uvm_anon_ctor, NULL, NULL);
   70 }
   71 
   72 static int
   73 uvm_anon_ctor(void *arg, void *object, int flags)
   74 {
   75         struct vm_anon *anon = object;
   76 
   77         anon->an_ref = 0;
   78         simple_lock_init(&anon->an_lock);
   79         anon->an_page = NULL;
   80 #if defined(VMSWAP)
   81         anon->an_swslot = 0;
   82 #endif /* defined(VMSWAP) */
   83 
   84         return 0;
   85 }
   86 
   87 /*
   88  * allocate an anon
   89  *
   90  * => new anon is returned locked!
   91  */
   92 struct vm_anon *
   93 uvm_analloc(void)
   94 {
   95         struct vm_anon *anon;
   96 
   97         anon = pool_cache_get(&uvm_anon_pool_cache, PR_NOWAIT);
   98         if (anon) {
   99                 KASSERT(anon->an_ref == 0);
  100                 LOCK_ASSERT(simple_lock_held(&anon->an_lock) == 0);
  101                 KASSERT(anon->an_page == NULL);
  102 #if defined(VMSWAP)
  103                 KASSERT(anon->an_swslot == 0);
  104 #endif /* defined(VMSWAP) */
  105                 anon->an_ref = 1;
  106                 simple_lock(&anon->an_lock);
  107         }
  108         return anon;
  109 }
  110 
  111 /*
  112  * uvm_anfree: free a single anon structure
  113  *
  114  * => caller must remove anon from its amap before calling (if it was in
  115  *      an amap).
  116  * => anon must be unlocked and have a zero reference count.
  117  * => we may lock the pageq's.
  118  */
  119 
  120 void
  121 uvm_anfree(struct vm_anon *anon)
  122 {
  123         struct vm_page *pg;
  124         UVMHIST_FUNC("uvm_anfree"); UVMHIST_CALLED(maphist);
  125         UVMHIST_LOG(maphist,"(anon=0x%x)", anon, 0,0,0);
  126 
  127         KASSERT(anon->an_ref == 0);
  128         LOCK_ASSERT(!simple_lock_held(&anon->an_lock));
  129 
  130         /*
  131          * get page
  132          */
  133 
  134         pg = anon->an_page;
  135 
  136         /*
  137          * if there is a resident page and it is loaned, then anon may not
  138          * own it.   call out to uvm_anon_lockpage() to ensure the real owner
  139          * of the page has been identified and locked.
  140          */
  141 
  142         if (pg && pg->loan_count) {
  143                 simple_lock(&anon->an_lock);
  144                 pg = uvm_anon_lockloanpg(anon);
  145                 simple_unlock(&anon->an_lock);
  146         }
  147 
  148         /*
  149          * if we have a resident page, we must dispose of it before freeing
  150          * the anon.
  151          */
  152 
  153         if (pg) {
  154 
  155                 /*
  156                  * if the page is owned by a uobject (now locked), then we must
  157                  * kill the loan on the page rather than free it.
  158                  */
  159 
  160                 if (pg->uobject) {
  161                         uvm_lock_pageq();
  162                         KASSERT(pg->loan_count > 0);
  163                         pg->loan_count--;
  164                         pg->uanon = NULL;
  165                         uvm_unlock_pageq();
  166                         simple_unlock(&pg->uobject->vmobjlock);
  167                 } else {
  168 
  169                         /*
  170                          * page has no uobject, so we must be the owner of it.
  171                          */
  172 
  173                         KASSERT((pg->flags & PG_RELEASED) == 0);
  174                         simple_lock(&anon->an_lock);
  175                         pmap_page_protect(pg, VM_PROT_NONE);
  176 
  177                         /*
  178                          * if the page is busy, mark it as PG_RELEASED
  179                          * so that uvm_anon_release will release it later.
  180                          */
  181 
  182                         if (pg->flags & PG_BUSY) {
  183                                 pg->flags |= PG_RELEASED;
  184                                 simple_unlock(&anon->an_lock);
  185                                 return;
  186                         }
  187                         uvm_lock_pageq();
  188                         uvm_pagefree(pg);
  189                         uvm_unlock_pageq();
  190                         simple_unlock(&anon->an_lock);
  191                         UVMHIST_LOG(maphist, "anon 0x%x, page 0x%x: "
  192                                     "freed now!", anon, pg, 0, 0);
  193                 }
  194         }
  195 #if defined(VMSWAP)
  196         if (pg == NULL && anon->an_swslot > 0) {
  197                 /* this page is no longer only in swap. */
  198                 simple_lock(&uvm.swap_data_lock);
  199                 KASSERT(uvmexp.swpgonly > 0);
  200                 uvmexp.swpgonly--;
  201                 simple_unlock(&uvm.swap_data_lock);
  202         }
  203 #endif /* defined(VMSWAP) */
  204 
  205         /*
  206          * free any swap resources.
  207          */
  208 
  209         uvm_anon_dropswap(anon);
  210 
  211         /*
  212          * give a page replacement hint.
  213          */
  214 
  215         uvmpdpol_anfree(anon);
  216 
  217         /*
  218          * now that we've stripped the data areas from the anon,
  219          * free the anon itself.
  220          */
  221 
  222         KASSERT(anon->an_page == NULL);
  223 #if defined(VMSWAP)
  224         KASSERT(anon->an_swslot == 0);
  225 #endif /* defined(VMSWAP) */
  226 
  227         pool_cache_put(&uvm_anon_pool_cache, anon);
  228         UVMHIST_LOG(maphist,"<- done!",0,0,0,0);
  229 }
  230 
  231 #if defined(VMSWAP)
  232 
  233 /*
  234  * uvm_anon_dropswap:  release any swap resources from this anon.
  235  *
  236  * => anon must be locked or have a reference count of 0.
  237  */
  238 void
  239 uvm_anon_dropswap(struct vm_anon *anon)
  240 {
  241         UVMHIST_FUNC("uvm_anon_dropswap"); UVMHIST_CALLED(maphist);
  242 
  243         if (anon->an_swslot == 0)
  244                 return;
  245 
  246         UVMHIST_LOG(maphist,"freeing swap for anon %p, paged to swslot 0x%x",
  247                     anon, anon->an_swslot, 0, 0);
  248         uvm_swap_free(anon->an_swslot, 1);
  249         anon->an_swslot = 0;
  250 }
  251 
  252 #endif /* defined(VMSWAP) */
  253 
  254 /*
  255  * uvm_anon_lockloanpg: given a locked anon, lock its resident page
  256  *
  257  * => anon is locked by caller
  258  * => on return: anon is locked
  259  *               if there is a resident page:
  260  *                      if it has a uobject, it is locked by us
  261  *                      if it is ownerless, we take over as owner
  262  *               we return the resident page (it can change during
  263  *               this function)
  264  * => note that the only time an anon has an ownerless resident page
  265  *      is if the page was loaned from a uvm_object and the uvm_object
  266  *      disowned it
  267  * => this only needs to be called when you want to do an operation
  268  *      on an anon's resident page and that page has a non-zero loan
  269  *      count.
  270  */
  271 struct vm_page *
  272 uvm_anon_lockloanpg(struct vm_anon *anon)
  273 {
  274         struct vm_page *pg;
  275         boolean_t locked = FALSE;
  276 
  277         LOCK_ASSERT(simple_lock_held(&anon->an_lock));
  278 
  279         /*
  280          * loop while we have a resident page that has a non-zero loan count.
  281          * if we successfully get our lock, we will "break" the loop.
  282          * note that the test for pg->loan_count is not protected -- this
  283          * may produce false positive results.   note that a false positive
  284          * result may cause us to do more work than we need to, but it will
  285          * not produce an incorrect result.
  286          */
  287 
  288         while (((pg = anon->an_page) != NULL) && pg->loan_count != 0) {
  289 
  290                 /*
  291                  * quickly check to see if the page has an object before
  292                  * bothering to lock the page queues.   this may also produce
  293                  * a false positive result, but that's ok because we do a real
  294                  * check after that.
  295                  */
  296 
  297                 if (pg->uobject) {
  298                         uvm_lock_pageq();
  299                         if (pg->uobject) {
  300                                 locked =
  301                                     simple_lock_try(&pg->uobject->vmobjlock);
  302                         } else {
  303                                 /* object disowned before we got PQ lock */
  304                                 locked = TRUE;
  305                         }
  306                         uvm_unlock_pageq();
  307 
  308                         /*
  309                          * if we didn't get a lock (try lock failed), then we
  310                          * toggle our anon lock and try again
  311                          */
  312 
  313                         if (!locked) {
  314                                 simple_unlock(&anon->an_lock);
  315 
  316                                 /*
  317                                  * someone locking the object has a chance to
  318                                  * lock us right now
  319                                  */
  320 
  321                                 simple_lock(&anon->an_lock);
  322                                 continue;
  323                         }
  324                 }
  325 
  326                 /*
  327                  * if page is un-owned [i.e. the object dropped its ownership],
  328                  * then we can take over as owner!
  329                  */
  330 
  331                 if (pg->uobject == NULL && (pg->pqflags & PQ_ANON) == 0) {
  332                         uvm_lock_pageq();
  333                         pg->pqflags |= PQ_ANON;
  334                         pg->loan_count--;
  335                         uvm_unlock_pageq();
  336                 }
  337                 break;
  338         }
  339         return(pg);
  340 }
  341 
  342 #if defined(VMSWAP)
  343 
  344 /*
  345  * fetch an anon's page.
  346  *
  347  * => anon must be locked, and is unlocked upon return.
  348  * => returns TRUE if pagein was aborted due to lack of memory.
  349  */
  350 
  351 boolean_t
  352 uvm_anon_pagein(struct vm_anon *anon)
  353 {
  354         struct vm_page *pg;
  355         struct uvm_object *uobj;
  356         int rv;
  357 
  358         /* locked: anon */
  359         LOCK_ASSERT(simple_lock_held(&anon->an_lock));
  360 
  361         rv = uvmfault_anonget(NULL, NULL, anon);
  362 
  363         /*
  364          * if rv == 0, anon is still locked, else anon
  365          * is unlocked
  366          */
  367 
  368         switch (rv) {
  369         case 0:
  370                 break;
  371 
  372         case EIO:
  373         case ERESTART:
  374 
  375                 /*
  376                  * nothing more to do on errors.
  377                  * ERESTART can only mean that the anon was freed,
  378                  * so again there's nothing to do.
  379                  */
  380 
  381                 return FALSE;
  382 
  383         default:
  384                 return TRUE;
  385         }
  386 
  387         /*
  388          * ok, we've got the page now.
  389          * mark it as dirty, clear its swslot and un-busy it.
  390          */
  391 
  392         pg = anon->an_page;
  393         uobj = pg->uobject;
  394         if (anon->an_swslot > 0)
  395                 uvm_swap_free(anon->an_swslot, 1);
  396         anon->an_swslot = 0;
  397         pg->flags &= ~(PG_CLEAN);
  398 
  399         /*
  400          * deactivate the page (to put it on a page queue)
  401          */
  402 
  403         pmap_clear_reference(pg);
  404         uvm_lock_pageq();
  405         if (pg->wire_count == 0)
  406                 uvm_pagedeactivate(pg);
  407         uvm_unlock_pageq();
  408 
  409         if (pg->flags & PG_WANTED) {
  410                 wakeup(pg);
  411                 pg->flags &= ~(PG_WANTED);
  412         }
  413 
  414         /*
  415          * unlock the anon and we're done.
  416          */
  417 
  418         simple_unlock(&anon->an_lock);
  419         if (uobj) {
  420                 simple_unlock(&uobj->vmobjlock);
  421         }
  422         return FALSE;
  423 }
  424 
  425 #endif /* defined(VMSWAP) */
  426 
  427 /*
  428  * uvm_anon_release: release an anon and its page.
  429  *
  430  * => caller must lock the anon.
  431  */
  432 
  433 void
  434 uvm_anon_release(struct vm_anon *anon)
  435 {
  436         struct vm_page *pg = anon->an_page;
  437 
  438         LOCK_ASSERT(simple_lock_held(&anon->an_lock));
  439 
  440         KASSERT(pg != NULL);
  441         KASSERT((pg->flags & PG_RELEASED) != 0);
  442         KASSERT((pg->flags & PG_BUSY) != 0);
  443         KASSERT(pg->uobject == NULL);
  444         KASSERT(pg->uanon == anon);
  445         KASSERT(pg->loan_count == 0);
  446         KASSERT(anon->an_ref == 0);
  447 
  448         uvm_lock_pageq();
  449         uvm_pagefree(pg);
  450         uvm_unlock_pageq();
  451         simple_unlock(&anon->an_lock);
  452 
  453         KASSERT(anon->an_page == NULL);
  454 
  455         uvm_anfree(anon);
  456 }

Cache object: 7f1c7e9dd5c7df561723118f167c6baf


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