xref: /netbsd-src/sys/kern/subr_extent.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
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