summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2002-01-10 18:56:04 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2002-01-10 18:56:04 +0000
commit51d44c76f8259d5eb15095863f32c368b5fd3efc (patch)
tree2e5626b178726766d43ff7b6a5dea681ebda1670 /sys
parente9c6e921cbf915e3537c1d55444c53cb844eca18 (diff)
Fix a locking error in pool_drain. Misc cleanup.
From NetBSD.
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/subr_pool.c93
1 files changed, 63 insertions, 30 deletions
diff --git a/sys/kern/subr_pool.c b/sys/kern/subr_pool.c
index 5f9f1c78cd1..18d1ca0a1a4 100644
--- a/sys/kern/subr_pool.c
+++ b/sys/kern/subr_pool.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: subr_pool.c,v 1.18 2002/01/10 14:31:17 art Exp $ */
-/* $NetBSD: subr_pool.c,v 1.59 2001/06/05 18:51:04 thorpej Exp $ */
+/* $OpenBSD: subr_pool.c,v 1.19 2002/01/10 18:56:03 art Exp $ */
+/* $NetBSD: subr_pool.c,v 1.61 2001/09/26 07:14:56 chs Exp $ */
/*-
* Copyright (c) 1997, 1999, 2000 The NetBSD Foundation, Inc.
@@ -97,6 +97,7 @@ struct pool_item_header {
caddr_t ph_page; /* this page's address */
struct timeval ph_time; /* last referenced */
};
+TAILQ_HEAD(pool_pagelist,pool_item_header);
struct pool_item {
#ifdef DIAGNOSTIC
@@ -271,7 +272,7 @@ pr_leave(struct pool *pp)
pp->pr_entered_line = 0;
}
-static __inline__ void
+static __inline void
pr_enter_check(struct pool *pp, int (*pr)(const char *, ...))
{
@@ -311,8 +312,10 @@ pr_find_pagehead(struct pool *pp, caddr_t page)
* Remove a page from the pool.
*/
static __inline void
-pr_rmpage(struct pool *pp, struct pool_item_header *ph)
+pr_rmpage(struct pool *pp, struct pool_item_header *ph,
+ struct pool_pagelist *pq)
{
+ int s;
/*
* If the page was idle, decrement the idle page count.
@@ -330,21 +333,23 @@ pr_rmpage(struct pool *pp, struct pool_item_header *ph)
pp->pr_nitems -= pp->pr_itemsperpage;
/*
- * Unlink a page from the pool and release it.
+ * Unlink a page from the pool and release it (or queue it for release).
*/
TAILQ_REMOVE(&pp->pr_pagelist, ph, ph_pagelist);
- (*pp->pr_free)(ph->ph_page, pp->pr_pagesz, pp->pr_mtype);
+ if (pq) {
+ TAILQ_INSERT_HEAD(pq, ph, ph_pagelist);
+ } else {
+ (*pp->pr_free)(ph->ph_page, pp->pr_pagesz, pp->pr_mtype);
+ if ((pp->pr_roflags & PR_PHINPAGE) == 0) {
+ LIST_REMOVE(ph, ph_hashlist);
+ s = splhigh();
+ pool_put(&phpool, ph);
+ splx(s);
+ }
+ }
pp->pr_npages--;
pp->pr_npagefree++;
- if ((pp->pr_roflags & PR_PHINPAGE) == 0) {
- int s;
- LIST_REMOVE(ph, ph_hashlist);
- s = splhigh();
- pool_put(&phpool, ph);
- splx(s);
- }
-
if (pp->pr_curpage == ph) {
/*
* Find a new non-empty page header, if any.
@@ -549,14 +554,15 @@ pool_destroy(struct pool *pp)
/* Remove all pages */
if ((pp->pr_roflags & PR_STATIC) == 0)
- while ((ph = pp->pr_pagelist.tqh_first) != NULL)
- pr_rmpage(pp, ph);
+ while ((ph = TAILQ_FIRST(&pp->pr_pagelist)) != NULL)
+ pr_rmpage(pp, ph, NULL);
/* Remove from global pool list */
simple_lock(&pool_head_slock);
TAILQ_REMOVE(&pool_head, pp, pr_poollist);
- /* XXX Only clear this if we were drainpp? */
- drainpp = NULL;
+ if (drainpp == pp) {
+ drainpp = NULL;
+ }
simple_unlock(&pool_head_slock);
#ifdef POOL_DIAGNOSTIC
@@ -612,7 +618,12 @@ pool_get(struct pool *pp, int flags)
(flags & PR_WAITOK) != 0))
panic("pool_get: must have NOWAIT");
+#ifdef LOCKDEBUG
+ if (flags & PR_WAITOK)
+ simple_lock_only_held(NULL, "pool_get(PR_WAITOK)");
#endif
+#endif /* DIAGNOSTIC */
+
simple_lock(&pp->pr_slock);
pr_enter(pp, file, line);
@@ -751,9 +762,13 @@ pool_get(struct pool *pp, int flags)
pp->pr_wchan, pp->pr_nitems);
panic("pool_get: nitems inconsistent\n");
}
+#endif
+#ifdef POOL_DIAGNOSTIC
pr_log(pp, v, PRLOG_GET, file, line);
+#endif
+#ifdef DIAGNOSTIC
if (__predict_false(pi->pi_magic != PI_MAGIC)) {
pr_printlog(pp, pi, printf);
panic("pool_get(%s): free list modified: magic=%x; page %p;"
@@ -835,6 +850,8 @@ pool_do_put(struct pool *pp, void *v)
caddr_t page;
int s;
+ LOCK_ASSERT(simple_lock_held(&pp->pr_slock));
+
page = (caddr_t)((u_long)v & pp->pr_pagemask);
#ifdef DIAGNOSTIC
@@ -908,7 +925,7 @@ pool_do_put(struct pool *pp, void *v)
if (ph->ph_nmissing == 0) {
pp->pr_nidle++;
if (pp->pr_npages > pp->pr_maxpages) {
- pr_rmpage(pp, ph);
+ pr_rmpage(pp, ph, NULL);
} else {
TAILQ_REMOVE(&pp->pr_pagelist, ph, ph_pagelist);
TAILQ_INSERT_TAIL(&pp->pr_pagelist, ph, ph_pagelist);
@@ -1228,6 +1245,7 @@ pool_page_alloc(unsigned long sz, int flags, int mtype)
static void
pool_page_free(void *v, unsigned long sz, int mtype)
{
+
uvm_km_free_poolpage((vaddr_t)v);
}
@@ -1265,6 +1283,7 @@ pool_reclaim(struct pool *pp)
struct pool_item_header *ph, *phnext;
struct pool_cache *pc;
struct timeval curtime;
+ struct pool_pagelist pq;
int s;
if (pp->pr_roflags & PR_STATIC)
@@ -1273,6 +1292,7 @@ pool_reclaim(struct pool *pp)
if (simple_lock_try(&pp->pr_slock) == 0)
return;
pr_enter(pp, file, line);
+ TAILQ_INIT(&pq);
/*
* Reclaim items from the pool's caches.
@@ -1305,12 +1325,26 @@ pool_reclaim(struct pool *pp)
pp->pr_minitems)
break;
- pr_rmpage(pp, ph);
+ pr_rmpage(pp, ph, &pq);
}
}
pr_leave(pp);
simple_unlock(&pp->pr_slock);
+ if (TAILQ_EMPTY(&pq)) {
+ return;
+ }
+ while ((ph = TAILQ_FIRST(&pq)) != NULL) {
+ TAILQ_REMOVE(&pq, ph, ph_pagelist);
+ (*pp->pr_free)(ph->ph_page, pp->pr_pagesz, pp->pr_mtype);
+ if (pp->pr_roflags & PR_PHINPAGE) {
+ continue;
+ }
+ LIST_REMOVE(ph, ph_hashlist);
+ s = splhigh();
+ pool_put(&phpool, ph);
+ splx(s);
+ }
}
@@ -1325,19 +1359,18 @@ pool_drain(void *arg)
struct pool *pp;
int s;
+ pp = NULL;
s = splvm();
simple_lock(&pool_head_slock);
-
- if (drainpp == NULL && (drainpp = TAILQ_FIRST(&pool_head)) == NULL)
- goto out;
-
- pp = drainpp;
- drainpp = TAILQ_NEXT(pp, pr_poollist);
-
- pool_reclaim(pp);
-
- out:
+ if (drainpp == NULL) {
+ drainpp = TAILQ_FIRST(&pool_head);
+ }
+ if (drainpp) {
+ pp = drainpp;
+ drainpp = TAILQ_NEXT(pp, pr_poollist);
+ }
simple_unlock(&pool_head_slock);
+ pool_reclaim(pp);
splx(s);
}