summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2011-07-05 16:36:16 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2011-07-05 16:36:16 +0000
commit097154c740b46d3a8c8dbf722433af1590aadad0 (patch)
treefaf15612559f1cfd92dd9192d4e61ddc06e708ac /sys/kern
parent037453b4d9fe9eb71bfb5b842d9e9fa77e69ad96 (diff)
when all you have is a hammer, make it a big one. add more checks to pool_chk
and a pool_init flag to aggressively run pool_chk. ok art deraadt
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/subr_pool.c64
1 files changed, 50 insertions, 14 deletions
diff --git a/sys/kern/subr_pool.c b/sys/kern/subr_pool.c
index fcc74a92fd6..29e1bbb6576 100644
--- a/sys/kern/subr_pool.c
+++ b/sys/kern/subr_pool.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_pool.c,v 1.104 2011/04/18 19:23:46 art Exp $ */
+/* $OpenBSD: subr_pool.c,v 1.105 2011/07/05 16:36:15 tedu Exp $ */
/* $NetBSD: subr_pool.c,v 1.61 2001/09/26 07:14:56 chs Exp $ */
/*-
@@ -113,7 +113,7 @@ void *pool_do_get(struct pool *, int);
void pool_do_put(struct pool *, void *);
void pr_rmpage(struct pool *, struct pool_item_header *,
struct pool_pagelist *);
-int pool_chk_page(struct pool *, const char *, struct pool_item_header *);
+int pool_chk_page(struct pool *, struct pool_item_header *, int);
struct pool_item_header *pool_alloc_item_header(struct pool *, caddr_t , int);
void *pool_allocator_alloc(struct pool *, int, int *);
@@ -468,7 +468,19 @@ pool_get(struct pool *pp, int flags)
#endif /* DIAGNOSTIC */
mtx_enter(&pp->pr_mtx);
+#ifdef POOL_DEBUG
+ if (pp->pr_roflags & PR_DEBUGCHK) {
+ if (pool_chk(pp))
+ panic("before pool_get");
+ }
+#endif
v = pool_do_get(pp, flags);
+#ifdef POOL_DEBUG
+ if (pp->pr_roflags & PR_DEBUGCHK) {
+ if (pool_chk(pp))
+ panic("after pool_get");
+ }
+#endif
mtx_leave(&pp->pr_mtx);
if (v == NULL)
return (v);
@@ -692,7 +704,19 @@ pool_put(struct pool *pp, void *v)
if (pp->pr_dtor)
pp->pr_dtor(pp->pr_arg, v);
mtx_enter(&pp->pr_mtx);
+#ifdef POOL_DEBUG
+ if (pp->pr_roflags & PR_DEBUGCHK) {
+ if (pool_chk(pp))
+ panic("before pool_put");
+ }
+#endif
pool_do_put(pp, v);
+#ifdef POOL_DEBUG
+ if (pp->pr_roflags & PR_DEBUGCHK) {
+ if (pool_chk(pp))
+ panic("after pool_put");
+ }
+#endif
mtx_leave(&pp->pr_mtx);
pp->pr_nput++;
}
@@ -1237,12 +1261,12 @@ db_show_all_pools(db_expr_t expr, int haddr, db_expr_t count, char *modif)
PRWORD(ovflw, " %*s", 6, 1, maxp);
PRWORD(ovflw, " %*lu\n", 5, 1, pp->pr_nidle);
- pool_chk(pp, pp->pr_wchan);
+ pool_chk(pp);
}
}
int
-pool_chk_page(struct pool *pp, const char *label, struct pool_item_header *ph)
+pool_chk_page(struct pool *pp, struct pool_item_header *ph, int expected)
{
struct pool_item *pi;
caddr_t page;
@@ -1250,12 +1274,12 @@ pool_chk_page(struct pool *pp, const char *label, struct pool_item_header *ph)
#if defined(DIAGNOSTIC) && defined(POOL_DEBUG)
int i, *ip;
#endif
+ const char *label = pp->pr_wchan;
page = (caddr_t)((u_long)ph & pp->pr_alloc->pa_pagemask);
if (page != ph->ph_page &&
(pp->pr_roflags & PR_PHINPAGE) != 0) {
- if (label != NULL)
- printf("%s: ", label);
+ printf("%s: ", label);
printf("pool(%p:%s): page inconsistency: page %p; "
"at page head addr %p (p %p)\n",
pp, pp->pr_wchan, ph->ph_page, ph, page);
@@ -1268,8 +1292,7 @@ pool_chk_page(struct pool *pp, const char *label, struct pool_item_header *ph)
#ifdef DIAGNOSTIC
if (pi->pi_magic != PI_MAGIC) {
- if (label != NULL)
- printf("%s: ", label);
+ printf("%s: ", label);
printf("pool(%s): free list modified: "
"page %p; item ordinal %d; addr %p "
"(p %p); offset 0x%x=0x%x\n",
@@ -1297,28 +1320,41 @@ pool_chk_page(struct pool *pp, const char *label, struct pool_item_header *ph)
if (page == ph->ph_page)
continue;
- if (label != NULL)
- printf("%s: ", label);
+ printf("%s: ", label);
printf("pool(%p:%s): page inconsistency: page %p;"
" item ordinal %d; addr %p (p %p)\n", pp,
pp->pr_wchan, ph->ph_page, n, pi, page);
return 1;
}
+ if (n + ph->ph_nmissing != pp->pr_itemsperpage) {
+ printf("pool(%p:%s): page inconsistency: page %p;"
+ " %d on list, %d missing, %d items per page\n", pp,
+ pp->pr_wchan, ph->ph_page, n, ph->ph_nmissing,
+ pp->pr_itemsperpage);
+ return 1;
+ }
+ if (expected >= 0 && n != expected) {
+ printf("pool(%p:%s): page inconsistency: page %p;"
+ " %d on list, %d missing, %d expected\n", pp,
+ pp->pr_wchan, ph->ph_page, n, ph->ph_nmissing,
+ expected);
+ return 1;
+ }
return 0;
}
int
-pool_chk(struct pool *pp, const char *label)
+pool_chk(struct pool *pp)
{
struct pool_item_header *ph;
int r = 0;
LIST_FOREACH(ph, &pp->pr_emptypages, ph_pagelist)
- r += pool_chk_page(pp, label, ph);
+ r += pool_chk_page(pp, ph, pp->pr_itemsperpage);
LIST_FOREACH(ph, &pp->pr_fullpages, ph_pagelist)
- r += pool_chk_page(pp, label, ph);
+ r += pool_chk_page(pp, ph, 0);
LIST_FOREACH(ph, &pp->pr_partpages, ph_pagelist)
- r += pool_chk_page(pp, label, ph);
+ r += pool_chk_page(pp, ph, -1);
return (r);
}