diff options
author | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2001-10-11 08:07:13 +0000 |
---|---|---|
committer | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2001-10-11 08:07:13 +0000 |
commit | 3114560bb67cbcaa1578333a39b2f8db9c0430a1 (patch) | |
tree | 4e672ae226e801a50f6bd50e74217d6c57dfa574 /sys | |
parent | 4956de05c4137ac410e3524aa9d2cde93a5b41ef (diff) |
Count pages not buffers. This fixes deadlock condition which mainly
occurs on the fs with large block size. We can have situation where
numcleanbufs < locleanbufs and numdirtybufs < hidirtybufs. So, buffer
flushing daemon never wakeups and other processes asleep forever waiting
for a clean buffers. We count pages only for the dirty buffers which are
on freelist(BQ_DIRTY).
niklas@ found this.
Rename flasher to cleaner. Suggested by costa@.
Discussed with niklas@, costa@, millert@, art@.
Ok deraadt@.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/init_main.c | 12 | ||||
-rw-r--r-- | sys/kern/vfs_bio.c | 160 |
2 files changed, 86 insertions, 86 deletions
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index fb294afb8a4..6f671250c98 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init_main.c,v 1.78 2001/09/29 20:09:34 gluk Exp $ */ +/* $OpenBSD: init_main.c,v 1.79 2001/10/11 08:07:12 gluk Exp $ */ /* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */ /* @@ -133,7 +133,7 @@ int main __P((void *)); void check_console __P((struct proc *)); void start_init __P((void *)); void start_pagedaemon __P((void *)); -void start_flusher __P((void *)); +void start_cleaner __P((void *)); void start_update __P((void *)); void start_reaper __P((void *)); void start_crypto __P((void *)); @@ -414,9 +414,9 @@ main(framep) if (kthread_create(start_reaper, NULL, NULL, "reaper")) panic("fork reaper"); - /* Create process 4, the flusher daemon kernel thread. */ - if (kthread_create(start_flusher, NULL, NULL, "flusher")) - panic("fork flusher"); + /* Create process 4, the cleaner daemon kernel thread. */ + if (kthread_create(start_cleaner, NULL, NULL, "cleaner")) + panic("fork cleaner"); /* Create process 5, the update daemon kernel thread. */ if (kthread_create(start_update, NULL, NULL, "update")) @@ -620,7 +620,7 @@ start_update(arg) } void -start_flusher(arg) +start_cleaner(arg) void *arg; { buf_daemon(curproc); diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index efd38401530..60383440480 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_bio.c,v 1.43 2001/09/20 08:22:26 gluk Exp $ */ +/* $OpenBSD: vfs_bio.c,v 1.44 2001/10/11 08:07:12 gluk Exp $ */ /* $NetBSD: vfs_bio.c,v 1.44 1996/06/11 11:15:36 pk Exp $ */ /*- @@ -111,28 +111,29 @@ int getnewbuf __P((int slpflag, int slptimeo, struct buf **)); /* * We keep a few counters to monitor the utilization of the buffer cache * - * numdirtybufs - number of all dirty (B_DELWRI) buffers. - * lodirtybufs - low water mark for buffer flushing daemon. - * hidirtybufs - high water mark for buffer flushing daemon. - * numfreebufs - number of buffers on BQ_CLEAN and BQ_DIRTY. unused. - * numcleanbufs - number of clean (!B_DELWRI) buffers on BQ_CLEAN. - * Used to track the need to speedup the flusher and for the syncer reserve. - * numemptybufs - number of buffers on BQ_EMPTY. unused. - * mincleanbufs - the lowest number of clean buffers this far. + * numdirtypages - number of pages on BQ_DIRTY queue. + * lodirtypages - low water mark for buffer cleaning daemon. + * hidirtypages - high water mark for buffer cleaning daemon. + * numfreepages - number of pages on BQ_CLEAN and BQ_DIRTY queues. unused. + * numcleanpages - number of pages on BQ_CLEAN queue. + * Used to track the need to speedup the cleaner and + * as a reserve for special processes like syncer. + * mincleanpages - the lowest byte count on BQ_CLEAN. + * numemptybufs - number of buffers on BQ_EMPTY. unused. */ -int numdirtybufs; -int lodirtybufs; -int hidirtybufs; -int numfreebufs; -int numcleanbufs; +long numdirtypages; +long lodirtypages; +long hidirtypages; +long numfreepages; +long numcleanpages; +long locleanpages; int numemptybufs; -int locleanbufs; #ifdef DEBUG -int mincleanbufs; +long mincleanpages; #endif -struct proc *flusherproc; -int bd_req; /* Sleep point for flusher daemon. */ +struct proc *cleanerproc; +int bd_req; /* Sleep point for cleaner daemon. */ void bremfree(bp) @@ -157,13 +158,15 @@ bremfree(bp) if (bp->b_bufsize <= 0) { numemptybufs--; } else if (!ISSET(bp->b_flags, B_LOCKED)) { - numfreebufs--; + numfreepages -= btoc(bp->b_bufsize); if (!ISSET(bp->b_flags, B_DELWRI)) { - numcleanbufs--; + numcleanpages -= btoc(bp->b_bufsize); #ifdef DEBUG - if (mincleanbufs > numcleanbufs) - mincleanbufs = numcleanbufs; + if (mincleanpages > numcleanpages) + mincleanpages = numcleanpages; #endif + } else { + numdirtypages -= btoc(bp->b_bufsize); } } TAILQ_REMOVE(dp, bp, b_freelist); @@ -201,8 +204,8 @@ bufinit() bp->b_flags = B_INVAL; if (bp->b_bufsize) { dp = &bufqueues[BQ_CLEAN]; - numfreebufs++; - numcleanbufs++; + numfreepages += btoc(bp->b_bufsize); + numcleanpages += btoc(bp->b_bufsize); } else { dp = &bufqueues[BQ_EMPTY]; numemptybufs++; @@ -211,25 +214,26 @@ bufinit() binshash(bp, &invalhash); } - numdirtybufs = 0; - hidirtybufs = nbuf / 4 + 20; - lodirtybufs = hidirtybufs / 2; + hidirtypages = bufpages / 4; + lodirtypages = hidirtypages / 2; /* - * Reserve 5% of bufs for syncer's needs, + * Reserve 5% of bufpages for syncer's needs, * but not more than 25% and if possible - * not less then 16 bufs. locleanbufs + * not less then 2 * MAXBSIZE. locleanpages * value must be not too small, but probably - * there are no reason to set it more than 32. + * there are no reason to set it more than 1-2 MB. */ - locleanbufs = nbuf / 20; - if (locleanbufs < 16) - locleanbufs = 16; - if (locleanbufs > nbuf / 4) - locleanbufs = nbuf / 4; + locleanpages = bufpages / 20; + if (locleanpages < btoc(2 * MAXBSIZE)) + locleanpages = btoc(2 * MAXBSIZE); + if (locleanpages > bufpages / 4) + locleanpages = bufpages / 4; + if (locleanpages > btoc(2 * 1024 * 1024)) + locleanpages = btoc(2 * 1024 * 1024); #ifdef DEBUG - mincleanbufs = locleanbufs; + mincleanpages = locleanpages; #endif } @@ -395,7 +399,6 @@ bwrite(bp) * be properly notified that its I/O has completed. */ if (wasdelayed) { - --numdirtybufs; reassignbuf(bp); } else curproc->p_stats->p_ru.ru_oublock++; @@ -452,7 +455,6 @@ bdwrite(bp) SET(bp->b_flags, B_DELWRI); s = splbio(); reassignbuf(bp); - ++numdirtybufs; splx(s); curproc->p_stats->p_ru.ru_oublock++; /* XXX */ } @@ -492,11 +494,6 @@ buf_dirty(bp) if (ISSET(bp->b_flags, B_DELWRI) == 0) { SET(bp->b_flags, B_DELWRI); reassignbuf(bp); - ++numdirtybufs; -#ifdef DIAGNOSTIC - if (numdirtybufs > nbuf) - panic("buf_dirty: incorrect number of dirty bufs"); -#endif } } @@ -510,11 +507,6 @@ buf_undirty(bp) if (ISSET(bp->b_flags, B_DELWRI)) { CLR(bp->b_flags, B_DELWRI); reassignbuf(bp); - --numdirtybufs; -#ifdef DIAGNOSTIC - if (numdirtybufs < 0) - panic("buf_undirty: incorrect number of dirty bufs"); -#endif } } @@ -553,7 +545,6 @@ brelse(bp) buf_deallocate(bp); if (ISSET(bp->b_flags, B_DELWRI)) { - --numdirtybufs; CLR(bp->b_flags, B_DELWRI); } @@ -568,8 +559,8 @@ brelse(bp) } else { /* invalid data */ bufq = &bufqueues[BQ_CLEAN]; - numfreebufs++; - numcleanbufs++; + numfreepages += btoc(bp->b_bufsize); + numcleanpages += btoc(bp->b_bufsize); } binsheadfree(bp, bufq); } else { @@ -581,12 +572,14 @@ brelse(bp) /* locked in core */ bufq = &bufqueues[BQ_LOCKED]; else { - numfreebufs++; + numfreepages += btoc(bp->b_bufsize); if (!ISSET(bp->b_flags, B_DELWRI)) { - numcleanbufs++; + numcleanpages += btoc(bp->b_bufsize); bufq = &bufqueues[BQ_CLEAN]; - } else + } else { + numdirtypages += btoc(bp->b_bufsize); bufq = &bufqueues[BQ_DIRTY]; + } } if (ISSET(bp->b_flags, B_AGE)) binsheadfree(bp, bufq); @@ -600,14 +593,14 @@ brelse(bp) /* Allow disk interrupts. */ splx(s); - /* Wake up syncer and flusher processes waiting for buffers */ + /* Wake up syncer and cleaner processes waiting for buffers */ if (nobuffers) { wakeup(&nobuffers); nobuffers = 0; } /* Wake up any processes waiting for any buffer to become free. */ - if (needbuffer && (numcleanbufs > locleanbufs)) { + if (needbuffer && (numcleanpages > locleanpages)) { needbuffer--; wakeup_one(&needbuffer); } @@ -850,13 +843,13 @@ getnewbuf(slpflag, slptimeo, bpp) start: s = splbio(); /* - * Wake up flusher if we're getting low on buffers. + * Wake up cleaner if we're getting low on buffers. */ - if (numdirtybufs >= hidirtybufs) + if (numdirtypages >= hidirtypages) wakeup(&bd_req); - if ((numcleanbufs <= locleanbufs) - && (curproc != syncerproc || curproc != flusherproc)) { + if ((numcleanpages <= locleanpages) + && (curproc != syncerproc || curproc != cleanerproc)) { needbuffer++; error = tsleep(&needbuffer, slpflag|(PRIBIO+1), "getnewbuf", slptimeo); @@ -927,7 +920,7 @@ start: } /* - * Buffer flushing daemon. + * Buffer cleaning daemon. */ void buf_daemon(struct proc *p) @@ -936,11 +929,11 @@ buf_daemon(struct proc *p) struct buf *bp; struct timeval starttime, timediff; - flusherproc = curproc; + cleanerproc = curproc; for (;;) { - if (numdirtybufs < hidirtybufs) { - tsleep(&bd_req, PRIBIO - 7, "flusher", 0); + if (numdirtypages < hidirtypages) { + tsleep(&bd_req, PRIBIO - 7, "cleaner", 0); } starttime = time; @@ -964,7 +957,8 @@ buf_daemon(struct proc *p) buf_countdeps(bp, 0, 1)) { SET(bp->b_flags, B_DEFERRED); s = splbio(); - ++numfreebufs; + numfreepages += btoc(bp->b_bufsize); + numdirtypages += btoc(bp->b_bufsize); binstailfree(bp, &bufqueues[BQ_DIRTY]); CLR(bp->b_flags, B_BUSY); continue; @@ -972,7 +966,7 @@ buf_daemon(struct proc *p) bawrite(bp); - if (numdirtybufs < lodirtybufs) + if (numdirtypages < lodirtypages) break; /* Never allow processing to run for more than 1 sec */ timersub(&time, &starttime, &timediff); @@ -1070,19 +1064,24 @@ vfs_bufstats() register struct bqueues *dp; int counts[MAXBSIZE/PAGE_SIZE+1]; int totals[BQUEUES]; + long ptotals[BQUEUES]; + long pages; static char *bname[BQUEUES] = { "LOCKED", "CLEAN", "DIRTY", "EMPTY" }; s = splbio(); for (dp = bufqueues, i = 0; dp < &bufqueues[BQUEUES]; dp++, i++) { count = 0; + pages = 0; for (j = 0; j <= MAXBSIZE/PAGE_SIZE; j++) counts[j] = 0; for (bp = dp->tqh_first; bp; bp = bp->b_freelist.tqe_next) { counts[bp->b_bufsize/PAGE_SIZE]++; count++; + pages += btoc(bp->b_bufsize); } totals[i] = count; - printf("%s: total-%d", bname[i], count); + ptotals[i] = pages; + printf("%s: total-%d(%d pages)", bname[i], count, pages); for (j = 0; j <= MAXBSIZE/PAGE_SIZE; j++) if (counts[j] != 0) printf(", %d-%d", j * PAGE_SIZE, counts[j]); @@ -1091,21 +1090,22 @@ vfs_bufstats() if (totals[BQ_EMPTY] != numemptybufs) printf("numemptybufs counter wrong: %d != %d\n", numemptybufs, totals[BQ_EMPTY]); - if ((totals[BQ_CLEAN] + totals[BQ_DIRTY]) != numfreebufs) - printf("numfreebufs counter wrong: %d != %d\n", - numfreebufs, totals[BQ_CLEAN] + totals[BQ_DIRTY]); - if (totals[BQ_CLEAN] != numcleanbufs) - printf("numcleanbufs counter wrong: %d != %d\n", - numcleanbufs, totals[BQ_CLEAN]); + if ((ptotals[BQ_CLEAN] + ptotals[BQ_DIRTY]) != numfreepages) + printf("numfreepages counter wrong: %ld != %ld\n", + numfreepages, ptotals[BQ_CLEAN] + ptotals[BQ_DIRTY]); + if (ptotals[BQ_CLEAN] != numcleanpages) + printf("numcleanpages counter wrong: %ld != %ld\n", + numcleanpages, ptotals[BQ_CLEAN]); else - printf("numcleanbufs: %d\n", numcleanbufs); - if (numdirtybufs < totals[BQ_DIRTY]) - printf("numdirtybufs counter wrong: %d < %d\n", - numdirtybufs, totals[BQ_DIRTY]); + printf("numcleanpages: %ld\n", numcleanpages); + if (numdirtypages != ptotals[BQ_DIRTY]) + printf("numdirtypages counter wrong: %ld != %ld\n", + numdirtypages, ptotals[BQ_DIRTY]); else - printf("numdirtybufs: %d\n", numdirtybufs); - printf("syncer eating up to %d bufs from %d reserved\n", - locleanbufs - mincleanbufs, locleanbufs); + printf("numdirtypages: %ld\n", numdirtypages); + + printf("syncer eating up to %ld pages from %ld reserved\n", + locleanpages - mincleanpages, locleanpages); splx(s); } #endif /* DEBUG */ |