[BACK]Return to uvm_anon.c CVS log [TXT][DIR] Up to [local] / sys / uvm

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