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