1 /* $NetBSD: subr_pool.c,v 1.17 1998/12/27 21:13:43 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 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 FOUNDATION OR CONTRIBUTORS 30 * BE 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 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/proc.h> 42 #include <sys/errno.h> 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/lock.h> 46 #include <sys/pool.h> 47 48 #include <vm/vm.h> 49 #include <vm/vm_kern.h> 50 51 #if defined(UVM) 52 #include <uvm/uvm.h> 53 #endif 54 55 /* 56 * Pool resource management utility. 57 * 58 * Memory is allocated in pages which are split into pieces according 59 * to the pool item size. Each page is kept on a list headed by `pr_pagelist' 60 * in the pool structure and the individual pool items are on a linked list 61 * headed by `ph_itemlist' in each page header. The memory for building 62 * the page list is either taken from the allocated pages themselves (for 63 * small pool items) or taken from an internal pool of page headers (`phpool'). 64 * 65 */ 66 67 /* List of all pools */ 68 TAILQ_HEAD(,pool) pool_head = TAILQ_HEAD_INITIALIZER(pool_head); 69 70 /* Private pool for page header structures */ 71 static struct pool phpool; 72 73 /* # of seconds to retain page after last use */ 74 int pool_inactive_time = 10; 75 76 /* Next candidate for drainage (see pool_drain()) */ 77 static struct pool *drainpp = NULL; 78 79 struct pool_item_header { 80 /* Page headers */ 81 TAILQ_ENTRY(pool_item_header) 82 ph_pagelist; /* pool page list */ 83 TAILQ_HEAD(,pool_item) ph_itemlist; /* chunk list for this page */ 84 LIST_ENTRY(pool_item_header) 85 ph_hashlist; /* Off-page page headers */ 86 int ph_nmissing; /* # of chunks in use */ 87 caddr_t ph_page; /* this page's address */ 88 struct timeval ph_time; /* last referenced */ 89 }; 90 91 struct pool_item { 92 #ifdef DIAGNOSTIC 93 int pi_magic; 94 #define PI_MAGIC 0xdeadbeef 95 #endif 96 /* Other entries use only this list entry */ 97 TAILQ_ENTRY(pool_item) pi_list; 98 }; 99 100 101 #define PR_HASH_INDEX(pp,addr) \ 102 (((u_long)(addr) >> (pp)->pr_pageshift) & (PR_HASHTABSIZE - 1)) 103 104 105 106 static struct pool_item_header 107 *pr_find_pagehead __P((struct pool *, caddr_t)); 108 static void pr_rmpage __P((struct pool *, struct pool_item_header *)); 109 static int pool_prime_page __P((struct pool *, caddr_t)); 110 static void *pool_page_alloc __P((unsigned long, int, int)); 111 static void pool_page_free __P((void *, unsigned long, int)); 112 113 114 #ifdef POOL_DIAGNOSTIC 115 /* 116 * Pool log entry. An array of these is allocated in pool_create(). 117 */ 118 struct pool_log { 119 const char *pl_file; 120 long pl_line; 121 int pl_action; 122 #define PRLOG_GET 1 123 #define PRLOG_PUT 2 124 void *pl_addr; 125 }; 126 127 /* Number of entries in pool log buffers */ 128 #ifndef POOL_LOGSIZE 129 #define POOL_LOGSIZE 10 130 #endif 131 132 int pool_logsize = POOL_LOGSIZE; 133 134 static void pr_log __P((struct pool *, void *, int, const char *, long)); 135 static void pr_printlog __P((struct pool *)); 136 137 static __inline__ void 138 pr_log(pp, v, action, file, line) 139 struct pool *pp; 140 void *v; 141 int action; 142 const char *file; 143 long line; 144 { 145 int n = pp->pr_curlogentry; 146 struct pool_log *pl; 147 148 if ((pp->pr_flags & PR_LOGGING) == 0) 149 return; 150 151 /* 152 * Fill in the current entry. Wrap around and overwrite 153 * the oldest entry if necessary. 154 */ 155 pl = &pp->pr_log[n]; 156 pl->pl_file = file; 157 pl->pl_line = line; 158 pl->pl_action = action; 159 pl->pl_addr = v; 160 if (++n >= pp->pr_logsize) 161 n = 0; 162 pp->pr_curlogentry = n; 163 } 164 165 static void 166 pr_printlog(pp) 167 struct pool *pp; 168 { 169 int i = pp->pr_logsize; 170 int n = pp->pr_curlogentry; 171 172 if ((pp->pr_flags & PR_LOGGING) == 0) 173 return; 174 175 pool_print(pp, "printlog"); 176 177 /* 178 * Print all entries in this pool's log. 179 */ 180 while (i-- > 0) { 181 struct pool_log *pl = &pp->pr_log[n]; 182 if (pl->pl_action != 0) { 183 printf("log entry %d:\n", i); 184 printf("\taction = %s, addr = %p\n", 185 pl->pl_action == PRLOG_GET ? "get" : "put", 186 pl->pl_addr); 187 printf("\tfile: %s at line %lu\n", 188 pl->pl_file, pl->pl_line); 189 } 190 if (++n >= pp->pr_logsize) 191 n = 0; 192 } 193 } 194 #else 195 #define pr_log(pp, v, action, file, line) 196 #define pr_printlog(pp) 197 #endif 198 199 200 /* 201 * Return the pool page header based on page address. 202 */ 203 static __inline__ struct pool_item_header * 204 pr_find_pagehead(pp, page) 205 struct pool *pp; 206 caddr_t page; 207 { 208 struct pool_item_header *ph; 209 210 if ((pp->pr_flags & PR_PHINPAGE) != 0) 211 return ((struct pool_item_header *)(page + pp->pr_phoffset)); 212 213 for (ph = LIST_FIRST(&pp->pr_hashtab[PR_HASH_INDEX(pp, page)]); 214 ph != NULL; 215 ph = LIST_NEXT(ph, ph_hashlist)) { 216 if (ph->ph_page == page) 217 return (ph); 218 } 219 return (NULL); 220 } 221 222 /* 223 * Remove a page from the pool. 224 */ 225 static __inline__ void 226 pr_rmpage(pp, ph) 227 struct pool *pp; 228 struct pool_item_header *ph; 229 { 230 231 /* 232 * If the page was idle, decrement the idle page count. 233 */ 234 if (ph->ph_nmissing == 0) { 235 #ifdef DIAGNOSTIC 236 if (pp->pr_nidle == 0) 237 panic("pr_rmpage: nidle inconsistent"); 238 #endif 239 pp->pr_nidle--; 240 } 241 242 /* 243 * Unlink a page from the pool and release it. 244 */ 245 TAILQ_REMOVE(&pp->pr_pagelist, ph, ph_pagelist); 246 (*pp->pr_free)(ph->ph_page, pp->pr_pagesz, pp->pr_mtype); 247 pp->pr_npages--; 248 pp->pr_npagefree++; 249 250 if ((pp->pr_flags & PR_PHINPAGE) == 0) { 251 LIST_REMOVE(ph, ph_hashlist); 252 pool_put(&phpool, ph); 253 } 254 255 if (pp->pr_curpage == ph) { 256 /* 257 * Find a new non-empty page header, if any. 258 * Start search from the page head, to increase the 259 * chance for "high water" pages to be freed. 260 */ 261 for (ph = TAILQ_FIRST(&pp->pr_pagelist); ph != NULL; 262 ph = TAILQ_NEXT(ph, ph_pagelist)) 263 if (TAILQ_FIRST(&ph->ph_itemlist) != NULL) 264 break; 265 266 pp->pr_curpage = ph; 267 } 268 } 269 270 /* 271 * Allocate and initialize a pool. 272 */ 273 struct pool * 274 pool_create(size, align, ioff, nitems, wchan, pagesz, alloc, release, mtype) 275 size_t size; 276 u_int align; 277 u_int ioff; 278 int nitems; 279 char *wchan; 280 size_t pagesz; 281 void *(*alloc) __P((unsigned long, int, int)); 282 void (*release) __P((void *, unsigned long, int)); 283 int mtype; 284 { 285 struct pool *pp; 286 int flags; 287 288 pp = (struct pool *)malloc(sizeof(*pp), M_POOL, M_NOWAIT); 289 if (pp == NULL) 290 return (NULL); 291 292 flags = PR_FREEHEADER; 293 #ifdef POOL_DIAGNOSTIC 294 if (pool_logsize != 0) 295 flags |= PR_LOGGING; 296 #endif 297 298 pool_init(pp, size, align, ioff, flags, wchan, pagesz, 299 alloc, release, mtype); 300 301 if (nitems != 0) { 302 if (pool_prime(pp, nitems, NULL) != 0) { 303 pool_destroy(pp); 304 return (NULL); 305 } 306 } 307 308 return (pp); 309 } 310 311 /* 312 * Initialize the given pool resource structure. 313 * 314 * We export this routine to allow other kernel parts to declare 315 * static pools that must be initialized before malloc() is available. 316 */ 317 void 318 pool_init(pp, size, align, ioff, flags, wchan, pagesz, alloc, release, mtype) 319 struct pool *pp; 320 size_t size; 321 u_int align; 322 u_int ioff; 323 int flags; 324 char *wchan; 325 size_t pagesz; 326 void *(*alloc) __P((unsigned long, int, int)); 327 void (*release) __P((void *, unsigned long, int)); 328 int mtype; 329 { 330 int off, slack, i; 331 332 /* 333 * Check arguments and construct default values. 334 */ 335 if (!powerof2(pagesz) || pagesz > PAGE_SIZE) 336 panic("pool_init: page size invalid (%lx)\n", (u_long)pagesz); 337 338 if (alloc == NULL && release == NULL) { 339 alloc = pool_page_alloc; 340 release = pool_page_free; 341 pagesz = PAGE_SIZE; /* Rounds to PAGE_SIZE anyhow. */ 342 } else if ((alloc != NULL && release != NULL) == 0) { 343 /* If you specifiy one, must specify both. */ 344 panic("pool_init: must specify alloc and release together"); 345 } 346 347 if (pagesz == 0) 348 pagesz = PAGE_SIZE; 349 350 if (align == 0) 351 align = ALIGN(1); 352 353 if (size < sizeof(struct pool_item)) 354 size = sizeof(struct pool_item); 355 356 /* 357 * Initialize the pool structure. 358 */ 359 TAILQ_INSERT_TAIL(&pool_head, pp, pr_poollist); 360 TAILQ_INIT(&pp->pr_pagelist); 361 pp->pr_curpage = NULL; 362 pp->pr_npages = 0; 363 pp->pr_minitems = 0; 364 pp->pr_minpages = 0; 365 pp->pr_maxpages = UINT_MAX; 366 pp->pr_flags = flags; 367 pp->pr_size = ALIGN(size); 368 pp->pr_align = align; 369 pp->pr_wchan = wchan; 370 pp->pr_mtype = mtype; 371 pp->pr_alloc = alloc; 372 pp->pr_free = release; 373 pp->pr_pagesz = pagesz; 374 pp->pr_pagemask = ~(pagesz - 1); 375 pp->pr_pageshift = ffs(pagesz) - 1; 376 377 /* 378 * Decide whether to put the page header off page to avoid 379 * wasting too large a part of the page. Off-page page headers 380 * go on a hash table, so we can match a returned item 381 * with its header based on the page address. 382 * We use 1/16 of the page size as the threshold (XXX: tune) 383 */ 384 if (pp->pr_size < pagesz/16) { 385 /* Use the end of the page for the page header */ 386 pp->pr_flags |= PR_PHINPAGE; 387 pp->pr_phoffset = off = 388 pagesz - ALIGN(sizeof(struct pool_item_header)); 389 } else { 390 /* The page header will be taken from our page header pool */ 391 pp->pr_phoffset = 0; 392 off = pagesz; 393 for (i = 0; i < PR_HASHTABSIZE; i++) { 394 LIST_INIT(&pp->pr_hashtab[i]); 395 } 396 } 397 398 /* 399 * Alignment is to take place at `ioff' within the item. This means 400 * we must reserve up to `align - 1' bytes on the page to allow 401 * appropriate positioning of each item. 402 * 403 * Silently enforce `0 <= ioff < align'. 404 */ 405 pp->pr_itemoffset = ioff = ioff % align; 406 pp->pr_itemsperpage = (off - ((align - ioff) % align)) / pp->pr_size; 407 408 /* 409 * Use the slack between the chunks and the page header 410 * for "cache coloring". 411 */ 412 slack = off - pp->pr_itemsperpage * pp->pr_size; 413 pp->pr_maxcolor = (slack / align) * align; 414 pp->pr_curcolor = 0; 415 416 pp->pr_nget = 0; 417 pp->pr_nfail = 0; 418 pp->pr_nput = 0; 419 pp->pr_npagealloc = 0; 420 pp->pr_npagefree = 0; 421 pp->pr_hiwat = 0; 422 pp->pr_nidle = 0; 423 424 #ifdef POOL_DIAGNOSTIC 425 if ((flags & PR_LOGGING) != 0) { 426 pp->pr_log = malloc(pool_logsize * sizeof(struct pool_log), 427 M_TEMP, M_NOWAIT); 428 if (pp->pr_log == NULL) 429 pp->pr_flags &= ~PR_LOGGING; 430 pp->pr_curlogentry = 0; 431 pp->pr_logsize = pool_logsize; 432 } 433 #endif 434 435 simple_lock_init(&pp->pr_lock); 436 lockinit(&pp->pr_resourcelock, PSWP, wchan, 0, 0); 437 438 /* 439 * Initialize private page header pool if we haven't done so yet. 440 */ 441 if (phpool.pr_size == 0) { 442 pool_init(&phpool, sizeof(struct pool_item_header), 0, 0, 443 0, "phpool", 0, 0, 0, 0); 444 } 445 446 return; 447 } 448 449 /* 450 * De-commision a pool resource. 451 */ 452 void 453 pool_destroy(pp) 454 struct pool *pp; 455 { 456 struct pool_item_header *ph; 457 458 #ifdef DIAGNOSTIC 459 if (pp->pr_nget - pp->pr_nput != 0) { 460 pr_printlog(pp); 461 panic("pool_destroy: pool busy: still out: %lu\n", 462 pp->pr_nget - pp->pr_nput); 463 } 464 #endif 465 466 /* Remove all pages */ 467 if ((pp->pr_flags & PR_STATIC) == 0) 468 while ((ph = pp->pr_pagelist.tqh_first) != NULL) 469 pr_rmpage(pp, ph); 470 471 /* Remove from global pool list */ 472 TAILQ_REMOVE(&pool_head, pp, pr_poollist); 473 drainpp = NULL; 474 475 #ifdef POOL_DIAGNOSTIC 476 if ((pp->pr_flags & PR_LOGGING) != 0) 477 free(pp->pr_log, M_TEMP); 478 #endif 479 480 if (pp->pr_flags & PR_FREEHEADER) 481 free(pp, M_POOL); 482 } 483 484 485 /* 486 * Grab an item from the pool; must be called at appropriate spl level 487 */ 488 #ifdef POOL_DIAGNOSTIC 489 void * 490 _pool_get(pp, flags, file, line) 491 struct pool *pp; 492 int flags; 493 const char *file; 494 long line; 495 #else 496 void * 497 pool_get(pp, flags) 498 struct pool *pp; 499 int flags; 500 #endif 501 { 502 void *v; 503 struct pool_item *pi; 504 struct pool_item_header *ph; 505 506 #ifdef DIAGNOSTIC 507 if ((pp->pr_flags & PR_STATIC) && (flags & PR_MALLOCOK)) { 508 pr_printlog(pp); 509 panic("pool_get: static"); 510 } 511 #endif 512 513 simple_lock(&pp->pr_lock); 514 if (curproc == NULL && (flags & PR_WAITOK) != 0) 515 panic("pool_get: must have NOWAIT"); 516 517 /* 518 * The convention we use is that if `curpage' is not NULL, then 519 * it points at a non-empty bucket. In particular, `curpage' 520 * never points at a page header which has PR_PHINPAGE set and 521 * has no items in its bucket. 522 */ 523 while ((ph = pp->pr_curpage) == NULL) { 524 void *v; 525 int lkflags = LK_EXCLUSIVE | LK_INTERLOCK | 526 ((flags & PR_WAITOK) == 0 ? LK_NOWAIT : 0); 527 528 /* Get long-term lock on pool */ 529 if (lockmgr(&pp->pr_resourcelock, lkflags, &pp->pr_lock) != 0) 530 return (NULL); 531 532 /* Check if pool became non-empty while we slept */ 533 if ((ph = pp->pr_curpage) != NULL) 534 goto again; 535 536 /* Call the page back-end allocator for more memory */ 537 v = (*pp->pr_alloc)(pp->pr_pagesz, flags, pp->pr_mtype); 538 if (v == NULL) { 539 if (flags & PR_URGENT) 540 panic("pool_get: urgent"); 541 if ((flags & PR_WAITOK) == 0) { 542 pp->pr_nfail++; 543 lockmgr(&pp->pr_resourcelock, LK_RELEASE, NULL); 544 return (NULL); 545 } 546 547 /* 548 * Wait for items to be returned to this pool. 549 * XXX: we actually want to wait just until 550 * the page allocator has memory again. Depending 551 * on this pool's usage, we might get stuck here 552 * for a long time. 553 */ 554 pp->pr_flags |= PR_WANTED; 555 lockmgr(&pp->pr_resourcelock, LK_RELEASE, NULL); 556 tsleep((caddr_t)pp, PSWP, pp->pr_wchan, 0); 557 simple_lock(&pp->pr_lock); 558 continue; 559 } 560 561 /* We have more memory; add it to the pool */ 562 pp->pr_npagealloc++; 563 pool_prime_page(pp, v); 564 565 again: 566 /* Re-acquire pool interlock */ 567 simple_lock(&pp->pr_lock); 568 lockmgr(&pp->pr_resourcelock, LK_RELEASE, NULL); 569 } 570 571 if ((v = pi = TAILQ_FIRST(&ph->ph_itemlist)) == NULL) 572 panic("pool_get: %s: page empty", pp->pr_wchan); 573 574 pr_log(pp, v, PRLOG_GET, file, line); 575 576 #ifdef DIAGNOSTIC 577 if (pi->pi_magic != PI_MAGIC) { 578 pr_printlog(pp); 579 panic("pool_get(%s): free list modified: magic=%x; page %p;" 580 " item addr %p\n", 581 pp->pr_wchan, pi->pi_magic, ph->ph_page, pi); 582 } 583 #endif 584 585 /* 586 * Remove from item list. 587 */ 588 TAILQ_REMOVE(&ph->ph_itemlist, pi, pi_list); 589 if (ph->ph_nmissing == 0) { 590 #ifdef DIAGNOSTIC 591 if (pp->pr_nidle == 0) 592 panic("pool_get: nidle inconsistent"); 593 #endif 594 pp->pr_nidle--; 595 } 596 ph->ph_nmissing++; 597 if (TAILQ_FIRST(&ph->ph_itemlist) == NULL) { 598 /* 599 * Find a new non-empty page header, if any. 600 * Start search from the page head, to increase 601 * the chance for "high water" pages to be freed. 602 * 603 * First, move the now empty page to the head of 604 * the page list. 605 */ 606 TAILQ_REMOVE(&pp->pr_pagelist, ph, ph_pagelist); 607 TAILQ_INSERT_HEAD(&pp->pr_pagelist, ph, ph_pagelist); 608 while ((ph = TAILQ_NEXT(ph, ph_pagelist)) != NULL) 609 if (TAILQ_FIRST(&ph->ph_itemlist) != NULL) 610 break; 611 612 pp->pr_curpage = ph; 613 } 614 615 pp->pr_nget++; 616 simple_unlock(&pp->pr_lock); 617 return (v); 618 } 619 620 /* 621 * Return resource to the pool; must be called at appropriate spl level 622 */ 623 #ifdef POOL_DIAGNOSTIC 624 void 625 _pool_put(pp, v, file, line) 626 struct pool *pp; 627 void *v; 628 const char *file; 629 long line; 630 #else 631 void 632 pool_put(pp, v) 633 struct pool *pp; 634 void *v; 635 #endif 636 { 637 struct pool_item *pi = v; 638 struct pool_item_header *ph; 639 caddr_t page; 640 641 page = (caddr_t)((u_long)v & pp->pr_pagemask); 642 643 simple_lock(&pp->pr_lock); 644 645 pr_log(pp, v, PRLOG_PUT, file, line); 646 647 if ((ph = pr_find_pagehead(pp, page)) == NULL) { 648 pr_printlog(pp); 649 panic("pool_put: %s: page header missing", pp->pr_wchan); 650 } 651 652 /* 653 * Return to item list. 654 */ 655 #ifdef DIAGNOSTIC 656 pi->pi_magic = PI_MAGIC; 657 #endif 658 TAILQ_INSERT_HEAD(&ph->ph_itemlist, pi, pi_list); 659 ph->ph_nmissing--; 660 pp->pr_nput++; 661 662 /* Cancel "pool empty" condition if it exists */ 663 if (pp->pr_curpage == NULL) 664 pp->pr_curpage = ph; 665 666 if (pp->pr_flags & PR_WANTED) { 667 pp->pr_flags &= ~PR_WANTED; 668 if (ph->ph_nmissing == 0) 669 pp->pr_nidle++; 670 wakeup((caddr_t)pp); 671 simple_unlock(&pp->pr_lock); 672 return; 673 } 674 675 /* 676 * If this page is now complete, move it to the end of the pagelist. 677 * If this page has just become un-empty, move it the head. 678 */ 679 if (ph->ph_nmissing == 0) { 680 pp->pr_nidle++; 681 if (pp->pr_npages > pp->pr_maxpages) { 682 #if 0 683 timeout(pool_drain, 0, pool_inactive_time*hz); 684 #else 685 pr_rmpage(pp, ph); 686 #endif 687 } else { 688 TAILQ_REMOVE(&pp->pr_pagelist, ph, ph_pagelist); 689 TAILQ_INSERT_TAIL(&pp->pr_pagelist, ph, ph_pagelist); 690 ph->ph_time = time; 691 692 /* XXX - update curpage */ 693 for (ph = TAILQ_FIRST(&pp->pr_pagelist); ph != NULL; 694 ph = TAILQ_NEXT(ph, ph_pagelist)) 695 if (TAILQ_FIRST(&ph->ph_itemlist) != NULL) 696 break; 697 698 pp->pr_curpage = ph; 699 } 700 } 701 702 simple_unlock(&pp->pr_lock); 703 } 704 705 /* 706 * Add N items to the pool. 707 */ 708 int 709 pool_prime(pp, n, storage) 710 struct pool *pp; 711 int n; 712 caddr_t storage; 713 { 714 caddr_t cp; 715 int newnitems, newpages; 716 717 #ifdef DIAGNOSTIC 718 if (storage && !(pp->pr_flags & PR_STATIC)) 719 panic("pool_prime: static"); 720 /* !storage && static caught below */ 721 #endif 722 723 (void)lockmgr(&pp->pr_resourcelock, LK_EXCLUSIVE, NULL); 724 newnitems = pp->pr_minitems + n; 725 newpages = 726 roundup(pp->pr_itemsperpage,newnitems) / pp->pr_itemsperpage 727 - pp->pr_minpages; 728 729 while (newpages-- > 0) { 730 731 if (pp->pr_flags & PR_STATIC) { 732 cp = storage; 733 storage += pp->pr_pagesz; 734 } else { 735 cp = (*pp->pr_alloc)(pp->pr_pagesz, 0, pp->pr_mtype); 736 } 737 738 if (cp == NULL) { 739 (void)lockmgr(&pp->pr_resourcelock, LK_RELEASE, NULL); 740 return (ENOMEM); 741 } 742 743 pool_prime_page(pp, cp); 744 pp->pr_minpages++; 745 } 746 747 pp->pr_minitems = newnitems; 748 749 if (pp->pr_minpages >= pp->pr_maxpages) 750 pp->pr_maxpages = pp->pr_minpages + 1; /* XXX */ 751 752 (void)lockmgr(&pp->pr_resourcelock, LK_RELEASE, NULL); 753 return (0); 754 } 755 756 /* 757 * Add a page worth of items to the pool. 758 */ 759 int 760 pool_prime_page(pp, storage) 761 struct pool *pp; 762 caddr_t storage; 763 { 764 struct pool_item *pi; 765 struct pool_item_header *ph; 766 caddr_t cp = storage; 767 unsigned int align = pp->pr_align; 768 unsigned int ioff = pp->pr_itemoffset; 769 int n; 770 771 simple_lock(&pp->pr_lock); 772 773 if ((pp->pr_flags & PR_PHINPAGE) != 0) { 774 ph = (struct pool_item_header *)(cp + pp->pr_phoffset); 775 } else { 776 ph = pool_get(&phpool, PR_URGENT); 777 LIST_INSERT_HEAD(&pp->pr_hashtab[PR_HASH_INDEX(pp, cp)], 778 ph, ph_hashlist); 779 } 780 781 /* 782 * Insert page header. 783 */ 784 TAILQ_INSERT_HEAD(&pp->pr_pagelist, ph, ph_pagelist); 785 TAILQ_INIT(&ph->ph_itemlist); 786 ph->ph_page = storage; 787 ph->ph_nmissing = 0; 788 ph->ph_time.tv_sec = ph->ph_time.tv_usec = 0; 789 790 pp->pr_nidle++; 791 792 /* 793 * Color this page. 794 */ 795 cp = (caddr_t)(cp + pp->pr_curcolor); 796 if ((pp->pr_curcolor += align) > pp->pr_maxcolor) 797 pp->pr_curcolor = 0; 798 799 /* 800 * Adjust storage to apply aligment to `pr_itemoffset' in each item. 801 */ 802 if (ioff != 0) 803 cp = (caddr_t)(cp + (align - ioff)); 804 805 /* 806 * Insert remaining chunks on the bucket list. 807 */ 808 n = pp->pr_itemsperpage; 809 810 while (n--) { 811 pi = (struct pool_item *)cp; 812 813 /* Insert on page list */ 814 TAILQ_INSERT_TAIL(&ph->ph_itemlist, pi, pi_list); 815 #ifdef DIAGNOSTIC 816 pi->pi_magic = PI_MAGIC; 817 #endif 818 cp = (caddr_t)(cp + pp->pr_size); 819 } 820 821 /* 822 * If the pool was depleted, point at the new page. 823 */ 824 if (pp->pr_curpage == NULL) 825 pp->pr_curpage = ph; 826 827 if (++pp->pr_npages > pp->pr_hiwat) 828 pp->pr_hiwat = pp->pr_npages; 829 830 simple_unlock(&pp->pr_lock); 831 return (0); 832 } 833 834 void 835 pool_setlowat(pp, n) 836 pool_handle_t pp; 837 int n; 838 { 839 840 (void)lockmgr(&pp->pr_resourcelock, LK_EXCLUSIVE, NULL); 841 pp->pr_minitems = n; 842 pp->pr_minpages = (n == 0) 843 ? 0 844 : roundup(pp->pr_itemsperpage,n) / pp->pr_itemsperpage; 845 (void)lockmgr(&pp->pr_resourcelock, LK_RELEASE, NULL); 846 } 847 848 void 849 pool_sethiwat(pp, n) 850 pool_handle_t pp; 851 int n; 852 { 853 854 (void)lockmgr(&pp->pr_resourcelock, LK_EXCLUSIVE, NULL); 855 pp->pr_maxpages = (n == 0) 856 ? 0 857 : roundup(pp->pr_itemsperpage,n) / pp->pr_itemsperpage; 858 (void)lockmgr(&pp->pr_resourcelock, LK_RELEASE, NULL); 859 } 860 861 862 /* 863 * Default page allocator. 864 */ 865 static void * 866 pool_page_alloc(sz, flags, mtype) 867 unsigned long sz; 868 int flags; 869 int mtype; 870 { 871 boolean_t waitok = (flags & PR_WAITOK) ? TRUE : FALSE; 872 873 #if defined(UVM) 874 return ((void *)uvm_km_alloc_poolpage(waitok)); 875 #else 876 return ((void *)kmem_alloc_poolpage(waitok)); 877 #endif 878 } 879 880 static void 881 pool_page_free(v, sz, mtype) 882 void *v; 883 unsigned long sz; 884 int mtype; 885 { 886 887 #if defined(UVM) 888 uvm_km_free_poolpage((vaddr_t)v); 889 #else 890 kmem_free_poolpage((vaddr_t)v); 891 #endif 892 } 893 894 /* 895 * Alternate pool page allocator for pools that know they will 896 * never be accessed in interrupt context. 897 */ 898 void * 899 pool_page_alloc_nointr(sz, flags, mtype) 900 unsigned long sz; 901 int flags; 902 int mtype; 903 { 904 #if defined(UVM) 905 boolean_t waitok = (flags & PR_WAITOK) ? TRUE : FALSE; 906 907 /* 908 * With UVM, we can use the kernel_map. 909 */ 910 return ((void *)uvm_km_alloc_poolpage1(kernel_map, uvm.kernel_object, 911 waitok)); 912 #else 913 /* 914 * Can't do anything so cool with Mach VM. 915 */ 916 return (pool_page_alloc(sz, flags, mtype)); 917 #endif 918 } 919 920 void 921 pool_page_free_nointr(v, sz, mtype) 922 void *v; 923 unsigned long sz; 924 int mtype; 925 { 926 927 #if defined(UVM) 928 uvm_km_free_poolpage1(kernel_map, (vaddr_t)v); 929 #else 930 pool_page_free(v, sz, mtype); 931 #endif 932 } 933 934 935 /* 936 * Release all complete pages that have not been used recently. 937 */ 938 void 939 pool_reclaim (pp) 940 pool_handle_t pp; 941 { 942 struct pool_item_header *ph, *phnext; 943 struct timeval curtime = time; 944 945 if (pp->pr_flags & PR_STATIC) 946 return; 947 948 if (simple_lock_try(&pp->pr_lock) == 0) 949 return; 950 951 for (ph = TAILQ_FIRST(&pp->pr_pagelist); ph != NULL; ph = phnext) { 952 phnext = TAILQ_NEXT(ph, ph_pagelist); 953 954 /* Check our minimum page claim */ 955 if (pp->pr_npages <= pp->pr_minpages) 956 break; 957 958 if (ph->ph_nmissing == 0) { 959 struct timeval diff; 960 timersub(&curtime, &ph->ph_time, &diff); 961 if (diff.tv_sec < pool_inactive_time) 962 continue; 963 pr_rmpage(pp, ph); 964 } 965 } 966 967 simple_unlock(&pp->pr_lock); 968 } 969 970 971 /* 972 * Drain pools, one at a time. 973 */ 974 void 975 pool_drain(arg) 976 void *arg; 977 { 978 struct pool *pp; 979 int s = splimp(); 980 981 /* XXX:lock pool head */ 982 if (drainpp == NULL && (drainpp = TAILQ_FIRST(&pool_head)) == NULL) { 983 splx(s); 984 return; 985 } 986 987 pp = drainpp; 988 drainpp = TAILQ_NEXT(pp, pr_poollist); 989 /* XXX:unlock pool head */ 990 991 pool_reclaim(pp); 992 splx(s); 993 } 994 995 996 #if defined(POOL_DIAGNOSTIC) || defined(DEBUG) 997 /* 998 * Diagnostic helpers. 999 */ 1000 void 1001 pool_print(pp, label) 1002 struct pool *pp; 1003 char *label; 1004 { 1005 1006 if (label != NULL) 1007 printf("%s: ", label); 1008 1009 printf("pool %s: nalloc %lu nfree %lu npagealloc %lu npagefree %lu\n" 1010 " npages %u minitems %u itemsperpage %u itemoffset %u\n" 1011 " nidle %lu\n", 1012 pp->pr_wchan, 1013 pp->pr_nget, 1014 pp->pr_nput, 1015 pp->pr_npagealloc, 1016 pp->pr_npagefree, 1017 pp->pr_npages, 1018 pp->pr_minitems, 1019 pp->pr_itemsperpage, 1020 pp->pr_itemoffset, 1021 pp->pr_nidle); 1022 } 1023 1024 int 1025 pool_chk(pp, label) 1026 struct pool *pp; 1027 char *label; 1028 { 1029 struct pool_item_header *ph; 1030 int r = 0; 1031 1032 simple_lock(&pp->pr_lock); 1033 1034 for (ph = TAILQ_FIRST(&pp->pr_pagelist); ph != NULL; 1035 ph = TAILQ_NEXT(ph, ph_pagelist)) { 1036 1037 struct pool_item *pi; 1038 int n; 1039 caddr_t page; 1040 1041 page = (caddr_t)((u_long)ph & pp->pr_pagemask); 1042 if (page != ph->ph_page && (pp->pr_flags & PR_PHINPAGE) != 0) { 1043 if (label != NULL) 1044 printf("%s: ", label); 1045 printf("pool(%p:%s): page inconsistency: page %p;" 1046 " at page head addr %p (p %p)\n", pp, 1047 pp->pr_wchan, ph->ph_page, 1048 ph, page); 1049 r++; 1050 goto out; 1051 } 1052 1053 for (pi = TAILQ_FIRST(&ph->ph_itemlist), n = 0; 1054 pi != NULL; 1055 pi = TAILQ_NEXT(pi,pi_list), n++) { 1056 1057 #ifdef DIAGNOSTIC 1058 if (pi->pi_magic != PI_MAGIC) { 1059 if (label != NULL) 1060 printf("%s: ", label); 1061 printf("pool(%s): free list modified: magic=%x;" 1062 " page %p; item ordinal %d;" 1063 " addr %p (p %p)\n", 1064 pp->pr_wchan, pi->pi_magic, ph->ph_page, 1065 n, pi, page); 1066 panic("pool"); 1067 } 1068 #endif 1069 page = (caddr_t)((u_long)pi & pp->pr_pagemask); 1070 if (page == ph->ph_page) 1071 continue; 1072 1073 if (label != NULL) 1074 printf("%s: ", label); 1075 printf("pool(%p:%s): page inconsistency: page %p;" 1076 " item ordinal %d; addr %p (p %p)\n", pp, 1077 pp->pr_wchan, ph->ph_page, 1078 n, pi, page); 1079 r++; 1080 goto out; 1081 } 1082 } 1083 out: 1084 simple_unlock(&pp->pr_lock); 1085 return (r); 1086 } 1087 #endif /* POOL_DIAGNOSTIC || DEBUG */ 1088