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.80 2020/10/25 00:05:26 chs Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1997 Charles D. Cranor and Washington University.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * uvm_anon.c: uvm anon ops
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: uvm_anon.c,v 1.80 2020/10/25 00:05:26 chs Exp $");
   34 
   35 #include "opt_uvmhist.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/pool.h>
   40 #include <sys/kernel.h>
   41 #include <sys/atomic.h>
   42 
   43 #include <uvm/uvm.h>
   44 #include <uvm/uvm_swap.h>
   45 #include <uvm/uvm_pdpolicy.h>
   46 
   47 static struct pool_cache        uvm_anon_cache;
   48 
   49 static int                      uvm_anon_ctor(void *, void *, int);
   50 
   51 void
   52 uvm_anon_init(void)
   53 {
   54 
   55         pool_cache_bootstrap(&uvm_anon_cache, sizeof(struct vm_anon), 0, 0,
   56             PR_LARGECACHE, "anonpl", NULL, IPL_NONE, uvm_anon_ctor,
   57             NULL, NULL);
   58 }
   59 
   60 static int
   61 uvm_anon_ctor(void *arg, void *object, int flags)
   62 {
   63         struct vm_anon *anon = object;
   64 
   65         anon->an_ref = 0;
   66         anon->an_lock = NULL;
   67         anon->an_page = NULL;
   68 #if defined(VMSWAP)
   69         anon->an_swslot = 0;
   70 #endif
   71         return 0;
   72 }
   73 
   74 /*
   75  * uvm_analloc: allocate a new anon.
   76  *
   77  * => anon will have no lock associated.
   78  */
   79 struct vm_anon *
   80 uvm_analloc(void)
   81 {
   82         struct vm_anon *anon;
   83 
   84         anon = pool_cache_get(&uvm_anon_cache, PR_NOWAIT);
   85         if (anon) {
   86                 KASSERT(anon->an_ref == 0);
   87                 KASSERT(anon->an_lock == NULL);
   88                 KASSERT(anon->an_page == NULL);
   89 #if defined(VMSWAP)
   90                 KASSERT(anon->an_swslot == 0);
   91 #endif
   92                 anon->an_ref = 1;
   93         }
   94         return anon;
   95 }
   96 
   97 /*
   98  * uvm_anfree: free a single anon structure
   99  *
  100  * => anon must be removed from the amap (if anon was in an amap).
  101  * => amap must be locked, if anon was owned by amap.
  102  * => we may drop and re-acquire the lock here (to break loans).
  103  */
  104 void
  105 uvm_anfree(struct vm_anon *anon)
  106 {
  107         struct vm_page *pg = anon->an_page, *pg2 __diagused;
  108 
  109         UVMHIST_FUNC(__func__);
  110         UVMHIST_CALLARGS(maphist,"(anon=%#jx)", (uintptr_t)anon, 0,0,0);
  111 
  112         KASSERT(anon->an_lock == NULL || rw_write_held(anon->an_lock));
  113         KASSERT(anon->an_ref == 0);
  114 
  115         /*
  116          * Dispose of the page, if it is resident.
  117          */
  118 
  119         if (__predict_true(pg != NULL)) {
  120                 KASSERT(anon->an_lock != NULL);
  121 
  122                 /*
  123                  * If there is a resident page and it is loaned, then anon
  124                  * may not own it.  Call out to uvm_anon_lockloanpg() to
  125                  * identify and lock the real owner of the page.
  126                  */
  127 
  128                 if (__predict_false(pg->loan_count != 0)) {
  129                         pg2 = uvm_anon_lockloanpg(anon);
  130                         KASSERT(pg2 == pg);
  131                 }
  132 
  133                 /*
  134                  * If the page is owned by a UVM object (now locked),
  135                  * then kill the loan on the page rather than free it,
  136                  * and release the object lock.
  137                  */
  138 
  139                 if (__predict_false(pg->uobject != NULL)) {
  140                         mutex_enter(&pg->interlock);
  141                         KASSERT(pg->loan_count > 0);
  142                         pg->loan_count--;
  143                         pg->uanon = NULL;
  144                         mutex_exit(&pg->interlock);
  145                         rw_exit(pg->uobject->vmobjlock);
  146                 } else {
  147 
  148                         /*
  149                          * If page has no UVM object, then anon is the owner,
  150                          * and it is already locked.
  151                          */
  152 
  153                         KASSERT((pg->flags & PG_RELEASED) == 0);
  154                         pmap_page_protect(pg, VM_PROT_NONE);
  155 
  156                         /*
  157                          * If the page is busy, mark it as PG_RELEASED, so
  158                          * that uvm_anon_release(9) would release it later.
  159                          */
  160 
  161                         if (__predict_false((pg->flags & PG_BUSY) != 0)) {
  162                                 pg->flags |= PG_RELEASED;
  163                                 rw_obj_hold(anon->an_lock);
  164                                 return;
  165                         }
  166                         uvm_pagefree(pg);
  167                         UVMHIST_LOG(maphist, "anon %#jx, page %#jx: "
  168                             "freed now!", (uintptr_t)anon, (uintptr_t)pg,
  169                             0, 0);
  170                 }
  171         } else {
  172 #if defined(VMSWAP)
  173                 if (anon->an_swslot > 0) {
  174                         /* This page is no longer only in swap. */
  175                         KASSERT(uvmexp.swpgonly > 0);
  176                         atomic_dec_uint(&uvmexp.swpgonly);
  177                 }
  178 #endif
  179         }
  180         anon->an_lock = NULL;
  181 
  182         /*
  183          * Free any swap resources, leave a page replacement hint.
  184          */
  185 
  186         uvm_anon_dropswap(anon);
  187         uvmpdpol_anfree(anon);
  188         UVMHIST_LOG(maphist,"<- done!",0,0,0,0);
  189         pool_cache_put(&uvm_anon_cache, anon);
  190 }
  191 
  192 /*
  193  * uvm_anon_lockloanpg: given a locked anon, lock its resident page owner.
  194  *
  195  * => anon is locked by caller
  196  * => on return: anon is locked
  197  *               if there is a resident page:
  198  *                      if it has a uobject, it is locked by us
  199  *                      if it is ownerless, we take over as owner
  200  *               we return the resident page (it can change during
  201  *               this function)
  202  * => note that the only time an anon has an ownerless resident page
  203  *      is if the page was loaned from a uvm_object and the uvm_object
  204  *      disowned it
  205  * => this only needs to be called when you want to do an operation
  206  *      on an anon's resident page and that page has a non-zero loan
  207  *      count.
  208  */
  209 struct vm_page *
  210 uvm_anon_lockloanpg(struct vm_anon *anon)
  211 {
  212         struct vm_page *pg;
  213         krw_t op;
  214 
  215         KASSERT(rw_lock_held(anon->an_lock));
  216 
  217         /*
  218          * loop while we have a resident page that has a non-zero loan count.
  219          * if we successfully get our lock, we will "break" the loop.
  220          * note that the test for pg->loan_count is not protected -- this
  221          * may produce false positive results.   note that a false positive
  222          * result may cause us to do more work than we need to, but it will
  223          * not produce an incorrect result.
  224          */
  225 
  226         while (((pg = anon->an_page) != NULL) && pg->loan_count != 0) {
  227                 mutex_enter(&pg->interlock);
  228                 if (pg->uobject) {
  229                         /*
  230                          * if we didn't get a lock (try lock failed), then we
  231                          * toggle our anon lock and try again
  232                          */
  233 
  234                         if (!rw_tryenter(pg->uobject->vmobjlock, RW_WRITER)) {
  235                                 /*
  236                                  * someone locking the object has a chance to
  237                                  * lock us right now
  238                                  *
  239                                  * XXX Better than yielding but inadequate.
  240                                  */
  241                                 mutex_exit(&pg->interlock);
  242                                 op = rw_lock_op(anon->an_lock);
  243                                 rw_exit(anon->an_lock);
  244                                 kpause("lkloanpg", false, 1, NULL);
  245                                 rw_enter(anon->an_lock, op);
  246                                 continue;
  247                         }
  248                 }
  249 
  250                 /*
  251                  * If page is un-owned i.e. the object dropped its ownership,
  252                  * then we have to take the ownership.
  253                  */
  254 
  255                 if (pg->uobject == NULL && (pg->flags & PG_ANON) == 0) {
  256                         pg->flags |= PG_ANON;
  257                         pg->loan_count--;
  258                 }
  259                 mutex_exit(&pg->interlock);
  260                 break;
  261         }
  262         return pg;
  263 }
  264 
  265 #if defined(VMSWAP)
  266 
  267 /*
  268  * uvm_anon_pagein: fetch an anon's page.
  269  *
  270  * => anon must be locked, and is unlocked upon return.
  271  * => returns true if pagein was aborted due to lack of memory.
  272  */
  273 
  274 bool
  275 uvm_anon_pagein(struct vm_amap *amap, struct vm_anon *anon)
  276 {
  277         struct vm_page *pg;
  278         struct uvm_object *uobj;
  279 
  280         KASSERT(rw_write_held(anon->an_lock));
  281         KASSERT(anon->an_lock == amap->am_lock);
  282 
  283         /*
  284          * Get the page of the anon.
  285          */
  286 
  287         switch (uvmfault_anonget(NULL, amap, anon)) {
  288         case 0:
  289                 /* Success - we have the page. */
  290                 KASSERT(rw_write_held(anon->an_lock));
  291                 break;
  292         case EIO:
  293         case ERESTART:
  294                 /*
  295                  * Nothing more to do on errors.  ERESTART means that the
  296                  * anon was freed.
  297                  */
  298                 return false;
  299         case ENOLCK:
  300                 panic("uvm_anon_pagein");
  301         default:
  302                 return true;
  303         }
  304 
  305         /*
  306          * Mark the page as dirty and clear its swslot.
  307          */
  308 
  309         pg = anon->an_page;
  310         uobj = pg->uobject;
  311         if (anon->an_swslot > 0) {
  312                 uvm_swap_free(anon->an_swslot, 1);
  313         }
  314         anon->an_swslot = 0;
  315         uvm_pagemarkdirty(pg, UVM_PAGE_STATUS_DIRTY);
  316 
  317         /*
  318          * Deactivate the page (to put it on a page queue).
  319          */
  320 
  321         uvm_pagelock(pg);
  322         uvm_pagedeactivate(pg);
  323         uvm_pageunlock(pg);
  324         rw_exit(anon->an_lock);
  325         if (uobj) {
  326                 rw_exit(uobj->vmobjlock);
  327         }
  328         return false;
  329 }
  330 
  331 /*
  332  * uvm_anon_dropswap: release any swap resources from this anon.
  333  *
  334  * => anon must be locked or have a reference count of 0.
  335  */
  336 void
  337 uvm_anon_dropswap(struct vm_anon *anon)
  338 {
  339         UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
  340 
  341         if (anon->an_swslot == 0)
  342                 return;
  343 
  344         UVMHIST_LOG(maphist,"freeing swap for anon %#jx, paged to swslot %#jx",
  345                     (uintptr_t)anon, anon->an_swslot, 0, 0);
  346         uvm_swap_free(anon->an_swslot, 1);
  347         anon->an_swslot = 0;
  348 }
  349 
  350 #endif
  351 
  352 /*
  353  * uvm_anon_release: release an anon and its page.
  354  *
  355  * => anon should not have any references.
  356  * => anon must be locked.
  357  */
  358 
  359 void
  360 uvm_anon_release(struct vm_anon *anon)
  361 {
  362         struct vm_page *pg = anon->an_page;
  363         krwlock_t *lock;
  364 
  365         KASSERT(rw_write_held(anon->an_lock));
  366         KASSERT(pg != NULL);
  367         KASSERT((pg->flags & PG_RELEASED) != 0);
  368         KASSERT((pg->flags & PG_BUSY) != 0);
  369         KASSERT(pg->uobject == NULL);
  370         KASSERT(pg->uanon == anon);
  371         KASSERT(pg->loan_count == 0);
  372         KASSERT(anon->an_ref == 0);
  373 
  374         if ((pg->flags & PG_PAGEOUT) != 0) {
  375                 pg->flags &= ~PG_PAGEOUT;
  376                 uvm_pageout_done(1);
  377         }
  378 
  379         uvm_pagefree(pg);
  380         KASSERT(anon->an_page == NULL);
  381         lock = anon->an_lock;
  382         uvm_anfree(anon);
  383         rw_exit(lock);
  384         /* Note: extra reference is held for PG_RELEASED case. */
  385         rw_obj_free(lock);
  386 }

Cache object: 76517d7873b82fa3895a0ab1e3948397


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