1*0b4f1452Smpi /* $OpenBSD: uvm_anon.c,v 1.61 2024/12/27 12:04:40 mpi Exp $ */ 22c932f6fSmiod /* $NetBSD: uvm_anon.c,v 1.10 2000/11/25 06:27:59 chs Exp $ */ 3cd7ee8acSart 4cd7ee8acSart /* 5cd7ee8acSart * Copyright (c) 1997 Charles D. Cranor and Washington University. 6cd7ee8acSart * All rights reserved. 7cd7ee8acSart * 8cd7ee8acSart * Redistribution and use in source and binary forms, with or without 9cd7ee8acSart * modification, are permitted provided that the following conditions 10cd7ee8acSart * are met: 11cd7ee8acSart * 1. Redistributions of source code must retain the above copyright 12cd7ee8acSart * notice, this list of conditions and the following disclaimer. 13cd7ee8acSart * 2. Redistributions in binary form must reproduce the above copyright 14cd7ee8acSart * notice, this list of conditions and the following disclaimer in the 15cd7ee8acSart * documentation and/or other materials provided with the distribution. 16cd7ee8acSart * 17cd7ee8acSart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18cd7ee8acSart * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19cd7ee8acSart * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20cd7ee8acSart * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21cd7ee8acSart * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22cd7ee8acSart * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23cd7ee8acSart * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24cd7ee8acSart * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25cd7ee8acSart * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26cd7ee8acSart * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27cd7ee8acSart */ 28cd7ee8acSart 29cd7ee8acSart /* 30cd7ee8acSart * uvm_anon.c: uvm anon ops 31cd7ee8acSart */ 32cd7ee8acSart 33cd7ee8acSart #include <sys/param.h> 34cd7ee8acSart #include <sys/systm.h> 35cd7ee8acSart #include <sys/malloc.h> 36cd7ee8acSart #include <sys/pool.h> 3728fbabcfSart #include <sys/kernel.h> 3803d1830dStedu #include <sys/atomic.h> 39cd7ee8acSart 40cd7ee8acSart #include <uvm/uvm.h> 41cd7ee8acSart #include <uvm/uvm_swap.h> 42cd7ee8acSart 438d0b5bafSpedro struct pool uvm_anon_pool; 4428fbabcfSart 45cd7ee8acSart void 462023d591Soga uvm_anon_init(void) 47cd7ee8acSart { 4819dcab73Smpi pool_init(&uvm_anon_pool, sizeof(struct vm_anon), 0, IPL_MPFLOOR, 49ac6cf2c1Stedu PR_WAITOK, "anonpl", NULL); 508d0b5bafSpedro pool_sethiwat(&uvm_anon_pool, uvmexp.free / 16); 5128fbabcfSart } 5228fbabcfSart 5328fbabcfSart /* 5452887a38Smpi * uvm_analloc: allocate a new anon. 5552887a38Smpi * 5652887a38Smpi * => anon will have no lock associated. 57cd7ee8acSart */ 58cd7ee8acSart struct vm_anon * 592023d591Soga uvm_analloc(void) 60cd7ee8acSart { 618d0b5bafSpedro struct vm_anon *anon; 62cd7ee8acSart 638d0b5bafSpedro anon = pool_get(&uvm_anon_pool, PR_NOWAIT); 648d0b5bafSpedro if (anon) { 6519dcab73Smpi anon->an_lock = NULL; 668d0b5bafSpedro anon->an_ref = 1; 678d0b5bafSpedro anon->an_page = NULL; 688d0b5bafSpedro anon->an_swslot = 0; 69cd7ee8acSart } 70b9df1565Smpi return anon; 71cd7ee8acSart } 72cd7ee8acSart 73cd7ee8acSart /* 7419dcab73Smpi * uvm_anfree_list: free a single anon structure 75cd7ee8acSart * 7619dcab73Smpi * => anon must be removed from the amap (if anon was in an amap). 7719dcab73Smpi * => amap must be locked, if anon was owned by amap. 78cd7ee8acSart * => we may lock the pageq's. 79cd7ee8acSart */ 80cd7ee8acSart void 8139ee2284Sbeck uvm_anfree_list(struct vm_anon *anon, struct pglist *pgl) 82cd7ee8acSart { 8319dcab73Smpi struct vm_page *pg = anon->an_page; 84cd7ee8acSart 8519dcab73Smpi KASSERT(anon->an_lock == NULL || rw_write_held(anon->an_lock)); 8619dcab73Smpi KASSERT(anon->an_ref == 0); 87cd7ee8acSart 88cd7ee8acSart /* 8919dcab73Smpi * Dispose of the page, if it is resident. 90cd7ee8acSart */ 9119dcab73Smpi if (pg != NULL) { 9219dcab73Smpi KASSERT(anon->an_lock != NULL); 9319dcab73Smpi 94cd7ee8acSart /* 9552887a38Smpi * If the page is busy, mark it as PG_RELEASED, so 9652887a38Smpi * that uvm_anon_release(9) would release it later. 97cd7ee8acSart */ 989662fca4Sart if ((pg->pg_flags & PG_BUSY) != 0) { 9965d6360cSart atomic_setbits_int(&pg->pg_flags, PG_RELEASED); 10019dcab73Smpi rw_obj_hold(anon->an_lock); 101cd7ee8acSart return; 102cd7ee8acSart } 1031e8cdc2eSderaadt pmap_page_protect(pg, PROT_NONE); 10439ee2284Sbeck if (pgl != NULL) { 10539ee2284Sbeck /* 106b3af768dSjsg * clean page, and put it on pglist 10739ee2284Sbeck * for later freeing. 10839ee2284Sbeck */ 109d21d8ab4Smpi uvm_lock_pageq(); 11039ee2284Sbeck uvm_pageclean(pg); 111d21d8ab4Smpi uvm_unlock_pageq(); 11239ee2284Sbeck TAILQ_INSERT_HEAD(pgl, pg, pageq); 11339ee2284Sbeck } else { 114cd7ee8acSart uvm_lock_pageq(); /* lock out pagedaemon */ 115cd7ee8acSart uvm_pagefree(pg); /* bye bye */ 116cd7ee8acSart uvm_unlock_pageq(); /* free the daemon */ 117cd7ee8acSart } 11819dcab73Smpi } else { 119c3c0e069Smpi if (anon->an_swslot != 0 && anon->an_swslot != SWSLOT_BAD) { 120c4a864baSmpi /* This page is no longer only in swap. */ 1214ceac6c1Smiod KASSERT(uvmexp.swpgonly > 0); 122c4a864baSmpi atomic_dec_int(&uvmexp.swpgonly); 1234ceac6c1Smiod } 12419dcab73Smpi } 12519dcab73Smpi anon->an_lock = NULL; 126cd7ee8acSart 12752887a38Smpi /* 12852887a38Smpi * Free any swap resources, leave a page replacement hint. 12952887a38Smpi */ 1308a42ed70Sart uvm_anon_dropswap(anon); 131cd7ee8acSart 1328d0b5bafSpedro KASSERT(anon->an_page == NULL); 1338d0b5bafSpedro KASSERT(anon->an_swslot == 0); 1348d0b5bafSpedro 1358d0b5bafSpedro pool_put(&uvm_anon_pool, anon); 136cd7ee8acSart } 137cd7ee8acSart 138cd7ee8acSart /* 1394bfd0d76Sstefan * uvm_anwait: wait for memory to become available to allocate an anon. 1404bfd0d76Sstefan */ 1414bfd0d76Sstefan void 1424bfd0d76Sstefan uvm_anwait(void) 1434bfd0d76Sstefan { 1444bfd0d76Sstefan struct vm_anon *anon; 1454bfd0d76Sstefan 1464bfd0d76Sstefan /* XXX: Want something like pool_wait()? */ 1474bfd0d76Sstefan anon = pool_get(&uvm_anon_pool, PR_WAITOK); 1484bfd0d76Sstefan pool_put(&uvm_anon_pool, anon); 1494bfd0d76Sstefan } 1504bfd0d76Sstefan 1514bfd0d76Sstefan /* 15252887a38Smpi * uvm_anon_pagein: fetch an anon's page. 15328fbabcfSart * 15452887a38Smpi * => anon must be locked, and is unlocked upon return. 15552887a38Smpi * => returns true if pagein was aborted due to lack of memory. 15628fbabcfSart */ 15728fbabcfSart 1588d0b5bafSpedro boolean_t 15919dcab73Smpi uvm_anon_pagein(struct vm_amap *amap, struct vm_anon *anon) 16028fbabcfSart { 16128fbabcfSart struct vm_page *pg; 16228fbabcfSart int rv; 16328fbabcfSart 16419dcab73Smpi KASSERT(rw_write_held(anon->an_lock)); 16519dcab73Smpi KASSERT(anon->an_lock == amap->am_lock); 16619dcab73Smpi 16752887a38Smpi /* 16852887a38Smpi * Get the page of the anon. 16952887a38Smpi */ 17019dcab73Smpi rv = uvmfault_anonget(NULL, amap, anon); 17128fbabcfSart 17228fbabcfSart switch (rv) { 17334e43087Smpi case 0: 17434e43087Smpi /* Success - we have the page. */ 17519dcab73Smpi KASSERT(rw_write_held(anon->an_lock)); 17628fbabcfSart break; 17734e43087Smpi case EACCES: 17834e43087Smpi case ERESTART: 17928fbabcfSart /* 18034e43087Smpi * Nothing more to do on errors. ERESTART means that the 18134e43087Smpi * anon was freed. 18228fbabcfSart */ 18328fbabcfSart return FALSE; 1842c932f6fSmiod default: 1852c932f6fSmiod #ifdef DIAGNOSTIC 1862c932f6fSmiod panic("anon_pagein: uvmfault_anonget -> %d", rv); 1872c932f6fSmiod #else 1882c932f6fSmiod return FALSE; 1892c932f6fSmiod #endif 19028fbabcfSart } 19128fbabcfSart 19228fbabcfSart /* 19352887a38Smpi * Mark the page as dirty and clear its swslot. 19428fbabcfSart */ 1958d0b5bafSpedro pg = anon->an_page; 19619dcab73Smpi if (anon->an_swslot > 0) { 19728fbabcfSart uvm_swap_free(anon->an_swslot, 1); 19819dcab73Smpi } 19928fbabcfSart anon->an_swslot = 0; 20065d6360cSart atomic_clearbits_int(&pg->pg_flags, PG_CLEAN); 20128fbabcfSart 20252887a38Smpi /* 20352887a38Smpi * Deactivate the page (to put it on a page queue). 20452887a38Smpi */ 20528fbabcfSart uvm_lock_pageq(); 20628fbabcfSart uvm_pagedeactivate(pg); 20728fbabcfSart uvm_unlock_pageq(); 20819dcab73Smpi rw_exit(anon->an_lock); 20928fbabcfSart 21028fbabcfSart return FALSE; 21128fbabcfSart } 21219dcab73Smpi 21319dcab73Smpi /* 21419dcab73Smpi * uvm_anon_dropswap: release any swap resources from this anon. 21519dcab73Smpi * 21619dcab73Smpi * => anon must be locked or have a reference count of 0. 21719dcab73Smpi */ 21819dcab73Smpi void 21919dcab73Smpi uvm_anon_dropswap(struct vm_anon *anon) 22019dcab73Smpi { 22119dcab73Smpi KASSERT(anon->an_ref == 0 || rw_lock_held(anon->an_lock)); 22219dcab73Smpi 22319dcab73Smpi if (anon->an_swslot == 0) 22419dcab73Smpi return; 22519dcab73Smpi 22619dcab73Smpi uvm_swap_free(anon->an_swslot, 1); 22719dcab73Smpi anon->an_swslot = 0; 22819dcab73Smpi } 22919dcab73Smpi 23019dcab73Smpi 23119dcab73Smpi /* 23219dcab73Smpi * uvm_anon_release: release an anon and its page. 23319dcab73Smpi * 23419dcab73Smpi * => anon should not have any references. 23519dcab73Smpi * => anon must be locked. 23619dcab73Smpi */ 23719dcab73Smpi 23819dcab73Smpi void 23919dcab73Smpi uvm_anon_release(struct vm_anon *anon) 24019dcab73Smpi { 24119dcab73Smpi struct vm_page *pg = anon->an_page; 24219dcab73Smpi struct rwlock *lock; 24319dcab73Smpi 24419dcab73Smpi KASSERT(rw_write_held(anon->an_lock)); 24519dcab73Smpi KASSERT(pg != NULL); 24619dcab73Smpi KASSERT((pg->pg_flags & PG_RELEASED) != 0); 24719dcab73Smpi KASSERT((pg->pg_flags & PG_BUSY) != 0); 24819dcab73Smpi KASSERT(pg->uobject == NULL); 24919dcab73Smpi KASSERT(pg->uanon == anon); 25019dcab73Smpi KASSERT(anon->an_ref == 0); 25119dcab73Smpi 25219dcab73Smpi uvm_lock_pageq(); 2534dac787cSmpi pmap_page_protect(pg, PROT_NONE); 25419dcab73Smpi uvm_pagefree(pg); 25519dcab73Smpi uvm_unlock_pageq(); 25619dcab73Smpi KASSERT(anon->an_page == NULL); 25719dcab73Smpi lock = anon->an_lock; 2583087914dSmpi uvm_anon_dropswap(anon); 2593087914dSmpi pool_put(&uvm_anon_pool, anon); 26019dcab73Smpi rw_exit(lock); 26119dcab73Smpi /* Note: extra reference is held for PG_RELEASED case. */ 26219dcab73Smpi rw_obj_free(lock); 26319dcab73Smpi } 264