Annotation of sys/kern/subr_extent.c, Revision 1.1.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