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