summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorBob Beck <beck@cvs.openbsd.org>2007-08-07 04:32:46 +0000
committerBob Beck <beck@cvs.openbsd.org>2007-08-07 04:32:46 +0000
commit2d5b677a9e990c57ed21b7fe0b972373d7258107 (patch)
tree4ca9ac1a405795b3892be0739623f5c40bd3b5f4 /sys
parent27ce1dca8fd2447fb99333a0f6166ef7ed8bae7b (diff)
A few changes to deal with multi-user performance issues seen. this
brings us back roughly to 4.1 level performance, although this is still far from optimal as we have seen in a number of cases. This change 1) puts a lower bound on buffer cache queues to prevent starvation 2) fixes the code which looks for a buffer to recycle 3) reduces the number of vnodes back to 4.1 levels to avoid complex performance issues better addressed after 4.2 ok art@ deraadt@, tested by many
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/vfs_bio.c41
-rw-r--r--sys/kern/vfs_subr.c9
2 files changed, 33 insertions, 17 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 12896be67a2..d70e8d577c4 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_bio.c,v 1.98 2007/07/09 15:30:25 miod Exp $ */
+/* $OpenBSD: vfs_bio.c,v 1.99 2007/08/07 04:32:45 beck Exp $ */
/* $NetBSD: vfs_bio.c,v 1.44 1996/06/11 11:15:36 pk Exp $ */
/*-
@@ -84,6 +84,8 @@ u_long bufhash;
TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];
+int bqpages[BQUEUES]; /* pages allocated, per queue */
+int bqpagelow;
int needbuffer;
struct bio_ops bioops;
@@ -162,6 +164,7 @@ void
bremfree(struct buf *bp)
{
struct bqueues *dp = NULL;
+ int queue;
/*
* We only calculate the head of the freelist when removing
@@ -178,9 +181,12 @@ bremfree(struct buf *bp)
panic("bremfree: lost tail");
}
numfreepages -= btoc(bp->b_bufsize);
- if (!ISSET(bp->b_flags, B_DELWRI))
+ if (!ISSET(bp->b_flags, B_DELWRI)) {
+ int qs = bp->b_bufsize;
+ queue = size2cqueue(&qs);
numcleanpages -= btoc(bp->b_bufsize);
- else
+ bqpages[queue] -= btoc(bp->b_bufsize);
+ } else
numdirtypages -= btoc(bp->b_bufsize);
TAILQ_REMOVE(dp, bp, b_freelist);
}
@@ -188,7 +194,7 @@ bremfree(struct buf *bp)
void
buf_init(struct buf *bp, int size)
{
- int npages;
+ int npages, queue;
splassert(IPL_BIO);
@@ -198,10 +204,12 @@ buf_init(struct buf *bp, int size)
bp->b_freelist.tqe_next = NOLIST;
bp->b_synctime = time_uptime + 300;
bp->b_dev = NODEV;
+ queue = size2cqueue(&size);
LIST_INIT(&bp->b_dep);
numbufpages += npages;
numfreepages += npages;
numcleanpages += npages;
+ bqpages[queue] += npages;
if (maxcleanpages < numcleanpages)
maxcleanpages = numcleanpages;
}
@@ -339,6 +347,12 @@ bufinit(void)
buf_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
ptoa(bufpages), 0, FALSE, NULL);
+ /*
+ * XXX don't starve any one queue below 5% of the total number
+ * of buffer cache pages.
+ */
+ bqpagelow = bufpages / 20;
+
bufhashtbl = hashinit(bufpages / 4, M_CACHE, M_WAITOK, &bufhash);
hidirtypages = (bufpages / 4) * 3;
lodirtypages = bufpages / 2;
@@ -769,6 +783,7 @@ brelse(struct buf *bp)
qs = bp->b_bufsize;
queue = size2cqueue(&qs);
numcleanpages += btoc(bp->b_bufsize);
+ bqpages[queue] += btoc(bp->b_bufsize);
if (maxcleanpages < numcleanpages)
maxcleanpages = numcleanpages;
binsheadfree(bp, &bufqueues[queue]);
@@ -784,6 +799,7 @@ brelse(struct buf *bp)
if (!ISSET(bp->b_flags, B_DELWRI)) {
numcleanpages += btoc(bp->b_bufsize);
+ bqpages[queue] += btoc(bp->b_bufsize);
if (maxcleanpages < numcleanpages)
maxcleanpages = numcleanpages;
bufq = &bufqueues[queue];
@@ -960,11 +976,14 @@ getsome:
queue = size2cqueue(&qs);
bp = buf_get(qs); /* XXX use qs instead and no need in buf_get? */
if (bp == NULL) {
- /* no free ones, try to reuse a clean one.. */
- for (bp = TAILQ_FIRST(&bufqueues[queue]);
- bp != NULL && queue < BQUEUES; queue++) {
- /* XXX */
- }
+ /*
+ * No free ones, try to reuse a clean one of the same or
+ * larger size.
+ */
+ do {
+ bp = TAILQ_FIRST(&bufqueues[queue]);
+ queue++;
+ } while (bp == NULL && queue < BQUEUES);
}
if (bp == NULL) {
/* we couldn't reuse a free one, nothing of the right size */
@@ -975,7 +994,9 @@ getsome:
int freemax = 20;
for (q = 1; q < BQUEUES; q++) {
int i = freemax;
- while ((bp = TAILQ_FIRST(&bufqueues[q])) && i--) {
+ while (bqpages[q] > bqpagelow
+ && (bp = TAILQ_FIRST(&bufqueues[q]))
+ && i--) {
gotsome++;
bremfree(bp);
if (LIST_FIRST(&bp->b_dep) != NULL)
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index a8b6aba5047..f39b05bcc05 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_subr.c,v 1.154 2007/06/01 17:29:10 beck Exp $ */
+/* $OpenBSD: vfs_subr.c,v 1.155 2007/08/07 04:32:45 beck Exp $ */
/* $NetBSD: vfs_subr.c,v 1.53 1996/04/22 01:39:13 christos Exp $ */
/*
@@ -120,12 +120,7 @@ void
vntblinit(void)
{
/* buffer cache may need a vnode for each buffer */
- /*
- * XXX note this is different from desiredvnodes, which is
- * XXX the old static value computed from MAXUSERS which is
- * XXX used for sizing may other subsystems (namecache, softdeps, etc)
- */
- maxvnodes = bufpages;
+ maxvnodes = desiredvnodes;
pool_init(&vnode_pool, sizeof(struct vnode), 0, 0, 0, "vnodes",
&pool_allocator_nointr);
TAILQ_INIT(&vnode_hold_list);