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