[BACK]Return to subr_extent.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/subr_extent.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: subr_extent.c,v 1.33 2006/06/04 22:47:16 miod Exp $   */
        !             2: /*     $NetBSD: subr_extent.c,v 1.7 1996/11/21 18:46:34 cgd Exp $      */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1996, 1998 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 and Matthias Drochner.
        !            10:  *
        !            11:  * Redistribution and use in source and binary forms, with or without
        !            12:  * modification, are permitted provided that the following conditions
        !            13:  * are met:
        !            14:  * 1. Redistributions of source code must retain the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer.
        !            16:  * 2. Redistributions in binary form must reproduce the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer in the
        !            18:  *    documentation and/or other materials provided with the distribution.
        !            19:  * 3. All advertising materials mentioning features or use of this software
        !            20:  *    must display the following acknowledgement:
        !            21:  *     This product includes software developed by the NetBSD
        !            22:  *     Foundation, Inc. and its contributors.
        !            23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            24:  *    contributors may be used to endorse or promote products derived
        !            25:  *    from this software without specific prior written permission.
        !            26:  *
        !            27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            37:  * POSSIBILITY OF SUCH DAMAGE.
        !            38:  */
        !            39:
        !            40: /*
        !            41:  * General purpose extent manager.
        !            42:  */
        !            43:
        !            44: #ifdef _KERNEL
        !            45: #include <sys/param.h>
        !            46: #include <sys/extent.h>
        !            47: #include <sys/malloc.h>
        !            48: #include <sys/time.h>
        !            49: #include <sys/systm.h>
        !            50: #include <sys/proc.h>
        !            51: #include <sys/queue.h>
        !            52: #include <sys/pool.h>
        !            53: #include <ddb/db_output.h>
        !            54: #else
        !            55: /*
        !            56:  * user-land definitions, so it can fit into a testing harness.
        !            57:  */
        !            58: #include <sys/param.h>
        !            59: #include <sys/pool.h>
        !            60: #include <sys/extent.h>
        !            61: #include <sys/queue.h>
        !            62: #include <errno.h>
        !            63: #include <stdlib.h>
        !            64: #include <stdio.h>
        !            65:
        !            66: #define        malloc(s, t, flags)             malloc(s)
        !            67: #define        free(p, t)                      free(p)
        !            68: #define        tsleep(chan, pri, str, timo)    (EWOULDBLOCK)
        !            69: #define        wakeup(chan)                    ((void)0)
        !            70: #define        pool_get(pool, flags)           malloc((pool)->pr_size, 0, 0)
        !            71: #define        pool_init(a, b, c, d, e, f, g)  (a)->pr_size = (b)
        !            72: #define        pool_put(pool, rp)              free((rp), 0)
        !            73: #define        panic                           printf
        !            74: #define        splvm()                         (1)
        !            75: #define        splx(s)                         ((void)(s))
        !            76: #endif
        !            77:
        !            78: static void extent_insert_and_optimize(struct extent *, u_long, u_long,
        !            79:            struct extent_region *, struct extent_region *);
        !            80: static struct extent_region *extent_alloc_region_descriptor(struct extent *, int);
        !            81: static void extent_free_region_descriptor(struct extent *,
        !            82:            struct extent_region *);
        !            83:
        !            84: /*
        !            85:  * Shortcut to align to an arbitrary power-of-two boundary.
        !            86:  */
        !            87: static __inline__ u_long
        !            88: extent_align(u_long start, u_long align, u_long skew)
        !            89: {
        !            90:        return ((((start - skew) + (align - 1)) & (-align)) + skew);
        !            91: }
        !            92:
        !            93:
        !            94: #if defined(DIAGNOSTIC) || defined(DDB)
        !            95: /*
        !            96:  * Register the extent on a doubly linked list.
        !            97:  * Should work, no?
        !            98:  */
        !            99: static LIST_HEAD(listhead, extent) ext_list;
        !           100: static void extent_register(struct extent *);
        !           101:
        !           102: static void
        !           103: extent_register(struct extent *ex)
        !           104: {
        !           105: #ifdef DIAGNOSTIC
        !           106:        struct extent *ep;
        !           107: #endif
        !           108:        static int initialized;
        !           109:
        !           110:        if (!initialized){
        !           111:                LIST_INIT(&ext_list);
        !           112:                initialized = 1;
        !           113:        }
        !           114:
        !           115: #ifdef DIAGNOSTIC
        !           116:        LIST_FOREACH(ep, &ext_list, ex_link) {
        !           117:                if (ep == ex)
        !           118:                        panic("extent_register: already registered");
        !           119:        }
        !           120: #endif
        !           121:
        !           122:        /* Insert into list */
        !           123:        LIST_INSERT_HEAD(&ext_list, ex, ex_link);
        !           124: }
        !           125: #endif /* DIAGNOSTIC || DDB */
        !           126:
        !           127: struct pool ex_region_pl;
        !           128:
        !           129: static void
        !           130: extent_pool_init(void)
        !           131: {
        !           132:        static int inited;
        !           133:
        !           134:        if (!inited) {
        !           135:                pool_init(&ex_region_pl, sizeof(struct extent_region), 0, 0, 0,
        !           136:                    "extentpl", NULL);
        !           137:                inited = 1;
        !           138:        }
        !           139: }
        !           140:
        !           141: #ifdef DDB
        !           142: /*
        !           143:  * Print out all extents registered.  This is used in
        !           144:  * DDB show extents
        !           145:  */
        !           146: void
        !           147: extent_print_all(void)
        !           148: {
        !           149:        struct extent *ep;
        !           150:
        !           151:        LIST_FOREACH(ep, &ext_list, ex_link) {
        !           152:                extent_print(ep);
        !           153:        }
        !           154: }
        !           155: #endif
        !           156:
        !           157: /*
        !           158:  * Allocate and initialize an extent map.
        !           159:  */
        !           160: struct extent *
        !           161: extent_create(char *name, u_long start, u_long end, int mtype, caddr_t storage,
        !           162:     size_t storagesize, int flags)
        !           163: {
        !           164:        struct extent *ex;
        !           165:        caddr_t cp = storage;
        !           166:        size_t sz = storagesize;
        !           167:        struct extent_region *rp;
        !           168:        int fixed_extent = (storage != NULL);
        !           169:
        !           170: #ifdef DIAGNOSTIC
        !           171:        /* Check arguments. */
        !           172:        if (name == NULL)
        !           173:                panic("extent_create: name == NULL");
        !           174:        if (end < start) {
        !           175:                printf("extent_create: extent `%s', start 0x%lx, end 0x%lx\n",
        !           176:                    name, start, end);
        !           177:                panic("extent_create: end < start");
        !           178:        }
        !           179:        if (fixed_extent && (storagesize < sizeof(struct extent_fixed)))
        !           180:                panic("extent_create: fixed extent, bad storagesize 0x%lx",
        !           181:                    (u_long)storagesize);
        !           182:        if (fixed_extent == 0 && (storagesize != 0 || storage != NULL))
        !           183:                panic("extent_create: storage provided for non-fixed");
        !           184: #endif
        !           185:
        !           186:        extent_pool_init();
        !           187:
        !           188:        /* Allocate extent descriptor. */
        !           189:        if (fixed_extent) {
        !           190:                struct extent_fixed *fex;
        !           191:
        !           192:                bzero(storage, storagesize);
        !           193:
        !           194:                /*
        !           195:                 * Align all descriptors on "long" boundaries.
        !           196:                 */
        !           197:                fex = (struct extent_fixed *)cp;
        !           198:                ex = (struct extent *)fex;
        !           199:                cp += ALIGN(sizeof(struct extent_fixed));
        !           200:                sz -= ALIGN(sizeof(struct extent_fixed));
        !           201:                fex->fex_storage = storage;
        !           202:                fex->fex_storagesize = storagesize;
        !           203:
        !           204:                /*
        !           205:                 * In a fixed extent, we have to pre-allocate region
        !           206:                 * descriptors and place them in the extent's freelist.
        !           207:                 */
        !           208:                LIST_INIT(&fex->fex_freelist);
        !           209:                while (sz >= ALIGN(sizeof(struct extent_region))) {
        !           210:                        rp = (struct extent_region *)cp;
        !           211:                        cp += ALIGN(sizeof(struct extent_region));
        !           212:                        sz -= ALIGN(sizeof(struct extent_region));
        !           213:                        LIST_INSERT_HEAD(&fex->fex_freelist, rp, er_link);
        !           214:                }
        !           215:        } else {
        !           216:                ex = (struct extent *)malloc(sizeof(struct extent),
        !           217:                    mtype, (flags & EX_WAITOK) ? M_WAITOK : M_NOWAIT);
        !           218:                if (ex == NULL)
        !           219:                        return (NULL);
        !           220:        }
        !           221:
        !           222:        /* Fill in the extent descriptor and return it to the caller. */
        !           223:        LIST_INIT(&ex->ex_regions);
        !           224:        ex->ex_name = name;
        !           225:        ex->ex_start = start;
        !           226:        ex->ex_end = end;
        !           227:        ex->ex_mtype = mtype;
        !           228:        ex->ex_flags = 0;
        !           229:        if (fixed_extent)
        !           230:                ex->ex_flags |= EXF_FIXED;
        !           231:        if (flags & EX_NOCOALESCE)
        !           232:                ex->ex_flags |= EXF_NOCOALESCE;
        !           233:
        !           234: #if defined(DIAGNOSTIC) || defined(DDB)
        !           235:        extent_register(ex);
        !           236: #endif
        !           237:        return (ex);
        !           238: }
        !           239:
        !           240: /*
        !           241:  * Destroy an extent map.
        !           242:  */
        !           243: void
        !           244: extent_destroy(struct extent *ex)
        !           245: {
        !           246:        struct extent_region *rp, *orp;
        !           247:
        !           248: #ifdef DIAGNOSTIC
        !           249:        /* Check arguments. */
        !           250:        if (ex == NULL)
        !           251:                panic("extent_destroy: NULL extent");
        !           252: #endif
        !           253:
        !           254:        /* Free all region descriptors in extent. */
        !           255:        for (rp = LIST_FIRST(&ex->ex_regions);
        !           256:            rp != LIST_END(&ex->ex_regions); ) {
        !           257:                orp = rp;
        !           258:                rp = LIST_NEXT(rp, er_link);
        !           259:                LIST_REMOVE(orp, er_link);
        !           260:                extent_free_region_descriptor(ex, orp);
        !           261:        }
        !           262:
        !           263: #if defined(DIAGNOSTIC) || defined(DDB)
        !           264:        /* Remove from the list of all extents. */
        !           265:        LIST_REMOVE(ex, ex_link);
        !           266: #endif
        !           267:
        !           268:        /* If we're not a fixed extent, free the extent descriptor itself. */
        !           269:        if ((ex->ex_flags & EXF_FIXED) == 0)
        !           270:                free(ex, ex->ex_mtype);
        !           271: }
        !           272:
        !           273: /*
        !           274:  * Insert a region descriptor into the sorted region list after the
        !           275:  * entry "after" or at the head of the list (if "after" is NULL).
        !           276:  * The region descriptor we insert is passed in "rp".  We must
        !           277:  * allocate the region descriptor before calling this function!
        !           278:  * If we don't need the region descriptor, it will be freed here.
        !           279:  */
        !           280: static void
        !           281: extent_insert_and_optimize(struct extent *ex, u_long start, u_long size,
        !           282:     struct extent_region *after, struct extent_region *rp)
        !           283: {
        !           284:        struct extent_region *nextr;
        !           285:        int appended = 0;
        !           286:
        !           287:        if (after == NULL) {
        !           288:                /*
        !           289:                 * We're the first in the region list.  If there's
        !           290:                 * a region after us, attempt to coalesce to save
        !           291:                 * descriptor overhead.
        !           292:                 */
        !           293:                if (((ex->ex_flags & EXF_NOCOALESCE) == 0) &&
        !           294:                    !LIST_EMPTY(&ex->ex_regions) &&
        !           295:                    ((start + size) == LIST_FIRST(&ex->ex_regions)->er_start)) {
        !           296:                        /*
        !           297:                         * We can coalesce.  Prepend us to the first region.
        !           298:                         */
        !           299:                        LIST_FIRST(&ex->ex_regions)->er_start = start;
        !           300:                        extent_free_region_descriptor(ex, rp);
        !           301:                        return;
        !           302:                }
        !           303:
        !           304:                /*
        !           305:                 * Can't coalesce.  Fill in the region descriptor
        !           306:                 * in, and insert us at the head of the region list.
        !           307:                 */
        !           308:                rp->er_start = start;
        !           309:                rp->er_end = start + (size - 1);
        !           310:                LIST_INSERT_HEAD(&ex->ex_regions, rp, er_link);
        !           311:                return;
        !           312:        }
        !           313:
        !           314:        /*
        !           315:         * If EXF_NOCOALESCE is set, coalescing is disallowed.
        !           316:         */
        !           317:        if (ex->ex_flags & EXF_NOCOALESCE)
        !           318:                goto cant_coalesce;
        !           319:
        !           320:        /*
        !           321:         * Attempt to coalesce with the region before us.
        !           322:         */
        !           323:        if ((after->er_end + 1) == start) {
        !           324:                /*
        !           325:                 * We can coalesce.  Append ourselves and make
        !           326:                 * note of it.
        !           327:                 */
        !           328:                after->er_end = start + (size - 1);
        !           329:                appended = 1;
        !           330:        }
        !           331:
        !           332:        /*
        !           333:         * Attempt to coalesce with the region after us.
        !           334:         */
        !           335:        if (LIST_NEXT(after, er_link) != NULL &&
        !           336:            ((start + size) == LIST_NEXT(after, er_link)->er_start)) {
        !           337:                /*
        !           338:                 * We can coalesce.  Note that if we appended ourselves
        !           339:                 * to the previous region, we exactly fit the gap, and
        !           340:                 * can free the "next" region descriptor.
        !           341:                 */
        !           342:                if (appended) {
        !           343:                        /*
        !           344:                         * Yup, we can free it up.
        !           345:                         */
        !           346:                        after->er_end = LIST_NEXT(after, er_link)->er_end;
        !           347:                        nextr = LIST_NEXT(after, er_link);
        !           348:                        LIST_REMOVE(nextr, er_link);
        !           349:                        extent_free_region_descriptor(ex, nextr);
        !           350:                } else {
        !           351:                        /*
        !           352:                         * Nope, just prepend us to the next region.
        !           353:                         */
        !           354:                        LIST_NEXT(after, er_link)->er_start = start;
        !           355:                }
        !           356:
        !           357:                extent_free_region_descriptor(ex, rp);
        !           358:                return;
        !           359:        }
        !           360:
        !           361:        /*
        !           362:         * We weren't able to coalesce with the next region, but
        !           363:         * we don't need to allocate a region descriptor if we
        !           364:         * appended ourselves to the previous region.
        !           365:         */
        !           366:        if (appended) {
        !           367:                extent_free_region_descriptor(ex, rp);
        !           368:                return;
        !           369:        }
        !           370:
        !           371:  cant_coalesce:
        !           372:
        !           373:        /*
        !           374:         * Fill in the region descriptor and insert ourselves
        !           375:         * into the region list.
        !           376:         */
        !           377:        rp->er_start = start;
        !           378:        rp->er_end = start + (size - 1);
        !           379:        LIST_INSERT_AFTER(after, rp, er_link);
        !           380: }
        !           381:
        !           382: /*
        !           383:  * Allocate a specific region in an extent map.
        !           384:  */
        !           385: int
        !           386: extent_alloc_region(struct extent *ex, u_long start, u_long size, int flags)
        !           387: {
        !           388:        struct extent_region *rp, *last, *myrp;
        !           389:        u_long end = start + (size - 1);
        !           390:        int error;
        !           391:
        !           392: #ifdef DIAGNOSTIC
        !           393:        /* Check arguments. */
        !           394:        if (ex == NULL)
        !           395:                panic("extent_alloc_region: NULL extent");
        !           396:        if (size < 1) {
        !           397:                printf("extent_alloc_region: extent `%s', size 0x%lx\n",
        !           398:                    ex->ex_name, size);
        !           399:                panic("extent_alloc_region: bad size");
        !           400:        }
        !           401:        if (end < start) {
        !           402:                printf(
        !           403:                 "extent_alloc_region: extent `%s', start 0x%lx, size 0x%lx\n",
        !           404:                 ex->ex_name, start, size);
        !           405:                panic("extent_alloc_region: overflow");
        !           406:        }
        !           407: #endif
        !           408:
        !           409:        /*
        !           410:         * Make sure the requested region lies within the
        !           411:         * extent.
        !           412:         */
        !           413:        if ((start < ex->ex_start) || (end > ex->ex_end)) {
        !           414: #ifdef DIAGNOSTIC
        !           415:                printf("extent_alloc_region: extent `%s' (0x%lx - 0x%lx)\n",
        !           416:                    ex->ex_name, ex->ex_start, ex->ex_end);
        !           417:                printf("extent_alloc_region: start 0x%lx, end 0x%lx\n",
        !           418:                    start, end);
        !           419:                panic("extent_alloc_region: region lies outside extent");
        !           420: #else
        !           421:                return (EINVAL);
        !           422: #endif
        !           423:        }
        !           424:
        !           425:        /*
        !           426:         * Allocate the region descriptor.  It will be freed later
        !           427:         * if we can coalesce with another region.
        !           428:         */
        !           429:        myrp = extent_alloc_region_descriptor(ex, flags);
        !           430:        if (myrp == NULL) {
        !           431: #ifdef DIAGNOSTIC
        !           432:                printf(
        !           433:                    "extent_alloc_region: can't allocate region descriptor\n");
        !           434: #endif
        !           435:                return (ENOMEM);
        !           436:        }
        !           437:
        !           438:  alloc_start:
        !           439:        /*
        !           440:         * Attempt to place ourselves in the desired area of the
        !           441:         * extent.  We save ourselves some work by keeping the list sorted.
        !           442:         * In other words, if the start of the current region is greater
        !           443:         * than the end of our region, we don't have to search any further.
        !           444:         */
        !           445:
        !           446:        /*
        !           447:         * Keep a pointer to the last region we looked at so
        !           448:         * that we don't have to traverse the list again when
        !           449:         * we insert ourselves.  If "last" is NULL when we
        !           450:         * finally insert ourselves, we go at the head of the
        !           451:         * list.  See extent_insert_and_optimize() for details.
        !           452:         */
        !           453:        last = NULL;
        !           454:
        !           455:        LIST_FOREACH(rp, &ex->ex_regions, er_link) {
        !           456:                if (rp->er_start > end) {
        !           457:                        /*
        !           458:                         * We lie before this region and don't
        !           459:                         * conflict.
        !           460:                         */
        !           461:                        break;
        !           462:                }
        !           463:
        !           464:                /*
        !           465:                 * The current region begins before we end.
        !           466:                 * Check for a conflict.
        !           467:                 */
        !           468:                if (rp->er_end >= start) {
        !           469:                        /*
        !           470:                         * We conflict.  If we can (and want to) wait,
        !           471:                         * do so.
        !           472:                         */
        !           473:                        if (flags & EX_WAITSPACE) {
        !           474:                                ex->ex_flags |= EXF_WANTED;
        !           475:                                error = tsleep(ex,
        !           476:                                    PRIBIO | ((flags & EX_CATCH) ? PCATCH : 0),
        !           477:                                    "extnt", 0);
        !           478:                                if (error)
        !           479:                                        return (error);
        !           480:                                goto alloc_start;
        !           481:                        }
        !           482:                        extent_free_region_descriptor(ex, myrp);
        !           483:                        return (EAGAIN);
        !           484:                }
        !           485:                /*
        !           486:                 * We don't conflict, but this region lies before
        !           487:                 * us.  Keep a pointer to this region, and keep
        !           488:                 * trying.
        !           489:                 */
        !           490:                last = rp;
        !           491:        }
        !           492:
        !           493:        /*
        !           494:         * We don't conflict with any regions.  "last" points
        !           495:         * to the region we fall after, or is NULL if we belong
        !           496:         * at the beginning of the region list.  Insert ourselves.
        !           497:         */
        !           498:        extent_insert_and_optimize(ex, start, size, last, myrp);
        !           499:        return (0);
        !           500: }
        !           501:
        !           502: /*
        !           503:  * Macro to check (x + y) <= z.  This check is designed to fail
        !           504:  * if an overflow occurs.
        !           505:  */
        !           506: #define LE_OV(x, y, z) ((((x) + (y)) >= (x)) && (((x) + (y)) <= (z)))
        !           507:
        !           508: /*
        !           509:  * Allocate a region in an extent map subregion.
        !           510:  *
        !           511:  * If EX_FAST is specified, we return the first fit in the map.
        !           512:  * Otherwise, we try to minimize fragmentation by finding the
        !           513:  * smallest gap that will hold the request.
        !           514:  *
        !           515:  * The allocated region is aligned to "alignment", which must be
        !           516:  * a power of 2.
        !           517:  */
        !           518: int
        !           519: extent_alloc_subregion(struct extent *ex, u_long substart, u_long subend,
        !           520:     u_long size, u_long alignment, u_long skew, u_long boundary, int flags,
        !           521:     u_long *result)
        !           522: {
        !           523:        struct extent_region *rp, *myrp, *last, *bestlast;
        !           524:        u_long newstart, newend, exend, beststart, bestovh, ovh;
        !           525:        u_long dontcross;
        !           526:        int error;
        !           527:
        !           528: #ifdef DIAGNOSTIC
        !           529:        /* Check arguments. */
        !           530:        if (ex == NULL)
        !           531:                panic("extent_alloc_subregion: NULL extent");
        !           532:        if (result == NULL)
        !           533:                panic("extent_alloc_subregion: NULL result pointer");
        !           534:        if ((substart < ex->ex_start) || (substart > ex->ex_end) ||
        !           535:            (subend > ex->ex_end) || (subend < ex->ex_start)) {
        !           536:   printf("extent_alloc_subregion: extent `%s', ex_start 0x%lx, ex_end 0x%lx\n",
        !           537:                    ex->ex_name, ex->ex_start, ex->ex_end);
        !           538:                printf("extent_alloc_subregion: substart 0x%lx, subend 0x%lx\n",
        !           539:                    substart, subend);
        !           540:                panic("extent_alloc_subregion: bad subregion");
        !           541:        }
        !           542:        if ((size < 1) || ((size - 1) > (subend - substart))) {
        !           543:                printf("extent_alloc_subregion: extent `%s', size 0x%lx\n",
        !           544:                    ex->ex_name, size);
        !           545:                panic("extent_alloc_subregion: bad size");
        !           546:        }
        !           547:        if (alignment == 0)
        !           548:                panic("extent_alloc_subregion: bad alignment");
        !           549:        if (boundary && (boundary < size)) {
        !           550:                printf(
        !           551:                    "extent_alloc_subregion: extent `%s', size 0x%lx, "
        !           552:                    "boundary 0x%lx\n", ex->ex_name, size, boundary);
        !           553:                panic("extent_alloc_subregion: bad boundary");
        !           554:        }
        !           555: #endif
        !           556:
        !           557:        /*
        !           558:         * Allocate the region descriptor.  It will be freed later
        !           559:         * if we can coalesce with another region.
        !           560:         */
        !           561:        myrp = extent_alloc_region_descriptor(ex, flags);
        !           562:        if (myrp == NULL) {
        !           563: #ifdef DIAGNOSTIC
        !           564:                printf(
        !           565:                 "extent_alloc_subregion: can't allocate region descriptor\n");
        !           566: #endif
        !           567:                return (ENOMEM);
        !           568:        }
        !           569:
        !           570:  alloc_start:
        !           571:        /*
        !           572:         * Keep a pointer to the last region we looked at so
        !           573:         * that we don't have to traverse the list again when
        !           574:         * we insert ourselves.  If "last" is NULL when we
        !           575:         * finally insert ourselves, we go at the head of the
        !           576:         * list.  See extent_insert_and_optimize() for deatails.
        !           577:         */
        !           578:        last = NULL;
        !           579:
        !           580:        /*
        !           581:         * Keep track of size and location of the smallest
        !           582:         * chunk we fit in.
        !           583:         *
        !           584:         * Since the extent can be as large as the numeric range
        !           585:         * of the CPU (0 - 0xffffffff for 32-bit systems), the
        !           586:         * best overhead value can be the maximum unsigned integer.
        !           587:         * Thus, we initialize "bestovh" to 0, since we insert ourselves
        !           588:         * into the region list immediately on an exact match (which
        !           589:         * is the only case where "bestovh" would be set to 0).
        !           590:         */
        !           591:        bestovh = 0;
        !           592:        beststart = 0;
        !           593:        bestlast = NULL;
        !           594:
        !           595:        /*
        !           596:         * Keep track of end of free region.  This is either the end of extent
        !           597:         * or the start of a region past the subend.
        !           598:         */
        !           599:        exend = ex->ex_end;
        !           600:
        !           601:        /*
        !           602:         * For N allocated regions, we must make (N + 1)
        !           603:         * checks for unallocated space.  The first chunk we
        !           604:         * check is the area from the beginning of the subregion
        !           605:         * to the first allocated region after that point.
        !           606:         */
        !           607:        newstart = extent_align(substart, alignment, skew);
        !           608:        if (newstart < ex->ex_start) {
        !           609: #ifdef DIAGNOSTIC
        !           610:                printf(
        !           611:       "extent_alloc_subregion: extent `%s' (0x%lx - 0x%lx), alignment 0x%lx\n",
        !           612:                 ex->ex_name, ex->ex_start, ex->ex_end, alignment);
        !           613:                panic("extent_alloc_subregion: overflow after alignment");
        !           614: #else
        !           615:                extent_free_region_descriptor(ex, myrp);
        !           616:                return (EINVAL);
        !           617: #endif
        !           618:        }
        !           619:
        !           620:        /*
        !           621:         * Find the first allocated region that begins on or after
        !           622:         * the subregion start, advancing the "last" pointer along
        !           623:         * the way.
        !           624:         */
        !           625:        LIST_FOREACH(rp, &ex->ex_regions, er_link) {
        !           626:                if (rp->er_start >= newstart)
        !           627:                        break;
        !           628:                last = rp;
        !           629:        }
        !           630:
        !           631:        /*
        !           632:         * Relocate the start of our candidate region to the end of
        !           633:         * the last allocated region (if there was one overlapping
        !           634:         * our subrange).
        !           635:         */
        !           636:        if (last != NULL && last->er_end >= newstart)
        !           637:                newstart = extent_align((last->er_end + 1), alignment, skew);
        !           638:
        !           639:        for (; rp != LIST_END(&ex->ex_regions); rp = LIST_NEXT(rp, er_link)) {
        !           640:                /*
        !           641:                 * If the region pasts the subend, bail out and see
        !           642:                 * if we fit against the subend.
        !           643:                 */
        !           644:                if (rp->er_start > subend) {
        !           645:                        exend = rp->er_start;
        !           646:                        break;
        !           647:                }
        !           648:
        !           649:                /*
        !           650:                 * Check the chunk before "rp".  Note that our
        !           651:                 * comparison is safe from overflow conditions.
        !           652:                 */
        !           653:                if (LE_OV(newstart, size, rp->er_start)) {
        !           654:                        /*
        !           655:                         * Do a boundary check, if necessary.  Note
        !           656:                         * that a region may *begin* on the boundary,
        !           657:                         * but it must end before the boundary.
        !           658:                         */
        !           659:                        if (boundary) {
        !           660:                                newend = newstart + (size - 1);
        !           661:
        !           662:                                /*
        !           663:                                 * Calculate the next boundary after the start
        !           664:                                 * of this region.
        !           665:                                 */
        !           666:                                dontcross = extent_align(newstart+1, boundary,
        !           667:                                    (flags & EX_BOUNDZERO) ? 0 : ex->ex_start)
        !           668:                                    - 1;
        !           669:
        !           670: #if 0
        !           671:                                printf("newstart=%lx newend=%lx ex_start=%lx ex_end=%lx boundary=%lx dontcross=%lx\n",
        !           672:                                    newstart, newend, ex->ex_start, ex->ex_end,
        !           673:                                    boundary, dontcross);
        !           674: #endif
        !           675:
        !           676:                                /* Check for overflow */
        !           677:                                if (dontcross < ex->ex_start)
        !           678:                                        dontcross = ex->ex_end;
        !           679:                                else if (newend > dontcross) {
        !           680:                                        /*
        !           681:                                         * Candidate region crosses boundary.
        !           682:                                         * Throw away the leading part and see
        !           683:                                         * if we still fit.
        !           684:                                         */
        !           685:                                        newstart = dontcross + 1;
        !           686:                                        newend = newstart + (size - 1);
        !           687:                                        dontcross += boundary;
        !           688:                                        if (!LE_OV(newstart, size, rp->er_start))
        !           689:                                                goto skip;
        !           690:                                }
        !           691:
        !           692:                                /*
        !           693:                                 * If we run past the end of
        !           694:                                 * the extent or the boundary
        !           695:                                 * overflows, then the request
        !           696:                                 * can't fit.
        !           697:                                 */
        !           698:                                if (newstart + size - 1 > ex->ex_end ||
        !           699:                                    dontcross < newstart)
        !           700:                                        goto fail;
        !           701:                        }
        !           702:
        !           703:                        /*
        !           704:                         * We would fit into this space.  Calculate
        !           705:                         * the overhead (wasted space).  If we exactly
        !           706:                         * fit, or we're taking the first fit, insert
        !           707:                         * ourselves into the region list.
        !           708:                         */
        !           709:                        ovh = rp->er_start - newstart - size;
        !           710:                        if ((flags & EX_FAST) || (ovh == 0))
        !           711:                                goto found;
        !           712:
        !           713:                        /*
        !           714:                         * Don't exactly fit, but check to see
        !           715:                         * if we're better than any current choice.
        !           716:                         */
        !           717:                        if ((bestovh == 0) || (ovh < bestovh)) {
        !           718:                                bestovh = ovh;
        !           719:                                beststart = newstart;
        !           720:                                bestlast = last;
        !           721:                        }
        !           722:                }
        !           723:
        !           724: skip:
        !           725:                /*
        !           726:                 * Skip past the current region and check again.
        !           727:                 */
        !           728:                newstart = extent_align((rp->er_end + 1), alignment, skew);
        !           729:                if (newstart < rp->er_end) {
        !           730:                        /*
        !           731:                         * Overflow condition.  Don't error out, since
        !           732:                         * we might have a chunk of space that we can
        !           733:                         * use.
        !           734:                         */
        !           735:                        goto fail;
        !           736:                }
        !           737:
        !           738:                last = rp;
        !           739:        }
        !           740:
        !           741:        /*
        !           742:         * The final check is from the current starting point to the
        !           743:         * end of the subregion.  If there were no allocated regions,
        !           744:         * "newstart" is set to the beginning of the subregion, or
        !           745:         * just past the end of the last allocated region, adjusted
        !           746:         * for alignment in either case.
        !           747:         */
        !           748:        if (LE_OV(newstart, (size - 1), subend)) {
        !           749:                /*
        !           750:                 * Do a boundary check, if necessary.  Note
        !           751:                 * that a region may *begin* on the boundary,
        !           752:                 * but it must end before the boundary.
        !           753:                 */
        !           754:                if (boundary) {
        !           755:                        newend = newstart + (size - 1);
        !           756:
        !           757:                        /*
        !           758:                         * Calculate the next boundary after the start
        !           759:                         * of this region.
        !           760:                         */
        !           761:                        dontcross = extent_align(newstart+1, boundary,
        !           762:                            (flags & EX_BOUNDZERO) ? 0 : ex->ex_start)
        !           763:                            - 1;
        !           764:
        !           765: #if 0
        !           766:                        printf("newstart=%lx newend=%lx ex_start=%lx ex_end=%lx boundary=%lx dontcross=%lx\n",
        !           767:                            newstart, newend, ex->ex_start, ex->ex_end,
        !           768:                            boundary, dontcross);
        !           769: #endif
        !           770:
        !           771:                        /* Check for overflow */
        !           772:                        if (dontcross < ex->ex_start)
        !           773:                                dontcross = ex->ex_end;
        !           774:                        else if (newend > dontcross) {
        !           775:                                /*
        !           776:                                 * Candidate region crosses boundary.
        !           777:                                 * Throw away the leading part and see
        !           778:                                 * if we still fit.
        !           779:                                 */
        !           780:                                newstart = dontcross + 1;
        !           781:                                newend = newstart + (size - 1);
        !           782:                                dontcross += boundary;
        !           783:                                if (!LE_OV(newstart, (size - 1), subend))
        !           784:                                        goto fail;
        !           785:                        }
        !           786:
        !           787:                        /*
        !           788:                         * If we run past the end of
        !           789:                         * the extent or the boundary
        !           790:                         * overflows, then the request
        !           791:                         * can't fit.
        !           792:                         */
        !           793:                        if (newstart + size - 1 > ex->ex_end ||
        !           794:                            dontcross < newstart)
        !           795:                                goto fail;
        !           796:                }
        !           797:
        !           798:                /*
        !           799:                 * We would fit into this space.  Calculate
        !           800:                 * the overhead (wasted space).  If we exactly
        !           801:                 * fit, or we're taking the first fit, insert
        !           802:                 * ourselves into the region list.
        !           803:                 */
        !           804:                ovh = exend - newstart - (size - 1);
        !           805:                if ((flags & EX_FAST) || (ovh == 0))
        !           806:                        goto found;
        !           807:
        !           808:                /*
        !           809:                 * Don't exactly fit, but check to see
        !           810:                 * if we're better than any current choice.
        !           811:                 */
        !           812:                if ((bestovh == 0) || (ovh < bestovh)) {
        !           813:                        bestovh = ovh;
        !           814:                        beststart = newstart;
        !           815:                        bestlast = last;
        !           816:                }
        !           817:        }
        !           818:
        !           819:  fail:
        !           820:        /*
        !           821:         * One of the following two conditions have
        !           822:         * occurred:
        !           823:         *
        !           824:         *      There is no chunk large enough to hold the request.
        !           825:         *
        !           826:         *      If EX_FAST was not specified, there is not an
        !           827:         *      exact match for the request.
        !           828:         *
        !           829:         * Note that if we reach this point and EX_FAST is
        !           830:         * set, then we know there is no space in the extent for
        !           831:         * the request.
        !           832:         */
        !           833:        if (((flags & EX_FAST) == 0) && (bestovh != 0)) {
        !           834:                /*
        !           835:                 * We have a match that's "good enough".
        !           836:                 */
        !           837:                newstart = beststart;
        !           838:                last = bestlast;
        !           839:                goto found;
        !           840:        }
        !           841:
        !           842:        /*
        !           843:         * No space currently available.  Wait for it to free up,
        !           844:         * if possible.
        !           845:         */
        !           846:        if (flags & EX_WAITSPACE) {
        !           847:                ex->ex_flags |= EXF_WANTED;
        !           848:                error = tsleep(ex,
        !           849:                    PRIBIO | ((flags & EX_CATCH) ? PCATCH : 0), "extnt", 0);
        !           850:                if (error)
        !           851:                        return (error);
        !           852:                goto alloc_start;
        !           853:        }
        !           854:
        !           855:        extent_free_region_descriptor(ex, myrp);
        !           856:        return (EAGAIN);
        !           857:
        !           858:  found:
        !           859:        /*
        !           860:         * Insert ourselves into the region list.
        !           861:         */
        !           862:        extent_insert_and_optimize(ex, newstart, size, last, myrp);
        !           863:        *result = newstart;
        !           864:        return (0);
        !           865: }
        !           866:
        !           867: int
        !           868: extent_free(struct extent *ex, u_long start, u_long size, int flags)
        !           869: {
        !           870:        struct extent_region *rp, *nrp = NULL;
        !           871:        u_long end = start + (size - 1);
        !           872:        int exflags;
        !           873:
        !           874: #ifdef DIAGNOSTIC
        !           875:        /* Check arguments. */
        !           876:        if (ex == NULL)
        !           877:                panic("extent_free: NULL extent");
        !           878:        if ((start < ex->ex_start) || (end > ex->ex_end)) {
        !           879:                extent_print(ex);
        !           880:                printf("extent_free: extent `%s', start 0x%lx, size 0x%lx\n",
        !           881:                    ex->ex_name, start, size);
        !           882:                panic("extent_free: extent `%s', region not within extent",
        !           883:                    ex->ex_name);
        !           884:        }
        !           885:        /* Check for an overflow. */
        !           886:        if (end < start) {
        !           887:                extent_print(ex);
        !           888:                printf("extent_free: extent `%s', start 0x%lx, size 0x%lx\n",
        !           889:                    ex->ex_name, start, size);
        !           890:                panic("extent_free: overflow");
        !           891:        }
        !           892: #endif
        !           893:
        !           894:        /*
        !           895:         * If we're allowing coalescing, we must allocate a region
        !           896:         * descriptor now, since it might block.
        !           897:         *
        !           898:         * XXX Make a static, create-time flags word, so we don't
        !           899:         * XXX have to lock to read it!
        !           900:         */
        !           901:        exflags = ex->ex_flags;
        !           902:
        !           903:        if ((exflags & EXF_NOCOALESCE) == 0) {
        !           904:                /* Allocate a region descriptor. */
        !           905:                nrp = extent_alloc_region_descriptor(ex, flags);
        !           906:                if (nrp == NULL)
        !           907:                        return (ENOMEM);
        !           908:        }
        !           909:
        !           910:        /*
        !           911:         * Find region and deallocate.  Several possibilities:
        !           912:         *
        !           913:         *      1. (start == er_start) && (end == er_end):
        !           914:         *         Free descriptor.
        !           915:         *
        !           916:         *      2. (start == er_start) && (end < er_end):
        !           917:         *         Adjust er_start.
        !           918:         *
        !           919:         *      3. (start > er_start) && (end == er_end):
        !           920:         *         Adjust er_end.
        !           921:         *
        !           922:         *      4. (start > er_start) && (end < er_end):
        !           923:         *         Fragment region.  Requires descriptor alloc.
        !           924:         *
        !           925:         * Cases 2, 3, and 4 require that the EXF_NOCOALESCE flag
        !           926:         * is not set.
        !           927:         */
        !           928:        LIST_FOREACH(rp, &ex->ex_regions, er_link) {
        !           929:                /*
        !           930:                 * Save ourselves some comparisons; does the current
        !           931:                 * region end before chunk to be freed begins?  If so,
        !           932:                 * then we haven't found the appropriate region descriptor.
        !           933:                 */
        !           934:                if (rp->er_end < start)
        !           935:                        continue;
        !           936:
        !           937:                /*
        !           938:                 * Save ourselves some traversal; does the current
        !           939:                 * region begin after the chunk to be freed ends?  If so,
        !           940:                 * then we've already passed any possible region descriptors
        !           941:                 * that might have contained the chunk to be freed.
        !           942:                 */
        !           943:                if (rp->er_start > end)
        !           944:                        break;
        !           945:
        !           946:                /* Case 1. */
        !           947:                if ((start == rp->er_start) && (end == rp->er_end)) {
        !           948:                        LIST_REMOVE(rp, er_link);
        !           949:                        extent_free_region_descriptor(ex, rp);
        !           950:                        goto done;
        !           951:                }
        !           952:
        !           953:                /*
        !           954:                 * The following cases all require that EXF_NOCOALESCE
        !           955:                 * is not set.
        !           956:                 */
        !           957:                if (ex->ex_flags & EXF_NOCOALESCE)
        !           958:                        continue;
        !           959:
        !           960:                /* Case 2. */
        !           961:                if ((start == rp->er_start) && (end < rp->er_end)) {
        !           962:                        rp->er_start = (end + 1);
        !           963:                        goto done;
        !           964:                }
        !           965:
        !           966:                /* Case 3. */
        !           967:                if ((start > rp->er_start) && (end == rp->er_end)) {
        !           968:                        rp->er_end = (start - 1);
        !           969:                        goto done;
        !           970:                }
        !           971:
        !           972:                /* Case 4. */
        !           973:                if ((start > rp->er_start) && (end < rp->er_end)) {
        !           974:                        /* Fill in new descriptor. */
        !           975:                        nrp->er_start = end + 1;
        !           976:                        nrp->er_end = rp->er_end;
        !           977:
        !           978:                        /* Adjust current descriptor. */
        !           979:                        rp->er_end = start - 1;
        !           980:
        !           981:                        /* Insert new descriptor after current. */
        !           982:                        LIST_INSERT_AFTER(rp, nrp, er_link);
        !           983:
        !           984:                        /* We used the new descriptor, so don't free it below */
        !           985:                        nrp = NULL;
        !           986:                        goto done;
        !           987:                }
        !           988:        }
        !           989:
        !           990:        /* Region not found, or request otherwise invalid. */
        !           991: #if defined(DIAGNOSTIC) || defined(DDB)
        !           992:        extent_print(ex);
        !           993: #endif
        !           994:        printf("extent_free: start 0x%lx, end 0x%lx\n", start, end);
        !           995:        panic("extent_free: region not found");
        !           996:
        !           997:  done:
        !           998:        if (nrp != NULL)
        !           999:                extent_free_region_descriptor(ex, nrp);
        !          1000:        if (ex->ex_flags & EXF_WANTED) {
        !          1001:                ex->ex_flags &= ~EXF_WANTED;
        !          1002:                wakeup(ex);
        !          1003:        }
        !          1004:        return (0);
        !          1005: }
        !          1006:
        !          1007: static struct extent_region *
        !          1008: extent_alloc_region_descriptor(struct extent *ex, int flags)
        !          1009: {
        !          1010:        struct extent_region *rp;
        !          1011:        int s;
        !          1012:
        !          1013:        if (ex->ex_flags & EXF_FIXED) {
        !          1014:                struct extent_fixed *fex = (struct extent_fixed *)ex;
        !          1015:
        !          1016:                while (LIST_EMPTY(&fex->fex_freelist)) {
        !          1017:                        if (flags & EX_MALLOCOK)
        !          1018:                                goto alloc;
        !          1019:
        !          1020:                        if ((flags & EX_WAITOK) == 0)
        !          1021:                                return (NULL);
        !          1022:                        ex->ex_flags |= EXF_FLWANTED;
        !          1023:                        if (tsleep(&fex->fex_freelist,
        !          1024:                            PRIBIO | ((flags & EX_CATCH) ? PCATCH : 0),
        !          1025:                            "extnt", 0))
        !          1026:                                return (NULL);
        !          1027:                }
        !          1028:                rp = LIST_FIRST(&fex->fex_freelist);
        !          1029:                LIST_REMOVE(rp, er_link);
        !          1030:
        !          1031:                /*
        !          1032:                 * Don't muck with flags after pulling it off the
        !          1033:                 * freelist; it may be a dynamiclly allocated
        !          1034:                 * region pointer that was kindly given to us,
        !          1035:                 * and we need to preserve that information.
        !          1036:                 */
        !          1037:
        !          1038:                return (rp);
        !          1039:        }
        !          1040:
        !          1041:  alloc:
        !          1042:        s = splvm();
        !          1043:        rp = pool_get(&ex_region_pl, (flags & EX_WAITOK) ? PR_WAITOK : 0);
        !          1044:        splx(s);
        !          1045:        if (rp != NULL)
        !          1046:                rp->er_flags = ER_ALLOC;
        !          1047:
        !          1048:        return (rp);
        !          1049: }
        !          1050:
        !          1051: static void
        !          1052: extent_free_region_descriptor(struct extent *ex, struct extent_region *rp)
        !          1053: {
        !          1054:        int s;
        !          1055:
        !          1056:        if (ex->ex_flags & EXF_FIXED) {
        !          1057:                struct extent_fixed *fex = (struct extent_fixed *)ex;
        !          1058:
        !          1059:                /*
        !          1060:                 * If someone's waiting for a region descriptor,
        !          1061:                 * be nice and give them this one, rather than
        !          1062:                 * just free'ing it back to the system.
        !          1063:                 */
        !          1064:                if (rp->er_flags & ER_ALLOC) {
        !          1065:                        if (ex->ex_flags & EXF_FLWANTED) {
        !          1066:                                /* Clear all but ER_ALLOC flag. */
        !          1067:                                rp->er_flags = ER_ALLOC;
        !          1068:                                LIST_INSERT_HEAD(&fex->fex_freelist, rp,
        !          1069:                                    er_link);
        !          1070:                                goto wake_em_up;
        !          1071:                        } else {
        !          1072:                                s = splvm();
        !          1073:                                pool_put(&ex_region_pl, rp);
        !          1074:                                splx(s);
        !          1075:                        }
        !          1076:                } else {
        !          1077:                        /* Clear all flags. */
        !          1078:                        rp->er_flags = 0;
        !          1079:                        LIST_INSERT_HEAD(&fex->fex_freelist, rp, er_link);
        !          1080:                }
        !          1081:
        !          1082:                if (ex->ex_flags & EXF_FLWANTED) {
        !          1083:  wake_em_up:
        !          1084:                        ex->ex_flags &= ~EXF_FLWANTED;
        !          1085:                        wakeup(&fex->fex_freelist);
        !          1086:                }
        !          1087:                return;
        !          1088:        }
        !          1089:
        !          1090:        /*
        !          1091:         * We know it's dynamically allocated if we get here.
        !          1092:         */
        !          1093:        s = splvm();
        !          1094:        pool_put(&ex_region_pl, rp);
        !          1095:        splx(s);
        !          1096: }
        !          1097:
        !          1098: #ifndef DDB
        !          1099: #define db_printf printf
        !          1100: #endif
        !          1101:
        !          1102: #if defined(DIAGNOSTIC) || defined(DDB) || !defined(_KERNEL)
        !          1103: void
        !          1104: extent_print(struct extent *ex)
        !          1105: {
        !          1106:        struct extent_region *rp;
        !          1107:
        !          1108:        if (ex == NULL)
        !          1109:                panic("extent_print: NULL extent");
        !          1110:
        !          1111: #ifdef _KERNEL
        !          1112:        db_printf("extent `%s' (0x%lx - 0x%lx), flags=%b\n", ex->ex_name,
        !          1113:            ex->ex_start, ex->ex_end, ex->ex_flags, EXF_BITS);
        !          1114: #else
        !          1115:        db_printf("extent `%s' (0x%lx - 0x%lx), flags = 0x%x\n", ex->ex_name,
        !          1116:            ex->ex_start, ex->ex_end, ex->ex_flags);
        !          1117: #endif
        !          1118:
        !          1119:        LIST_FOREACH(rp, &ex->ex_regions, er_link)
        !          1120:                db_printf("     0x%lx - 0x%lx\n", rp->er_start, rp->er_end);
        !          1121: }
        !          1122: #endif

CVSweb