aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Dyson <dyson@FreeBSD.org>1997-06-15 17:56:53 +0000
committerJohn Dyson <dyson@FreeBSD.org>1997-06-15 17:56:53 +0000
commit6b195d32a1cd26c13df527a3c3d02598119c2f55 (patch)
tree0304209c493d06ccf148bd866e0f1c5261434170
parentc4bbabfe4f75ae51d86c6eb7098ec17df17ce69b (diff)
downloadsrc-6b195d32a1cd26c13df527a3c3d02598119c2f55.tar.gz
src-6b195d32a1cd26c13df527a3c3d02598119c2f55.zip
Fix a problem with the VN device. Specifically, the VN device can
cause a problem of spiraling death due to buffer resource limitations. The vfs_bio code in general had little ability to handle buffer resource management, and now it does. Also, there are a lot more knobs for tuning the vfs_bio code now. The knobs came free because of the need that there always be some immediately available buffers (non-delayed or locked) for use. Note that the buffer cache code is much less likely to get bogged down with lots of delayed writes, even more so than before.
Notes
Notes: svn path=/head/; revision=26664
-rw-r--r--sys/gnu/ext2fs/ext2_linux_ialloc.c6
-rw-r--r--sys/gnu/fs/ext2fs/ext2_linux_ialloc.c6
-rw-r--r--sys/kern/vfs_bio.c272
-rw-r--r--sys/kern/vfs_cluster.c3
-rw-r--r--sys/sys/bio.h4
-rw-r--r--sys/sys/buf.h4
-rw-r--r--sys/ufs/lfs/lfs_bio.c3
-rw-r--r--sys/ufs/lfs/lfs_segment.c12
8 files changed, 267 insertions, 43 deletions
diff --git a/sys/gnu/ext2fs/ext2_linux_ialloc.c b/sys/gnu/ext2fs/ext2_linux_ialloc.c
index c20770bc733b..c93c20e6cd98 100644
--- a/sys/gnu/ext2fs/ext2_linux_ialloc.c
+++ b/sys/gnu/ext2fs/ext2_linux_ialloc.c
@@ -53,6 +53,7 @@
*/
void mark_buffer_dirty(struct buf *bh)
{
+ numdirtybuffers++;
bh->b_flags |= B_DELWRI;
bh->b_flags &= ~(B_READ | B_ERROR);
}
@@ -62,6 +63,11 @@ void mark_buffer_dirty(struct buf *bh)
*/
int ll_w_block(struct buf * bp, int waitfor)
{
+ if (bp->b_flags & B_DELWRI) {
+ --numdirtybuffers;
+ if (needsbuffer)
+ vfs_bio_need_satisfy();
+ }
bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
bp->b_flags |= B_WRITEINPROG;
bp->b_vp->v_numoutput++;
diff --git a/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c b/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c
index c20770bc733b..c93c20e6cd98 100644
--- a/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c
+++ b/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c
@@ -53,6 +53,7 @@
*/
void mark_buffer_dirty(struct buf *bh)
{
+ numdirtybuffers++;
bh->b_flags |= B_DELWRI;
bh->b_flags &= ~(B_READ | B_ERROR);
}
@@ -62,6 +63,11 @@ void mark_buffer_dirty(struct buf *bh)
*/
int ll_w_block(struct buf * bp, int waitfor)
{
+ if (bp->b_flags & B_DELWRI) {
+ --numdirtybuffers;
+ if (needsbuffer)
+ vfs_bio_need_satisfy();
+ }
bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
bp->b_flags |= B_WRITEINPROG;
bp->b_vp->v_numoutput++;
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 2f2a121a431c..f2477e56c771 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -18,7 +18,7 @@
* 5. Modifications may be freely made to this file if the above conditions
* are met.
*
- * $Id: vfs_bio.c,v 1.119 1997/06/06 09:04:28 dfr Exp $
+ * $Id: vfs_bio.c,v 1.120 1997/06/13 08:30:40 bde Exp $
*/
/*
@@ -85,6 +85,7 @@ static void vfs_page_set_valid(struct buf *bp, vm_ooffset_t off,
static void vfs_clean_pages(struct buf * bp);
static void vfs_setdirty(struct buf *bp);
static void vfs_vmio_release(struct buf *bp);
+static void flushdirtybuffers(int slpflag, int slptimeo);
int needsbuffer;
@@ -111,13 +112,44 @@ static vm_offset_t bogus_offset;
static int bufspace, maxbufspace, vmiospace, maxvmiobufspace,
bufmallocspace, maxbufmallocspace;
+int numdirtybuffers, lodirtybuffers, hidirtybuffers;
+static int numfreebuffers, lofreebuffers, hifreebuffers;
+
+SYSCTL_INT(_vfs, OID_AUTO, numdirtybuffers, CTLFLAG_RD,
+ &numdirtybuffers, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, lodirtybuffers, CTLFLAG_RW,
+ &lodirtybuffers, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, hidirtybuffers, CTLFLAG_RW,
+ &hidirtybuffers, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, numfreebuffers, CTLFLAG_RD,
+ &numfreebuffers, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, lofreebuffers, CTLFLAG_RW,
+ &lofreebuffers, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, hifreebuffers, CTLFLAG_RW,
+ &hifreebuffers, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, maxbufspace, CTLFLAG_RW,
+ &maxbufspace, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, bufspace, CTLFLAG_RD,
+ &bufspace, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, maxvmiobufspace, CTLFLAG_RW,
+ &maxvmiobufspace, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, vmiospace, CTLFLAG_RD,
+ &vmiospace, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, maxmallocbufspace, CTLFLAG_RW,
+ &maxbufmallocspace, 0, "");
+SYSCTL_INT(_vfs, OID_AUTO, bufmallocspace, CTLFLAG_RD,
+ &bufmallocspace, 0, "");
static struct bufhashhdr bufhashtbl[BUFHSZ], invalhash;
static struct bqueues bufqueues[BUFFER_QUEUES];
extern int vm_swap_size;
-#define BUF_MAXUSE 16
+#define BUF_MAXUSE 24
+
+#define VFS_BIO_NEED_ANY 1
+#define VFS_BIO_NEED_LOWLIMIT 2
+#define VFS_BIO_NEED_FREE 4
/*
* Initialize buffer headers and related structures.
@@ -172,6 +204,17 @@ bufinit()
*/
maxbufmallocspace = maxbufspace / 20;
+/*
+ * Remove the probability of deadlock conditions by limiting the
+ * number of dirty buffers.
+ */
+ hidirtybuffers = nbuf / 6 + 20;
+ lodirtybuffers = nbuf / 12 + 10;
+ numdirtybuffers = 0;
+ lofreebuffers = nbuf / 18 + 5;
+ hifreebuffers = 2 * lofreebuffers;
+ numfreebuffers = nbuf;
+
bogus_offset = kmem_alloc_pageable(kernel_map, PAGE_SIZE);
bogus_page = vm_page_alloc(kernel_object,
((bogus_offset - VM_MIN_KERNEL_ADDRESS) >> PAGE_SHIFT),
@@ -210,8 +253,13 @@ bremfree(struct buf * bp)
TAILQ_REMOVE(&bufqueues[bp->b_qindex], bp, b_freelist);
bp->b_qindex = QUEUE_NONE;
} else {
+#if !defined(MAX_PERF)
panic("bremfree: removing a buffer when not on a queue");
+#endif
}
+ if ((bp->b_flags & B_INVAL) ||
+ (bp->b_flags & (B_DELWRI|B_LOCKED)) == 0)
+ --numfreebuffers;
splx(s);
}
@@ -316,13 +364,16 @@ bwrite(struct buf * bp)
brelse(bp);
return (0);
}
+#if !defined(MAX_PERF)
if (!(bp->b_flags & B_BUSY))
panic("bwrite: buffer is not busy???");
+#endif
bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
bp->b_flags |= B_WRITEINPROG;
- if ((oldflags & (B_ASYNC|B_DELWRI)) == (B_ASYNC|B_DELWRI)) {
+ if ((oldflags & B_DELWRI) == B_DELWRI) {
+ --numdirtybuffers;
reassignbuf(bp, bp->b_vp);
}
@@ -385,6 +436,22 @@ vn_bwrite(ap)
return (bwrite(ap->a_bp));
}
+void
+vfs_bio_need_satisfy(void) {
+ ++numfreebuffers;
+ if (!needsbuffer)
+ return;
+ if (numdirtybuffers < lodirtybuffers) {
+ needsbuffer &= ~(VFS_BIO_NEED_ANY | VFS_BIO_NEED_LOWLIMIT);
+ } else {
+ needsbuffer &= ~VFS_BIO_NEED_ANY;
+ }
+ if (numfreebuffers >= hifreebuffers) {
+ needsbuffer &= ~VFS_BIO_NEED_FREE;
+ }
+ wakeup(&needsbuffer);
+}
+
/*
* Delayed write. (Buffer is marked dirty).
*/
@@ -392,9 +459,12 @@ void
bdwrite(struct buf * bp)
{
+#if !defined(MAX_PERF)
if ((bp->b_flags & B_BUSY) == 0) {
panic("bdwrite: buffer is not busy");
}
+#endif
+
if (bp->b_flags & B_INVAL) {
brelse(bp);
return;
@@ -407,6 +477,7 @@ bdwrite(struct buf * bp)
if ((bp->b_flags & B_DELWRI) == 0) {
bp->b_flags |= B_DONE | B_DELWRI;
reassignbuf(bp, bp->b_vp);
+ ++numdirtybuffers;
}
/*
@@ -436,6 +507,10 @@ bdwrite(struct buf * bp)
*/
vfs_clean_pages(bp);
bqrelse(bp);
+
+ if (numdirtybuffers >= hidirtybuffers)
+ flushdirtybuffers(0, 0);
+
return;
}
@@ -493,6 +568,8 @@ brelse(struct buf * bp)
if ((bp->b_flags & (B_NOCACHE | B_INVAL | B_ERROR)) ||
(bp->b_bufsize <= 0)) {
bp->b_flags |= B_INVAL;
+ if (bp->b_flags & B_DELWRI)
+ --numdirtybuffers;
bp->b_flags &= ~(B_DELWRI | B_CACHE);
if (((bp->b_flags & B_VMIO) == 0) && bp->b_vp) {
if (bp->b_bufsize)
@@ -533,8 +610,11 @@ brelse(struct buf * bp)
int iototal = bp->b_bufsize;
vp = bp->b_vp;
+
+#if !defined(MAX_PERF)
if (!vp)
panic("brelse: missing vp");
+#endif
if (bp->b_npages) {
vm_pindex_t poff;
@@ -548,9 +628,11 @@ brelse(struct buf * bp)
m = bp->b_pages[i];
if (m == bogus_page) {
m = vm_page_lookup(obj, poff + i);
+#if !defined(MAX_PERF)
if (!m) {
panic("brelse: page missing\n");
}
+#endif
bp->b_pages[i] = m;
pmap_qenter(trunc_page(bp->b_data),
bp->b_pages, bp->b_npages);
@@ -590,12 +672,15 @@ brelse(struct buf * bp)
if (bp->b_flags & (B_INVAL | B_RELBUF))
vfs_vmio_release(bp);
}
+#if !defined(MAX_PERF)
if (bp->b_qindex != QUEUE_NONE)
panic("brelse: free buffer onto another queue???");
+#endif
/* enqueue */
/* buffers with no memory */
if (bp->b_bufsize == 0) {
+ bp->b_flags |= B_INVAL;
bp->b_qindex = QUEUE_EMPTY;
TAILQ_INSERT_HEAD(&bufqueues[QUEUE_EMPTY], bp, b_freelist);
LIST_REMOVE(bp, b_hash);
@@ -605,41 +690,39 @@ brelse(struct buf * bp)
* Get rid of the kva allocation *now*
*/
bfreekva(bp);
- if (needsbuffer) {
- wakeup(&needsbuffer);
- needsbuffer=0;
- }
- /* buffers with junk contents */
+
+ /* buffers with junk contents */
} else if (bp->b_flags & (B_ERROR | B_INVAL | B_NOCACHE | B_RELBUF)) {
+ bp->b_flags |= B_INVAL;
bp->b_qindex = QUEUE_AGE;
TAILQ_INSERT_HEAD(&bufqueues[QUEUE_AGE], bp, b_freelist);
LIST_REMOVE(bp, b_hash);
LIST_INSERT_HEAD(&invalhash, bp, b_hash);
bp->b_dev = NODEV;
- if (needsbuffer) {
- wakeup(&needsbuffer);
- needsbuffer=0;
- }
- /* buffers that are locked */
+
+ /* buffers that are locked */
} else if (bp->b_flags & B_LOCKED) {
bp->b_qindex = QUEUE_LOCKED;
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_LOCKED], bp, b_freelist);
- /* buffers with stale but valid contents */
+
+ /* buffers with stale but valid contents */
} else if (bp->b_flags & B_AGE) {
bp->b_qindex = QUEUE_AGE;
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_AGE], bp, b_freelist);
- if (needsbuffer) {
- wakeup(&needsbuffer);
- needsbuffer=0;
- }
- /* buffers with valid and quite potentially reuseable contents */
+
+ /* buffers with valid and quite potentially reuseable contents */
} else {
bp->b_qindex = QUEUE_LRU;
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_LRU], bp, b_freelist);
- if (needsbuffer) {
- wakeup(&needsbuffer);
- needsbuffer=0;
+ }
+
+ if ((bp->b_flags & B_INVAL) ||
+ (bp->b_flags & (B_LOCKED|B_DELWRI)) == 0) {
+ if (bp->b_flags & B_DELWRI) {
+ --numdirtybuffers;
+ bp->b_flags &= ~B_DELWRI;
}
+ vfs_bio_need_satisfy();
}
/* unlock */
@@ -658,15 +741,16 @@ bqrelse(struct buf * bp)
s = splbio();
-
/* anyone need this block? */
if (bp->b_flags & B_WANTED) {
bp->b_flags &= ~(B_WANTED | B_AGE);
wakeup(bp);
}
+#if !defined(MAX_PERF)
if (bp->b_qindex != QUEUE_NONE)
panic("bqrelse: free buffer onto another queue???");
+#endif
if (bp->b_flags & B_LOCKED) {
bp->b_flags &= ~B_ERROR;
@@ -676,10 +760,10 @@ bqrelse(struct buf * bp)
} else {
bp->b_qindex = QUEUE_LRU;
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_LRU], bp, b_freelist);
- if (needsbuffer) {
- wakeup(&needsbuffer);
- needsbuffer=0;
- }
+ }
+
+ if ((bp->b_flags & (B_LOCKED|B_DELWRI)) == 0) {
+ vfs_bio_need_satisfy();
}
/* unlock */
@@ -854,11 +938,12 @@ vfs_bio_awrite(struct buf * bp)
* Find a buffer header which is available for use.
*/
static struct buf *
-getnewbuf(int slpflag, int slptimeo, int size, int maxsize)
+getnewbuf(struct vnode *vp, int slpflag, int slptimeo, int size, int maxsize)
{
struct buf *bp;
int nbyteswritten = 0;
vm_offset_t addr;
+ static int writerecursion = 0;
start:
if (bufspace >= maxbufspace)
@@ -866,9 +951,11 @@ start:
/* can we constitute a new buffer? */
if ((bp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTY]))) {
+#if !defined(MAX_PERF)
if (bp->b_qindex != QUEUE_EMPTY)
panic("getnewbuf: inconsistent EMPTY queue, qindex=%d",
bp->b_qindex);
+#endif
bp->b_flags |= B_BUSY;
bremfree(bp);
goto fillbuf;
@@ -880,21 +967,25 @@ trytofreespace:
* VM/Buffer cache even if a buffer is freed.
*/
if ((bp = TAILQ_FIRST(&bufqueues[QUEUE_AGE]))) {
+#if !defined(MAX_PERF)
if (bp->b_qindex != QUEUE_AGE)
panic("getnewbuf: inconsistent AGE queue, qindex=%d",
bp->b_qindex);
+#endif
} else if ((bp = TAILQ_FIRST(&bufqueues[QUEUE_LRU]))) {
+#if !defined(MAX_PERF)
if (bp->b_qindex != QUEUE_LRU)
panic("getnewbuf: inconsistent LRU queue, qindex=%d",
bp->b_qindex);
+#endif
}
if (!bp) {
/* wait for a free buffer of any kind */
- needsbuffer = 1;
+ needsbuffer |= VFS_BIO_NEED_ANY;
do
tsleep(&needsbuffer, (PRIBIO + 1) | slpflag, "newbuf",
slptimeo);
- while (needsbuffer);
+ while (needsbuffer & VFS_BIO_NEED_ANY);
return (0);
}
@@ -922,13 +1013,36 @@ trytofreespace:
}
}
+
/* if we are a delayed write, convert to an async write */
if ((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI) {
- nbyteswritten += vfs_bio_awrite(bp);
- if (!slpflag && !slptimeo) {
- return (0);
+
+ if (writerecursion > 0) {
+ bp = TAILQ_FIRST(&bufqueues[QUEUE_AGE]);
+ while (bp) {
+ if ((bp->b_flags & B_DELWRI) == 0)
+ break;
+ bp = TAILQ_NEXT(bp, b_freelist);
+ }
+ if (bp == NULL) {
+ bp = TAILQ_FIRST(&bufqueues[QUEUE_LRU]);
+ while (bp) {
+ if ((bp->b_flags & B_DELWRI) == 0)
+ break;
+ bp = TAILQ_NEXT(bp, b_freelist);
+ }
+ }
+ if (bp == NULL)
+ panic("getnewbuf: cannot get buffer, infinite recursion failure");
+ } else {
+ ++writerecursion;
+ nbyteswritten += vfs_bio_awrite(bp);
+ --writerecursion;
+ if (!slpflag && !slptimeo) {
+ return (0);
+ }
+ goto start;
}
- goto start;
}
if (bp->b_flags & B_WANTED) {
@@ -1021,6 +1135,64 @@ fillbuf:
return (bp);
}
+static void
+waitfreebuffers(int slpflag, int slptimeo) {
+ while (numfreebuffers < hifreebuffers) {
+ flushdirtybuffers(slpflag, slptimeo);
+ if (numfreebuffers < hifreebuffers)
+ break;
+ needsbuffer |= VFS_BIO_NEED_FREE;
+ if (tsleep(&needsbuffer, PRIBIO|slpflag, "biofre", slptimeo))
+ break;
+ }
+}
+
+static void
+flushdirtybuffers(int slpflag, int slptimeo) {
+ int s;
+ static pid_t flushing = 0;
+
+ s = splbio();
+
+ if (flushing) {
+ if (flushing == curproc->p_pid) {
+ splx(s);
+ return;
+ }
+ while (flushing) {
+ if (tsleep(&flushing, PRIBIO|slpflag, "biofls", slptimeo)) {
+ splx(s);
+ return;
+ }
+ }
+ }
+ flushing = curproc->p_pid;
+
+ while (numdirtybuffers > lodirtybuffers) {
+ struct buf *bp;
+ needsbuffer |= VFS_BIO_NEED_LOWLIMIT;
+ bp = TAILQ_FIRST(&bufqueues[QUEUE_AGE]);
+ if (bp == NULL)
+ bp = TAILQ_FIRST(&bufqueues[QUEUE_LRU]);
+
+ while (bp && ((bp->b_flags & B_DELWRI) == 0)) {
+ bp = TAILQ_NEXT(bp, b_freelist);
+ }
+
+ if (bp) {
+ splx(s);
+ vfs_bio_awrite(bp);
+ s = splbio();
+ continue;
+ }
+ break;
+ }
+
+ flushing = 0;
+ wakeup(&flushing);
+ splx(s);
+}
+
/*
* Check to see if a block is currently memory resident.
*/
@@ -1141,6 +1313,7 @@ getblk(struct vnode * vp, daddr_t blkno, int size, int slpflag, int slptimeo)
int s;
struct bufhashhdr *bh;
int maxsize;
+ static pid_t flushing = 0;
if (vp->v_mount) {
maxsize = vp->v_mount->mnt_stat.f_iosize;
@@ -1153,11 +1326,17 @@ getblk(struct vnode * vp, daddr_t blkno, int size, int slpflag, int slptimeo)
maxsize = size;
}
+#if !defined(MAX_PERF)
if (size > MAXBSIZE)
panic("getblk: size(%d) > MAXBSIZE(%d)\n", size, MAXBSIZE);
+#endif
s = splbio();
loop:
+ if (numfreebuffers < lofreebuffers) {
+ waitfreebuffers(slpflag, slptimeo);
+ }
+
if ((bp = gbincore(vp, blkno))) {
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
@@ -1172,7 +1351,7 @@ loop:
}
bp->b_flags |= B_BUSY | B_CACHE;
bremfree(bp);
-
+
/*
* check for size inconsistancies (note that they shouldn't happen
* but do when filesystems don't handle the size changes correctly.)
@@ -1197,7 +1376,7 @@ loop:
} else {
vm_object_t obj;
- if ((bp = getnewbuf(slpflag, slptimeo, size, maxsize)) == 0) {
+ if ((bp = getnewbuf(vp, slpflag, slptimeo, size, maxsize)) == 0) {
if (slpflag || slptimeo) {
splx(s);
return NULL;
@@ -1260,7 +1439,7 @@ geteblk(int size)
int s;
s = splbio();
- while ((bp = getnewbuf(0, 0, size, MAXBSIZE)) == 0);
+ while ((bp = getnewbuf(0, 0, 0, size, MAXBSIZE)) == 0);
splx(s);
allocbuf(bp, size);
bp->b_flags |= B_INVAL;
@@ -1287,11 +1466,13 @@ allocbuf(struct buf * bp, int size)
int newbsize, mbsize;
int i;
+#if !defined(MAX_PERF)
if (!(bp->b_flags & B_BUSY))
panic("allocbuf: buffer not busy");
if (bp->b_kvasize < size)
panic("allocbuf: buffer too small");
+#endif
if ((bp->b_flags & B_VMIO) == 0) {
caddr_t origbuf;
@@ -1519,7 +1700,7 @@ allocbuf(struct buf * bp, int size)
}
}
if (bp->b_flags & B_VMIO)
- vmiospace += bp->b_bufsize;
+ vmiospace += (newbsize - bp->b_bufsize);
bufspace += (newbsize - bp->b_bufsize);
bp->b_bufsize = newbsize;
bp->b_bcount = size;
@@ -1560,12 +1741,17 @@ biodone(register struct buf * bp)
int s;
s = splbio();
+
+#if !defined(MAX_PERF)
if (!(bp->b_flags & B_BUSY))
panic("biodone: buffer not busy");
+#endif
if (bp->b_flags & B_DONE) {
splx(s);
+#if !defined(MAX_PERF)
printf("biodone: buffer already done\n");
+#endif
return;
}
bp->b_flags |= B_DONE;
@@ -1598,9 +1784,11 @@ biodone(register struct buf * bp)
else
foff = (vm_ooffset_t) vp->v_mount->mnt_stat.f_iosize * bp->b_lblkno;
obj = vp->v_object;
+#if !defined(MAX_PERF)
if (!obj) {
panic("biodone: no object");
}
+#endif
#if defined(VFS_BIO_DEBUG)
if (obj->paging_in_progress < bp->b_npages) {
printf("biodone: paging in progress(%d) < bp->b_npages(%d)\n",
@@ -1647,12 +1835,15 @@ biodone(register struct buf * bp)
* have not set the page busy flag correctly!!!
*/
if (m->busy == 0) {
+#if !defined(MAX_PERF)
printf("biodone: page busy < 0, "
"pindex: %d, foff: 0x(%x,%x), "
"resid: %d, index: %d\n",
(int) m->pindex, (int)(foff >> 32),
(int) foff & 0xffffffff, resid, i);
+#endif
if (vp->v_type != VBLK)
+#if !defined(MAX_PERF)
printf(" iosize: %ld, lblkno: %d, flags: 0x%lx, npages: %d\n",
bp->b_vp->v_mount->mnt_stat.f_iosize,
(int) bp->b_lblkno,
@@ -1663,6 +1854,7 @@ biodone(register struct buf * bp)
bp->b_flags, bp->b_npages);
printf(" valid: 0x%x, dirty: 0x%x, wired: %d\n",
m->valid, m->dirty, m->wire_count);
+#endif
panic("biodone: page busy < 0\n");
}
--m->busy;
@@ -1763,9 +1955,11 @@ vfs_unbusy_pages(struct buf * bp)
if (m == bogus_page) {
m = vm_page_lookup(obj, OFF_TO_IDX(foff) + i);
+#if !defined(MAX_PERF)
if (!m) {
panic("vfs_unbusy_pages: page missing\n");
}
+#endif
bp->b_pages[i] = m;
pmap_qenter(trunc_page(bp->b_data), bp->b_pages, bp->b_npages);
}
@@ -2015,10 +2209,12 @@ vm_hold_free_pages(struct buf * bp, vm_offset_t from, vm_offset_t to)
for (pg = from; pg < to; pg += PAGE_SIZE, index++) {
p = bp->b_pages[index];
if (p && (index < bp->b_npages)) {
+#if !defined(MAX_PERF)
if (p->busy) {
printf("vm_hold_free_pages: blkno: %d, lblkno: %d\n",
bp->b_blkno, bp->b_lblkno);
}
+#endif
bp->b_pages[index] = NULL;
pmap_kremove(pg);
vm_page_unwire(p);
diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c
index 740cc2cf0c22..5f926b9d930f 100644
--- a/sys/kern/vfs_cluster.c
+++ b/sys/kern/vfs_cluster.c
@@ -33,7 +33,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_cluster.c 8.7 (Berkeley) 2/13/94
- * $Id: vfs_cluster.c,v 1.45 1997/04/18 14:12:17 dfr Exp $
+ * $Id: vfs_cluster.c,v 1.46 1997/04/25 11:14:00 dfr Exp $
*/
#include <sys/param.h>
@@ -725,6 +725,7 @@ cluster_wbuild(vp, size, start_lbn, len)
bp->b_bcount += size;
bp->b_bufsize += size;
+ --numdirtybuffers;
tbp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
tbp->b_flags |= B_ASYNC;
s = splbio();
diff --git a/sys/sys/bio.h b/sys/sys/bio.h
index e52c809918b1..8cb3c8cccdfb 100644
--- a/sys/sys/bio.h
+++ b/sys/sys/bio.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)buf.h 8.9 (Berkeley) 3/30/95
- * $Id$
+ * $Id: buf.h,v 1.38 1997/02/22 09:44:49 peter Exp $
*/
#ifndef _SYS_BUF_H_
@@ -194,6 +194,7 @@ extern char *buffers; /* The buffer contents. */
extern int bufpages; /* Number of memory pages in the buffer pool. */
extern struct buf *swbuf; /* Swap I/O buffer headers. */
extern int nswbuf; /* Number of swap I/O buffer headers. */
+extern int needsbuffer, numdirtybuffers;
extern TAILQ_HEAD(swqueue, buf) bswlist;
void bufinit __P((void));
@@ -244,6 +245,7 @@ void vm_bounce_alloc __P((struct buf *));
void vm_bounce_free __P((struct buf *));
vm_offset_t vm_bounce_kva_alloc __P((int));
void vm_bounce_kva_alloc_free __P((vm_offset_t, int));
+void vfs_bio_need_satisfy __P((void));
#endif /* KERNEL */
#endif /* !_SYS_BUF_H_ */
diff --git a/sys/sys/buf.h b/sys/sys/buf.h
index e52c809918b1..8cb3c8cccdfb 100644
--- a/sys/sys/buf.h
+++ b/sys/sys/buf.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)buf.h 8.9 (Berkeley) 3/30/95
- * $Id$
+ * $Id: buf.h,v 1.38 1997/02/22 09:44:49 peter Exp $
*/
#ifndef _SYS_BUF_H_
@@ -194,6 +194,7 @@ extern char *buffers; /* The buffer contents. */
extern int bufpages; /* Number of memory pages in the buffer pool. */
extern struct buf *swbuf; /* Swap I/O buffer headers. */
extern int nswbuf; /* Number of swap I/O buffer headers. */
+extern int needsbuffer, numdirtybuffers;
extern TAILQ_HEAD(swqueue, buf) bswlist;
void bufinit __P((void));
@@ -244,6 +245,7 @@ void vm_bounce_alloc __P((struct buf *));
void vm_bounce_free __P((struct buf *));
vm_offset_t vm_bounce_kva_alloc __P((int));
void vm_bounce_kva_alloc_free __P((vm_offset_t, int));
+void vfs_bio_need_satisfy __P((void));
#endif /* KERNEL */
#endif /* !_SYS_BUF_H_ */
diff --git a/sys/ufs/lfs/lfs_bio.c b/sys/ufs/lfs/lfs_bio.c
index 3fc1050114eb..57663efd50a1 100644
--- a/sys/ufs/lfs/lfs_bio.c
+++ b/sys/ufs/lfs/lfs_bio.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)lfs_bio.c 8.10 (Berkeley) 6/10/95
- * $Id: lfs_bio.c,v 1.11 1997/02/22 09:47:17 peter Exp $
+ * $Id: lfs_bio.c,v 1.12 1997/03/23 00:45:13 bde Exp $
*/
#include <sys/param.h>
@@ -117,6 +117,7 @@ lfs_bwrite(ap)
ip->i_flag |= IN_CHANGE | IN_MODIFIED | IN_UPDATE;
fs->lfs_avail -= db;
++locked_queue_count;
+ ++numdirtybuffers;
bp->b_flags |= B_DELWRI | B_LOCKED;
bp->b_flags &= ~(B_READ | B_ERROR);
s = splbio();
diff --git a/sys/ufs/lfs/lfs_segment.c b/sys/ufs/lfs/lfs_segment.c
index 7c2c0a5c2429..4798303a5c3f 100644
--- a/sys/ufs/lfs/lfs_segment.c
+++ b/sys/ufs/lfs/lfs_segment.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)lfs_segment.c 8.10 (Berkeley) 6/10/95
- * $Id: lfs_segment.c,v 1.20 1997/02/22 09:47:22 peter Exp $
+ * $Id: lfs_segment.c,v 1.21 1997/03/23 00:45:17 bde Exp $
*/
#include <sys/param.h>
@@ -985,6 +985,11 @@ lfs_writeseg(fs, sp)
cbp->b_bcount += bp->b_bcount;
if (bp->b_flags & B_LOCKED)
--locked_queue_count;
+ if (bp->b_flags & (B_DELWRI|B_LOCKED)) {
+ --numdirtybuffers;
+ if (needsbuffer)
+ vfs_bio_need_satisfy();
+ }
bp->b_flags &= ~(B_ERROR | B_READ | B_DELWRI |
B_LOCKED | B_GATHERED);
if (bp->b_flags & B_CALL) {
@@ -1059,6 +1064,11 @@ lfs_writesuper(fs)
/* XXX Toggle between first two superblocks; for now just write first */
bp->b_dev = i_dev;
bp->b_flags |= B_BUSY | B_CALL | B_ASYNC;
+ if (bp->b_flags & (B_DELWRI|B_LOCKED)) {
+ --numdirtybuffers;
+ if (needsbuffer)
+ vfs_bio_need_satisfy();
+ }
bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI);
bp->b_iodone = lfs_supercallback;
vop_strategy_a.a_desc = VDESC(vop_strategy);