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

Annotation of sys/uvm/uvm_pglist.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: uvm_pglist.c,v 1.20 2007/04/13 18:57:49 art Exp $     */
        !             2: /*     $NetBSD: uvm_pglist.c,v 1.13 2001/02/18 21:19:08 chs Exp $      */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1997 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
        !            10:  * NASA Ames Research Center.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *      This product includes software developed by the NetBSD
        !            23:  *      Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: /*
        !            42:  * uvm_pglist.c: pglist functions
        !            43:  */
        !            44:
        !            45: #include <sys/param.h>
        !            46: #include <sys/systm.h>
        !            47: #include <sys/malloc.h>
        !            48: #include <sys/proc.h>
        !            49:
        !            50: #include <uvm/uvm.h>
        !            51:
        !            52: #ifdef VM_PAGE_ALLOC_MEMORY_STATS
        !            53: #define        STAT_INCR(v)    (v)++
        !            54: #define        STAT_DECR(v)    do { \
        !            55:                if ((v) == 0) \
        !            56:                        printf("%s:%d -- Already 0!\n", __FILE__, __LINE__); \
        !            57:                else \
        !            58:                        (v)--; \
        !            59:        } while (0)
        !            60: u_long uvm_pglistalloc_npages;
        !            61: #else
        !            62: #define        STAT_INCR(v)
        !            63: #define        STAT_DECR(v)
        !            64: #endif
        !            65:
        !            66: int    uvm_pglistalloc_simple(psize_t, paddr_t, paddr_t, struct pglist *);
        !            67:
        !            68: int
        !            69: uvm_pglistalloc_simple(psize_t size, paddr_t low, paddr_t high,
        !            70:     struct pglist *rlist)
        !            71: {
        !            72:        psize_t try;
        !            73:        int psi;
        !            74:        struct vm_page *pg;
        !            75:        int s, todo, idx, pgflidx, error, free_list;
        !            76:        UVMHIST_FUNC("uvm_pglistalloc_simple"); UVMHIST_CALLED(pghist);
        !            77: #ifdef DEBUG
        !            78:        vm_page_t tp;
        !            79: #endif
        !            80:
        !            81:        /* Default to "lose". */
        !            82:        error = ENOMEM;
        !            83:
        !            84:        todo = size / PAGE_SIZE;
        !            85:
        !            86:        /*
        !            87:         * Block all memory allocation and lock the free list.
        !            88:         */
        !            89:        s = uvm_lock_fpageq();
        !            90:
        !            91:        /* Are there even any free pages? */
        !            92:        if (uvmexp.free <= (uvmexp.reserve_pagedaemon + uvmexp.reserve_kernel))
        !            93:                goto out;
        !            94:
        !            95:        for (try = low; try < high; try += PAGE_SIZE) {
        !            96:
        !            97:                /*
        !            98:                 * Make sure this is a managed physical page.
        !            99:                 */
        !           100:
        !           101:                if ((psi = vm_physseg_find(atop(try), &idx)) == -1)
        !           102:                        continue; /* managed? */
        !           103:                pg = &vm_physmem[psi].pgs[idx];
        !           104:                if (VM_PAGE_IS_FREE(pg) == 0)
        !           105:                        continue;
        !           106:
        !           107:                free_list = uvm_page_lookup_freelist(pg);
        !           108:                pgflidx = (pg->pg_flags & PG_ZERO) ? PGFL_ZEROS : PGFL_UNKNOWN;
        !           109: #ifdef DEBUG
        !           110:                for (tp = TAILQ_FIRST(&uvm.page_free[free_list].pgfl_queues[pgflidx]);
        !           111:                     tp != NULL;
        !           112:                     tp = TAILQ_NEXT(tp, pageq)) {
        !           113:                        if (tp == pg)
        !           114:                                break;
        !           115:                }
        !           116:                if (tp == NULL)
        !           117:                        panic("uvm_pglistalloc_simple: page not on freelist");
        !           118: #endif
        !           119:                TAILQ_REMOVE(&uvm.page_free[free_list].pgfl_queues[pgflidx], pg, pageq);
        !           120:                uvmexp.free--;
        !           121:                if (pg->pg_flags & PG_ZERO)
        !           122:                        uvmexp.zeropages--;
        !           123:                pg->pg_flags = PG_CLEAN;
        !           124:                pg->uobject = NULL;
        !           125:                pg->uanon = NULL;
        !           126:                pg->pg_version++;
        !           127:                TAILQ_INSERT_TAIL(rlist, pg, pageq);
        !           128:                STAT_INCR(uvm_pglistalloc_npages);
        !           129:                if (--todo == 0) {
        !           130:                        error = 0;
        !           131:                        goto out;
        !           132:                }
        !           133:        }
        !           134:
        !           135: out:
        !           136:        /*
        !           137:         * check to see if we need to generate some free pages waking
        !           138:         * the pagedaemon.
        !           139:         */
        !           140:
        !           141:        if (!error && (uvmexp.free + uvmexp.paging < uvmexp.freemin ||
        !           142:            (uvmexp.free + uvmexp.paging < uvmexp.freetarg &&
        !           143:            uvmexp.inactive < uvmexp.inactarg))) {
        !           144:                wakeup(&uvm.pagedaemon);
        !           145:        }
        !           146:
        !           147:        uvm_unlock_fpageq(s);
        !           148:
        !           149:        if (error)
        !           150:                uvm_pglistfree(rlist);
        !           151:
        !           152:        return (error);
        !           153: }
        !           154:
        !           155: /*
        !           156:  * uvm_pglistalloc: allocate a list of pages
        !           157:  *
        !           158:  * => allocated pages are placed at the tail of rlist.  rlist is
        !           159:  *    assumed to be properly initialized by caller.
        !           160:  * => returns 0 on success or errno on failure
        !           161:  * => XXX: implementation allocates only a single segment, also
        !           162:  *     might be able to better advantage of vm_physeg[].
        !           163:  * => doesn't take into account clean non-busy pages on inactive list
        !           164:  *     that could be used(?)
        !           165:  * => params:
        !           166:  *     size            the size of the allocation, rounded to page size.
        !           167:  *     low             the low address of the allowed allocation range.
        !           168:  *     high            the high address of the allowed allocation range.
        !           169:  *     alignment       memory must be aligned to this power-of-two boundary.
        !           170:  *     boundary        no segment in the allocation may cross this
        !           171:  *                     power-of-two boundary (relative to zero).
        !           172:  */
        !           173:
        !           174: int
        !           175: uvm_pglistalloc(size, low, high, alignment, boundary, rlist, nsegs, waitok)
        !           176:        psize_t size;
        !           177:        paddr_t low, high, alignment, boundary;
        !           178:        struct pglist *rlist;
        !           179:        int nsegs, waitok;
        !           180: {
        !           181:        paddr_t try, idxpa, lastidxpa;
        !           182:        int psi;
        !           183:        struct vm_page *pgs;
        !           184:        int s, tryidx, idx, pgflidx, end, error, free_list;
        !           185:        vm_page_t m;
        !           186:        u_long pagemask;
        !           187: #ifdef DEBUG
        !           188:        vm_page_t tp;
        !           189: #endif
        !           190:        UVMHIST_FUNC("uvm_pglistalloc"); UVMHIST_CALLED(pghist);
        !           191:
        !           192:        KASSERT((alignment & (alignment - 1)) == 0);
        !           193:        KASSERT((boundary & (boundary - 1)) == 0);
        !           194:
        !           195:        /*
        !           196:         * Our allocations are always page granularity, so our alignment
        !           197:         * must be, too.
        !           198:         */
        !           199:        if (alignment < PAGE_SIZE)
        !           200:                alignment = PAGE_SIZE;
        !           201:
        !           202:        if (size == 0)
        !           203:                return (EINVAL);
        !           204:
        !           205:        size = round_page(size);
        !           206:        try = roundup(low, alignment);
        !           207:
        !           208:        if ((nsegs >= size / PAGE_SIZE) && (alignment == PAGE_SIZE) &&
        !           209:            (boundary == 0))
        !           210:                return (uvm_pglistalloc_simple(size, try, high, rlist));
        !           211:
        !           212:        if (boundary != 0 && boundary < size)
        !           213:                return (EINVAL);
        !           214:
        !           215:        pagemask = ~(boundary - 1);
        !           216:
        !           217:        /* Default to "lose". */
        !           218:        error = ENOMEM;
        !           219:
        !           220:        /*
        !           221:         * Block all memory allocation and lock the free list.
        !           222:         */
        !           223:        s = uvm_lock_fpageq();
        !           224:
        !           225:        /* Are there even any free pages? */
        !           226:        if (uvmexp.free <= (uvmexp.reserve_pagedaemon + uvmexp.reserve_kernel))
        !           227:                goto out;
        !           228:
        !           229:        for (;; try += alignment) {
        !           230:                if (try + size > high) {
        !           231:
        !           232:                        /*
        !           233:                         * We've run past the allowable range.
        !           234:                         */
        !           235:
        !           236:                        goto out;
        !           237:                }
        !           238:
        !           239:                /*
        !           240:                 * Make sure this is a managed physical page.
        !           241:                 */
        !           242:
        !           243:                if ((psi = vm_physseg_find(atop(try), &idx)) == -1)
        !           244:                        continue; /* managed? */
        !           245:                if (vm_physseg_find(atop(try + size), NULL) != psi)
        !           246:                        continue; /* end must be in this segment */
        !           247:
        !           248:                tryidx = idx;
        !           249:                end = idx + (size / PAGE_SIZE);
        !           250:                pgs = vm_physmem[psi].pgs;
        !           251:
        !           252:                /*
        !           253:                 * Found a suitable starting page.  See of the range is free.
        !           254:                 */
        !           255:
        !           256:                for (; idx < end; idx++) {
        !           257:                        if (VM_PAGE_IS_FREE(&pgs[idx]) == 0) {
        !           258:                                break;
        !           259:                        }
        !           260:                        idxpa = VM_PAGE_TO_PHYS(&pgs[idx]);
        !           261:                        if (idx > tryidx) {
        !           262:                                lastidxpa = VM_PAGE_TO_PHYS(&pgs[idx - 1]);
        !           263:                                if ((lastidxpa + PAGE_SIZE) != idxpa) {
        !           264:
        !           265:                                        /*
        !           266:                                         * Region not contiguous.
        !           267:                                         */
        !           268:
        !           269:                                        break;
        !           270:                                }
        !           271:                                if (boundary != 0 &&
        !           272:                                    ((lastidxpa ^ idxpa) & pagemask) != 0) {
        !           273:
        !           274:                                        /*
        !           275:                                         * Region crosses boundary.
        !           276:                                         */
        !           277:
        !           278:                                        break;
        !           279:                                }
        !           280:                        }
        !           281:                }
        !           282:                if (idx == end) {
        !           283:                        break;
        !           284:                }
        !           285:        }
        !           286:
        !           287: #if PGFL_NQUEUES != 2
        !           288: #error uvm_pglistalloc needs to be updated
        !           289: #endif
        !           290:
        !           291:        /*
        !           292:         * we have a chunk of memory that conforms to the requested constraints.
        !           293:         */
        !           294:        idx = tryidx;
        !           295:        while (idx < end) {
        !           296:                m = &pgs[idx];
        !           297:                free_list = uvm_page_lookup_freelist(m);
        !           298:                pgflidx = (m->pg_flags & PG_ZERO) ? PGFL_ZEROS : PGFL_UNKNOWN;
        !           299: #ifdef DEBUG
        !           300:                for (tp = TAILQ_FIRST(&uvm.page_free[
        !           301:                        free_list].pgfl_queues[pgflidx]);
        !           302:                     tp != NULL;
        !           303:                     tp = TAILQ_NEXT(tp, pageq)) {
        !           304:                        if (tp == m)
        !           305:                                break;
        !           306:                }
        !           307:                if (tp == NULL)
        !           308:                        panic("uvm_pglistalloc: page not on freelist");
        !           309: #endif
        !           310:                TAILQ_REMOVE(&uvm.page_free[free_list].pgfl_queues[pgflidx],
        !           311:                    m, pageq);
        !           312:                uvmexp.free--;
        !           313:                if (m->pg_flags & PG_ZERO)
        !           314:                        uvmexp.zeropages--;
        !           315:                m->pg_flags = PG_CLEAN;
        !           316:                m->uobject = NULL;
        !           317:                m->uanon = NULL;
        !           318:                m->pg_version++;
        !           319:                TAILQ_INSERT_TAIL(rlist, m, pageq);
        !           320:                idx++;
        !           321:                STAT_INCR(uvm_pglistalloc_npages);
        !           322:        }
        !           323:        error = 0;
        !           324:
        !           325: out:
        !           326:        /*
        !           327:         * check to see if we need to generate some free pages waking
        !           328:         * the pagedaemon.
        !           329:         */
        !           330:
        !           331:        if (uvmexp.free + uvmexp.paging < uvmexp.freemin ||
        !           332:            (uvmexp.free + uvmexp.paging < uvmexp.freetarg &&
        !           333:             uvmexp.inactive < uvmexp.inactarg)) {
        !           334:                wakeup(&uvm.pagedaemon);
        !           335:        }
        !           336:
        !           337:        uvm_unlock_fpageq(s);
        !           338:
        !           339:        return (error);
        !           340: }
        !           341:
        !           342: /*
        !           343:  * uvm_pglistfree: free a list of pages
        !           344:  *
        !           345:  * => pages should already be unmapped
        !           346:  */
        !           347:
        !           348: void
        !           349: uvm_pglistfree(struct pglist *list)
        !           350: {
        !           351:        struct vm_page *m;
        !           352:        int s;
        !           353:        UVMHIST_FUNC("uvm_pglistfree"); UVMHIST_CALLED(pghist);
        !           354:
        !           355:        /*
        !           356:         * Block all memory allocation and lock the free list.
        !           357:         */
        !           358:        s = uvm_lock_fpageq();
        !           359:
        !           360:        while ((m = TAILQ_FIRST(list)) != NULL) {
        !           361:                KASSERT((m->pg_flags & (PQ_ACTIVE|PQ_INACTIVE)) == 0);
        !           362:                TAILQ_REMOVE(list, m, pageq);
        !           363: #ifdef DEBUG
        !           364:                if (m->uobject == (void *)0xdeadbeef &&
        !           365:                    m->uanon == (void *)0xdeadbeef) {
        !           366:                        panic("uvm_pagefree: freeing free page %p", m);
        !           367:                }
        !           368:
        !           369:                m->uobject = (void *)0xdeadbeef;
        !           370:                m->offset = 0xdeadbeef;
        !           371:                m->uanon = (void *)0xdeadbeef;
        !           372: #endif
        !           373:                atomic_clearbits_int(&m->pg_flags, PQ_MASK);
        !           374:                atomic_setbits_int(&m->pg_flags, PQ_FREE);
        !           375:                TAILQ_INSERT_TAIL(&uvm.page_free[
        !           376:                    uvm_page_lookup_freelist(m)].pgfl_queues[PGFL_UNKNOWN],
        !           377:                    m, pageq);
        !           378:                uvmexp.free++;
        !           379:                if (uvmexp.zeropages < UVM_PAGEZERO_TARGET)
        !           380:                        uvm.page_idle_zero = vm_page_zero_enable;
        !           381:                STAT_DECR(uvm_pglistalloc_npages);
        !           382:        }
        !           383:
        !           384:        uvm_unlock_fpageq(s);
        !           385: }

CVSweb