Annotation of 43BSDReno/sys/kern/subr_rmap.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986 Regents of the University of California.
        !             3:  * All rights reserved.  The Berkeley software License Agreement
        !             4:  * specifies the terms and conditions for redistribution.
        !             5:  *
        !             6:  *     @(#)subr_rmap.c 7.4 (Berkeley) 5/15/90
        !             7:  */
        !             8: 
        !             9: #include "param.h"
        !            10: #include "systm.h"
        !            11: #include "map.h"
        !            12: #include "user.h"
        !            13: #include "proc.h"
        !            14: #include "text.h"
        !            15: #include "kernel.h"
        !            16: 
        !            17: /*
        !            18:  * Resource map handling routines.
        !            19:  *
        !            20:  * A resource map is an array of structures each
        !            21:  * of which describes a segment of the address space of an available
        !            22:  * resource.  The segments are described by their base address and
        !            23:  * length, and sorted in address order.  Each resource map has a fixed
        !            24:  * maximum number of segments allowed.  Resources are allocated
        !            25:  * by taking part or all of one of the segments of the map.
        !            26:  *
        !            27:  * Returning of resources will require another segment if
        !            28:  * the returned resources are not adjacent in the address
        !            29:  * space to an existing segment.  If the return of a segment
        !            30:  * would require a slot which is not available, then one of
        !            31:  * the resource map segments is discarded after a warning is printed.
        !            32:  * Returning of resources may also cause the map to collapse
        !            33:  * by coalescing two existing segments and the returned space
        !            34:  * into a single segment.  In this case the resource map is
        !            35:  * made smaller by copying together to fill the resultant gap.
        !            36:  *
        !            37:  * N.B.: the current implementation uses a dense array and does
        !            38:  * not admit the value ``0'' as a legal address, since that is used
        !            39:  * as a delimiter.
        !            40:  */
        !            41: 
        !            42: /*
        !            43:  * Initialize map mp to have (mapsize-2) segments
        !            44:  * and to be called ``name'', which we print if
        !            45:  * the slots become so fragmented that we lose space.
        !            46:  * The map itself is initialized with size elements free
        !            47:  * starting at addr.
        !            48:  */
        !            49: rminit(mp, size, addr, name, mapsize)
        !            50:        register struct map *mp;
        !            51:        long size, addr;
        !            52:        char *name;
        !            53:        int mapsize;
        !            54: {
        !            55:        register struct mapent *ep = (struct mapent *)(mp+1);
        !            56: 
        !            57:        mp->m_name = name;
        !            58: /* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */
        !            59:        /*
        !            60:         * One of the mapsize slots is taken by the map structure,
        !            61:         * segments has size 0 and addr 0, and acts as a delimiter.
        !            62:         * We insure that we never use segments past the end of
        !            63:         * the array which is given by mp->m_limit.
        !            64:         * Instead, when excess segments occur we discard some resources.
        !            65:         */
        !            66:        mp->m_limit = (struct mapent *)&mp[mapsize];
        !            67:        /*
        !            68:         * Simulate a rmfree(), but with the option to
        !            69:         * call with size 0 and addr 0 when we just want
        !            70:         * to initialize without freeing.
        !            71:         */
        !            72:        ep->m_size = size;
        !            73:        ep->m_addr = addr;
        !            74:        (++ep)->m_size = 0;
        !            75:        ep->m_addr = 0;
        !            76: }
        !            77: 
        !            78: /*
        !            79:  * Allocate 'size' units from the given
        !            80:  * map. Return the base of the allocated space.
        !            81:  * In a map, the addresses are increasing and the
        !            82:  * list is terminated by a 0 size.
        !            83:  *
        !            84:  * Algorithm is first-fit.
        !            85:  *
        !            86:  * This routine knows about the interleaving of the swapmap
        !            87:  * and handles that.
        !            88:  */
        !            89: long
        !            90: rmalloc(mp, size)
        !            91:        register struct map *mp;
        !            92:        long size;
        !            93: {
        !            94:        register struct mapent *ep = (struct mapent *)(mp+1);
        !            95:        register int addr;
        !            96:        register struct mapent *bp;
        !            97:        swblk_t first, rest;
        !            98: 
        !            99:        if (size <= 0 || mp == swapmap && size > dmmax)
        !           100:                panic("rmalloc");
        !           101:        /*
        !           102:         * Search for a piece of the resource map which has enough
        !           103:         * free space to accomodate the request.
        !           104:         */
        !           105:        for (bp = ep; bp->m_size; bp++) {
        !           106:                if (bp->m_size >= size) {
        !           107:                        /*
        !           108:                         * If allocating from swapmap,
        !           109:                         * then have to respect interleaving
        !           110:                         * boundaries.
        !           111:                         */
        !           112:                        if (mp == swapmap && nswdev > 1 &&
        !           113:                            (first = dmmax - bp->m_addr%dmmax) < size) {
        !           114:                                if (bp->m_size - first < size)
        !           115:                                        continue;
        !           116:                                addr = bp->m_addr + first;
        !           117:                                rest = bp->m_size - first - size;
        !           118:                                bp->m_size = first;
        !           119:                                if (rest)
        !           120:                                        rmfree(swapmap, rest, addr+size);
        !           121:                                return (addr);
        !           122:                        }
        !           123:                        /*
        !           124:                         * Allocate from the map.
        !           125:                         * If there is no space left of the piece
        !           126:                         * we allocated from, move the rest of
        !           127:                         * the pieces to the left.
        !           128:                         */
        !           129:                        addr = bp->m_addr;
        !           130:                        bp->m_addr += size;
        !           131:                        if ((bp->m_size -= size) == 0) {
        !           132:                                do {
        !           133:                                        bp++;
        !           134:                                        (bp-1)->m_addr = bp->m_addr;
        !           135:                                } while ((bp-1)->m_size = bp->m_size);
        !           136:                        }
        !           137:                        if (mp == swapmap && addr % CLSIZE)
        !           138:                                panic("rmalloc swapmap");
        !           139:                        return (addr);
        !           140:                }
        !           141:        }
        !           142:        return (0);
        !           143: }
        !           144: 
        !           145: /*
        !           146:  * Free the previously allocated space at addr
        !           147:  * of size units into the specified map.
        !           148:  * Sort addr into map and combine on
        !           149:  * one or both ends if possible.
        !           150:  */
        !           151: rmfree(mp, size, addr)
        !           152:        struct map *mp;
        !           153:        long size, addr;
        !           154: {
        !           155:        struct mapent *firstbp;
        !           156:        register struct mapent *bp;
        !           157:        register int t;
        !           158: 
        !           159:        /*
        !           160:         * Both address and size must be
        !           161:         * positive, or the protocol has broken down.
        !           162:         */
        !           163:        if (addr <= 0 || size <= 0)
        !           164:                goto badrmfree;
        !           165:        /*
        !           166:         * Locate the piece of the map which starts after the
        !           167:         * returned space (or the end of the map).
        !           168:         */
        !           169:        firstbp = bp = (struct mapent *)(mp + 1);
        !           170:        for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
        !           171:                continue;
        !           172:        /*
        !           173:         * If the piece on the left abuts us,
        !           174:         * then we should combine with it.
        !           175:         */
        !           176:        if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
        !           177:                /*
        !           178:                 * Check no overlap (internal error).
        !           179:                 */
        !           180:                if ((bp-1)->m_addr+(bp-1)->m_size > addr)
        !           181:                        goto badrmfree;
        !           182:                /*
        !           183:                 * Add into piece on the left by increasing its size.
        !           184:                 */
        !           185:                (bp-1)->m_size += size;
        !           186:                /*
        !           187:                 * If the combined piece abuts the piece on
        !           188:                 * the right now, compress it in also,
        !           189:                 * by shifting the remaining pieces of the map over.
        !           190:                 */
        !           191:                if (bp->m_addr && addr+size >= bp->m_addr) {
        !           192:                        if (addr+size > bp->m_addr)
        !           193:                                goto badrmfree;
        !           194:                        (bp-1)->m_size += bp->m_size;
        !           195:                        while (bp->m_size) {
        !           196:                                bp++;
        !           197:                                (bp-1)->m_addr = bp->m_addr;
        !           198:                                (bp-1)->m_size = bp->m_size;
        !           199:                        }
        !           200:                }
        !           201:                goto done;
        !           202:        }
        !           203:        /*
        !           204:         * Don't abut on the left, check for abutting on
        !           205:         * the right.
        !           206:         */
        !           207:        if (addr+size >= bp->m_addr && bp->m_size) {
        !           208:                if (addr+size > bp->m_addr)
        !           209:                        goto badrmfree;
        !           210:                bp->m_addr -= size;
        !           211:                bp->m_size += size;
        !           212:                goto done;
        !           213:        }
        !           214:        /*
        !           215:         * Don't abut at all.  Make a new entry
        !           216:         * and check for map overflow.
        !           217:         */
        !           218:        do {
        !           219:                t = bp->m_addr;
        !           220:                bp->m_addr = addr;
        !           221:                addr = t;
        !           222:                t = bp->m_size;
        !           223:                bp->m_size = size;
        !           224:                bp++;
        !           225:        } while (size = t);
        !           226:        /*
        !           227:         * Segment at bp is to be the delimiter;
        !           228:         * If there is not room for it 
        !           229:         * then the table is too full
        !           230:         * and we must discard something.
        !           231:         */
        !           232:        if (bp+1 > mp->m_limit) {
        !           233:                /*
        !           234:                 * Back bp up to last available segment.
        !           235:                 * which contains a segment already and must
        !           236:                 * be made into the delimiter.
        !           237:                 * Discard second to last entry,
        !           238:                 * since it is presumably smaller than the last
        !           239:                 * and move the last entry back one.
        !           240:                 */
        !           241:                bp--;
        !           242:                printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name,
        !           243:                    (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
        !           244:                bp[-1] = bp[0];
        !           245:                bp[0].m_size = bp[0].m_addr = 0;
        !           246:        }
        !           247: done:
        !           248:        /*
        !           249:         * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE!
        !           250:         */
        !           251:        if ((mp == kernelmap) && kmapwnt) {
        !           252:                kmapwnt = 0;
        !           253:                wakeup((caddr_t)kernelmap);
        !           254:        }
        !           255:        return;
        !           256: badrmfree:
        !           257:        panic("bad rmfree");
        !           258: }
        !           259: 
        !           260: /*
        !           261:  * Allocate 'size' units from the given map, starting at address 'addr'.
        !           262:  * Return 'addr' if successful, 0 if not.
        !           263:  * This may cause the creation or destruction of a resource map segment.
        !           264:  *
        !           265:  * This routine will return failure status if there is not enough room
        !           266:  * for a required additional map segment.
        !           267:  *
        !           268:  * An attempt to use this on 'swapmap' will result in
        !           269:  * a failure return.  This is due mainly to laziness and could be fixed
        !           270:  * to do the right thing, although it probably will never be used.
        !           271:  */
        !           272: rmget(mp, size, addr)
        !           273:        register struct map *mp;
        !           274: {
        !           275:        register struct mapent *ep = (struct mapent *)(mp+1);
        !           276:        register struct mapent *bp, *bp2;
        !           277: 
        !           278:        if (size <= 0)
        !           279:                panic("rmget");
        !           280:        if (mp == swapmap)
        !           281:                return (0);
        !           282:        /*
        !           283:         * Look for a map segment containing the requested address.
        !           284:         * If none found, return failure.
        !           285:         */
        !           286:        for (bp = ep; bp->m_size; bp++)
        !           287:                if (bp->m_addr <= addr && bp->m_addr + bp->m_size > addr)
        !           288:                        break;
        !           289:        if (bp->m_size == 0)
        !           290:                return (0);
        !           291: 
        !           292:        /*
        !           293:         * If segment is too small, return failure.
        !           294:         * If big enough, allocate the block, compressing or expanding
        !           295:         * the map as necessary.
        !           296:         */
        !           297:        if (bp->m_addr + bp->m_size < addr + size)
        !           298:                return (0);
        !           299:        if (bp->m_addr == addr)
        !           300:                if (bp->m_addr + bp->m_size == addr + size) {
        !           301:                        /*
        !           302:                         * Allocate entire segment and compress map
        !           303:                         */
        !           304:                        bp2 = bp;
        !           305:                        while (bp2->m_size) {
        !           306:                                bp2++;
        !           307:                                (bp2-1)->m_addr = bp2->m_addr;
        !           308:                                (bp2-1)->m_size = bp2->m_size;
        !           309:                        }
        !           310:                } else {
        !           311:                        /*
        !           312:                         * Allocate first part of segment
        !           313:                         */
        !           314:                        bp->m_addr += size;
        !           315:                        bp->m_size -= size;
        !           316:                }
        !           317:        else
        !           318:                if (bp->m_addr + bp->m_size == addr + size) {
        !           319:                        /*
        !           320:                         * Allocate last part of segment
        !           321:                         */
        !           322:                        bp->m_size -= size;
        !           323:                } else {
        !           324:                        /*
        !           325:                         * Allocate from middle of segment, but only
        !           326:                         * if table can be expanded.
        !           327:                         */
        !           328:                        for (bp2=bp; bp2->m_size; bp2++)
        !           329:                                ;
        !           330:                        if (bp2 + 1 >= mp->m_limit)
        !           331:                                return (0);
        !           332:                        while (bp2 > bp) {
        !           333:                                (bp2+1)->m_addr = bp2->m_addr;
        !           334:                                (bp2+1)->m_size = bp2->m_size;
        !           335:                                bp2--;
        !           336:                        }
        !           337:                        (bp+1)->m_addr = addr + size;
        !           338:                        (bp+1)->m_size =
        !           339:                            bp->m_addr + bp->m_size - (addr + size);
        !           340:                        bp->m_size = addr - bp->m_addr;
        !           341:                }
        !           342:        return (addr);
        !           343: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.