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