Annotation of sys/uvm/uvm_anon.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uvm_anon.c,v 1.28 2007/06/18 21:51:15 pedro Exp $ */
! 2: /* $NetBSD: uvm_anon.c,v 1.10 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_anon.c: uvm anon ops
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/proc.h>
! 43: #include <sys/malloc.h>
! 44: #include <sys/pool.h>
! 45: #include <sys/kernel.h>
! 46:
! 47: #include <uvm/uvm.h>
! 48: #include <uvm/uvm_swap.h>
! 49:
! 50: struct pool uvm_anon_pool;
! 51:
! 52: /*
! 53: * allocate anons
! 54: */
! 55: void
! 56: uvm_anon_init()
! 57: {
! 58: pool_init(&uvm_anon_pool, sizeof(struct vm_anon), 0, 0, 0, "anonpl",
! 59: &pool_allocator_nointr);
! 60: pool_sethiwat(&uvm_anon_pool, uvmexp.free / 16);
! 61: }
! 62:
! 63: /*
! 64: * allocate an anon
! 65: */
! 66: struct vm_anon *
! 67: uvm_analloc()
! 68: {
! 69: struct vm_anon *anon;
! 70:
! 71: anon = pool_get(&uvm_anon_pool, PR_NOWAIT);
! 72: if (anon) {
! 73: simple_lock_init(&anon->an_lock);
! 74: anon->an_ref = 1;
! 75: anon->an_page = NULL;
! 76: anon->an_swslot = 0;
! 77: simple_lock(&anon->an_lock);
! 78: }
! 79: return(anon);
! 80: }
! 81:
! 82: /*
! 83: * uvm_anfree: free a single anon structure
! 84: *
! 85: * => caller must remove anon from its amap before calling (if it was in
! 86: * an amap).
! 87: * => anon must be unlocked and have a zero reference count.
! 88: * => we may lock the pageq's.
! 89: */
! 90: void
! 91: uvm_anfree(anon)
! 92: struct vm_anon *anon;
! 93: {
! 94: struct vm_page *pg;
! 95: UVMHIST_FUNC("uvm_anfree"); UVMHIST_CALLED(maphist);
! 96: UVMHIST_LOG(maphist,"(anon=%p)", anon, 0,0,0);
! 97:
! 98: /*
! 99: * get page
! 100: */
! 101:
! 102: pg = anon->an_page;
! 103:
! 104: /*
! 105: * if there is a resident page and it is loaned, then anon may not
! 106: * own it. call out to uvm_anon_lockpage() to ensure the real owner
! 107: * of the page has been identified and locked.
! 108: */
! 109:
! 110: if (pg && pg->loan_count)
! 111: pg = uvm_anon_lockloanpg(anon);
! 112:
! 113: /*
! 114: * if we have a resident page, we must dispose of it before freeing
! 115: * the anon.
! 116: */
! 117:
! 118: if (pg) {
! 119:
! 120: /*
! 121: * if the page is owned by a uobject (now locked), then we must
! 122: * kill the loan on the page rather than free it.
! 123: */
! 124:
! 125: if (pg->uobject) {
! 126: uvm_lock_pageq();
! 127: KASSERT(pg->loan_count > 0);
! 128: pg->loan_count--;
! 129: pg->uanon = NULL;
! 130: uvm_unlock_pageq();
! 131: simple_unlock(&pg->uobject->vmobjlock);
! 132: } else {
! 133:
! 134: /*
! 135: * page has no uobject, so we must be the owner of it.
! 136: *
! 137: * if page is busy then we just mark it as released
! 138: * (who ever has it busy must check for this when they
! 139: * wake up). if the page is not busy then we can
! 140: * free it now.
! 141: */
! 142:
! 143: if ((pg->pg_flags & PG_BUSY) != 0) {
! 144: /* tell them to dump it when done */
! 145: atomic_setbits_int(&pg->pg_flags, PG_RELEASED);
! 146: UVMHIST_LOG(maphist,
! 147: " anon %p, page %p: BUSY (released!)",
! 148: anon, pg, 0, 0);
! 149: return;
! 150: }
! 151: pmap_page_protect(pg, VM_PROT_NONE);
! 152: uvm_lock_pageq(); /* lock out pagedaemon */
! 153: uvm_pagefree(pg); /* bye bye */
! 154: uvm_unlock_pageq(); /* free the daemon */
! 155: UVMHIST_LOG(maphist,"anon %p, page %p: freed now!",
! 156: anon, pg, 0, 0);
! 157: }
! 158: }
! 159:
! 160: /*
! 161: * free any swap resources.
! 162: */
! 163: uvm_anon_dropswap(anon);
! 164:
! 165: /*
! 166: * now that we've stripped the data areas from the anon, free the anon
! 167: * itself!
! 168: */
! 169: KASSERT(anon->an_page == NULL);
! 170: KASSERT(anon->an_swslot == 0);
! 171:
! 172: pool_put(&uvm_anon_pool, anon);
! 173: UVMHIST_LOG(maphist,"<- done!",0,0,0,0);
! 174: }
! 175:
! 176: /*
! 177: * uvm_anon_dropswap: release any swap resources from this anon.
! 178: *
! 179: * => anon must be locked or have a reference count of 0.
! 180: */
! 181: void
! 182: uvm_anon_dropswap(anon)
! 183: struct vm_anon *anon;
! 184: {
! 185: UVMHIST_FUNC("uvm_anon_dropswap"); UVMHIST_CALLED(maphist);
! 186:
! 187: if (anon->an_swslot == 0)
! 188: return;
! 189:
! 190: UVMHIST_LOG(maphist,"freeing swap for anon %p, paged to swslot 0x%lx",
! 191: anon, anon->an_swslot, 0, 0);
! 192: uvm_swap_free(anon->an_swslot, 1);
! 193: anon->an_swslot = 0;
! 194:
! 195: if (anon->an_page == NULL) {
! 196: /* this page is no longer only in swap. */
! 197: simple_lock(&uvm.swap_data_lock);
! 198: uvmexp.swpgonly--;
! 199: simple_unlock(&uvm.swap_data_lock);
! 200: }
! 201: }
! 202:
! 203: /*
! 204: * uvm_anon_lockloanpg: given a locked anon, lock its resident page
! 205: *
! 206: * => anon is locked by caller
! 207: * => on return: anon is locked
! 208: * if there is a resident page:
! 209: * if it has a uobject, it is locked by us
! 210: * if it is ownerless, we take over as owner
! 211: * we return the resident page (it can change during
! 212: * this function)
! 213: * => note that the only time an anon has an ownerless resident page
! 214: * is if the page was loaned from a uvm_object and the uvm_object
! 215: * disowned it
! 216: * => this only needs to be called when you want to do an operation
! 217: * on an anon's resident page and that page has a non-zero loan
! 218: * count.
! 219: */
! 220: struct vm_page *
! 221: uvm_anon_lockloanpg(anon)
! 222: struct vm_anon *anon;
! 223: {
! 224: struct vm_page *pg;
! 225: boolean_t locked = FALSE;
! 226:
! 227: /*
! 228: * loop while we have a resident page that has a non-zero loan count.
! 229: * if we successfully get our lock, we will "break" the loop.
! 230: * note that the test for pg->loan_count is not protected -- this
! 231: * may produce false positive results. note that a false positive
! 232: * result may cause us to do more work than we need to, but it will
! 233: * not produce an incorrect result.
! 234: */
! 235:
! 236: while (((pg = anon->an_page) != NULL) && pg->loan_count != 0) {
! 237:
! 238: /*
! 239: * quickly check to see if the page has an object before
! 240: * bothering to lock the page queues. this may also produce
! 241: * a false positive result, but that's ok because we do a real
! 242: * check after that.
! 243: *
! 244: * XXX: quick check -- worth it? need volatile?
! 245: */
! 246:
! 247: if (pg->uobject) {
! 248:
! 249: uvm_lock_pageq();
! 250: if (pg->uobject) { /* the "real" check */
! 251: locked =
! 252: simple_lock_try(&pg->uobject->vmobjlock);
! 253: } else {
! 254: /* object disowned before we got PQ lock */
! 255: locked = TRUE;
! 256: }
! 257: uvm_unlock_pageq();
! 258:
! 259: /*
! 260: * if we didn't get a lock (try lock failed), then we
! 261: * toggle our anon lock and try again
! 262: */
! 263:
! 264: if (!locked) {
! 265: simple_unlock(&anon->an_lock);
! 266:
! 267: /*
! 268: * someone locking the object has a chance to
! 269: * lock us right now
! 270: */
! 271:
! 272: simple_lock(&anon->an_lock);
! 273: continue;
! 274: }
! 275: }
! 276:
! 277: /*
! 278: * if page is un-owned [i.e. the object dropped its ownership],
! 279: * then we can take over as owner!
! 280: */
! 281:
! 282: if (pg->uobject == NULL && (pg->pg_flags & PQ_ANON) == 0) {
! 283: uvm_lock_pageq();
! 284: atomic_setbits_int(&pg->pg_flags, PQ_ANON);
! 285: pg->loan_count--; /* ... and drop our loan */
! 286: uvm_unlock_pageq();
! 287: }
! 288:
! 289: /*
! 290: * we did it! break the loop
! 291: */
! 292:
! 293: break;
! 294: }
! 295: return(pg);
! 296: }
! 297:
! 298: /*
! 299: * fetch an anon's page.
! 300: *
! 301: * => anon must be locked, and is unlocked upon return.
! 302: * => returns TRUE if pagein was aborted due to lack of memory.
! 303: */
! 304:
! 305: boolean_t
! 306: uvm_anon_pagein(anon)
! 307: struct vm_anon *anon;
! 308: {
! 309: struct vm_page *pg;
! 310: struct uvm_object *uobj;
! 311: int rv;
! 312:
! 313: /* locked: anon */
! 314: rv = uvmfault_anonget(NULL, NULL, anon);
! 315: /*
! 316: * if rv == VM_PAGER_OK, anon is still locked, else anon
! 317: * is unlocked
! 318: */
! 319:
! 320: switch (rv) {
! 321: case VM_PAGER_OK:
! 322: break;
! 323:
! 324: case VM_PAGER_ERROR:
! 325: case VM_PAGER_REFAULT:
! 326:
! 327: /*
! 328: * nothing more to do on errors.
! 329: * VM_PAGER_REFAULT can only mean that the anon was freed,
! 330: * so again there's nothing to do.
! 331: */
! 332:
! 333: return FALSE;
! 334:
! 335: default:
! 336: #ifdef DIAGNOSTIC
! 337: panic("anon_pagein: uvmfault_anonget -> %d", rv);
! 338: #else
! 339: return FALSE;
! 340: #endif
! 341: }
! 342:
! 343: /*
! 344: * ok, we've got the page now.
! 345: * mark it as dirty, clear its swslot and un-busy it.
! 346: */
! 347:
! 348: pg = anon->an_page;
! 349: uobj = pg->uobject;
! 350: uvm_swap_free(anon->an_swslot, 1);
! 351: anon->an_swslot = 0;
! 352: atomic_clearbits_int(&pg->pg_flags, PG_CLEAN);
! 353:
! 354: /*
! 355: * deactivate the page (to put it on a page queue)
! 356: */
! 357:
! 358: pmap_clear_reference(pg);
! 359: pmap_page_protect(pg, VM_PROT_NONE);
! 360: uvm_lock_pageq();
! 361: uvm_pagedeactivate(pg);
! 362: uvm_unlock_pageq();
! 363:
! 364: /*
! 365: * unlock the anon and we're done.
! 366: */
! 367:
! 368: simple_unlock(&anon->an_lock);
! 369: if (uobj) {
! 370: simple_unlock(&uobj->vmobjlock);
! 371: }
! 372: return FALSE;
! 373: }
CVSweb