1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-27 16:39:08 +00:00

1) Fix a bug that a buffer is removed from a queue, but the

queue type is not set to QUEUE_NONE.  This appears to have
	caused a hang bug that has been lurking.
2)	Fix bugs that brelse'ing locked buffers do not "free" them, but the
	code assumes so.  This can cause hangs when LFS is used.
3)	Use malloced memory for directories when applicable.  The amount
	of malloced memory is seriously limited, but should decrease the
	amount of memory used by an average directory to 1/4 - 1/2 previous.
	This capability is fully tunable.  (Note that there is no config
	parameter, and might never be.)
4)	Bias slightly the buffer cache usage towards non-VMIO buffers.  Since
	the data in VMIO buffers is not lost when the buffer is reclaimed, this
	will help performance.  This is adjustable also.
This commit is contained in:
John Dyson 1996-03-02 04:40:56 +00:00
parent 9d2baf5cdf
commit 6538dda3dc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=14319
2 changed files with 124 additions and 28 deletions

View File

@ -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.84 1996/01/19 03:58:08 dyson Exp $
* $Id: vfs_bio.c,v 1.85 1996/03/02 03:45:04 dyson Exp $
*/
/*
@ -104,7 +104,8 @@ caddr_t buffers_kva;
vm_page_t bogus_page;
static vm_offset_t bogus_offset;
static int bufspace, maxbufspace;
static int bufspace, maxbufspace, vmiospace, maxvmiobufspace,
bufmallocspace, maxbufmallocspace;
static struct bufhashhdr bufhashtbl[BUFHSZ], invalhash;
static struct bqueues bufqueues[BUFFER_QUEUES];
@ -155,6 +156,18 @@ bufinit()
* keeps the size of the buffer cache "in check" for big block filesystems.
*/
maxbufspace = 2 * (nbuf + 8) * PAGE_SIZE;
/*
* reserve 1/3 of the buffers for metadata (VDIR) which might not be VMIO'ed
*/
maxvmiobufspace = 2 * maxbufspace / 3;
/*
* Limit the amount of malloc memory since it is wired permanently into
* the kernel space. Even though this is accounted for in the buffer
* allocation, we don't want the malloced region to grow uncontrolled.
* The malloc scheme improves memory utilization significantly on average
* (small) directories.
*/
maxbufmallocspace = maxbufspace / 20;
bogus_offset = kmem_alloc_pageable(kernel_map, PAGE_SIZE);
bogus_page = vm_page_alloc(kernel_object,
@ -397,11 +410,6 @@ brelse(struct buf * bp)
/* anyone need a "free" block? */
s = splbio();
if (needsbuffer) {
needsbuffer = 0;
wakeup(&needsbuffer);
}
/* anyone need this block? */
if (bp->b_flags & B_WANTED) {
bp->b_flags &= ~(B_WANTED | B_AGE);
@ -505,6 +513,10 @@ brelse(struct buf * bp)
LIST_REMOVE(bp, b_hash);
LIST_INSERT_HEAD(&invalhash, bp, b_hash);
bp->b_dev = NODEV;
if (needsbuffer) {
wakeup(&needsbuffer);
needsbuffer=0;
}
/* buffers with junk contents */
} else if (bp->b_flags & (B_ERROR | B_INVAL | B_NOCACHE | B_RELBUF)) {
bp->b_qindex = QUEUE_AGE;
@ -512,6 +524,10 @@ brelse(struct buf * bp)
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 */
} else if (bp->b_flags & B_LOCKED) {
bp->b_qindex = QUEUE_LOCKED;
@ -520,10 +536,18 @@ brelse(struct buf * bp)
} 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 */
} else {
bp->b_qindex = QUEUE_LRU;
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_LRU], bp, b_freelist);
if (needsbuffer) {
wakeup(&needsbuffer);
needsbuffer=0;
}
}
/* unlock */
@ -541,10 +565,6 @@ bqrelse(struct buf * bp)
s = splbio();
if (needsbuffer) {
needsbuffer = 0;
wakeup(&needsbuffer);
}
/* anyone need this block? */
if (bp->b_flags & B_WANTED) {
@ -563,6 +583,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;
}
}
/* unlock */
@ -602,6 +626,7 @@ vfs_vmio_release(bp)
}
}
bufspace -= bp->b_bufsize;
vmiospace -= bp->b_bufsize;
pmap_qremove(trunc_page((vm_offset_t) bp->b_data), bp->b_npages);
bp->b_npages = 0;
bp->b_bufsize = 0;
@ -707,7 +732,6 @@ getnewbuf(int slpflag, int slptimeo, int doingvmio)
int s;
int nbyteswritten = 0;
s = splbio();
start:
if (bufspace >= maxbufspace)
goto trytofreespace;
@ -741,16 +765,28 @@ getnewbuf(int slpflag, int slptimeo, int doingvmio)
needsbuffer = 1;
tsleep(&needsbuffer,
(PRIBIO + 1) | slpflag, "newbuf", slptimeo);
splx(s);
return (0);
}
/*
* We are fairly aggressive about freeing VMIO buffers, but since
* the buffering is intact without buffer headers, there is not
* much loss. We gain by maintaining non-VMIOed metadata in buffers.
*/
if ((bp->b_qindex == QUEUE_LRU) && (bp->b_usecount > 0)) {
--bp->b_usecount;
TAILQ_REMOVE(&bufqueues[QUEUE_LRU], bp, b_freelist);
if (bufqueues[QUEUE_LRU].tqh_first != NULL) {
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_LRU], bp, b_freelist);
goto start;
if ((bp->b_flags & B_VMIO) == 0 ||
(vmiospace < maxvmiobufspace)) {
--bp->b_usecount;
TAILQ_REMOVE(&bufqueues[QUEUE_LRU], bp, b_freelist);
if (bufqueues[QUEUE_LRU].tqh_first != NULL) {
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_LRU], bp, b_freelist);
goto start;
}
/*
* Make sure that the buffer is flagged as not being on a
* queue.
*/
bp->b_qindex = QUEUE_NONE;
}
}
@ -758,7 +794,6 @@ getnewbuf(int slpflag, int slptimeo, int doingvmio)
if ((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI) {
nbyteswritten += vfs_bio_awrite(bp);
if (!slpflag && !slptimeo) {
splx(s);
return (0);
}
goto start;
@ -790,7 +825,6 @@ getnewbuf(int slpflag, int slptimeo, int doingvmio)
LIST_REMOVE(bp, b_hash);
LIST_INSERT_HEAD(&invalhash, bp, b_hash);
splx(s);
if (bp->b_bufsize) {
allocbuf(bp, 0);
}
@ -808,7 +842,6 @@ getnewbuf(int slpflag, int slptimeo, int doingvmio)
bp->b_validoff = bp->b_validend = 0;
bp->b_usecount = 2;
if (bufspace >= maxbufspace + nbyteswritten) {
s = splbio();
bp->b_flags |= B_INVAL;
brelse(bp);
goto trytofreespace;
@ -1037,8 +1070,11 @@ struct buf *
geteblk(int size)
{
struct buf *bp;
int s;
s = splbio();
while ((bp = getnewbuf(0, 0, 0)) == 0);
splx(s);
allocbuf(bp, size);
bp->b_flags |= B_INVAL;
return (bp);
@ -1068,22 +1104,80 @@ allocbuf(struct buf * bp, int size)
panic("allocbuf: buffer not busy");
if ((bp->b_flags & B_VMIO) == 0) {
caddr_t origbuf;
int origbufsize;
/*
* Just get anonymous memory from the kernel
*/
mbsize = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
newbsize = round_page(size);
if (bp->b_flags & B_MALLOC)
newbsize = mbsize;
else
newbsize = round_page(size);
if (newbsize < bp->b_bufsize) {
/*
* malloced buffers are not shrunk
*/
if (bp->b_flags & B_MALLOC) {
if (newbsize) {
bp->b_bcount = size;
} else {
free(bp->b_data, M_TEMP);
bufspace -= bp->b_bufsize;
bufmallocspace -= bp->b_bufsize;
bp->b_data = (caddr_t) buffers_kva + (bp - buf) * MAXBSIZE;
bp->b_bufsize = 0;
bp->b_bcount = 0;
bp->b_flags &= ~B_MALLOC;
}
return 1;
}
vm_hold_free_pages(
bp,
(vm_offset_t) bp->b_data + newbsize,
(vm_offset_t) bp->b_data + bp->b_bufsize);
} else if (newbsize > bp->b_bufsize) {
/*
* We only use malloced memory on the first allocation.
* and revert to page-allocated memory when the buffer grows.
*/
if ( (bufmallocspace < maxbufmallocspace) &&
(bp->b_bufsize == 0) &&
(mbsize <= PAGE_SIZE/2)) {
bp->b_data = malloc(mbsize, M_TEMP, M_WAITOK);
bp->b_bufsize = mbsize;
bp->b_bcount = size;
bp->b_flags |= B_MALLOC;
bufspace += mbsize;
bufmallocspace += mbsize;
return 1;
}
origbuf = NULL;
origbufsize = 0;
/*
* If the buffer is growing on it's other-than-first allocation,
* then we revert to the page-allocation scheme.
*/
if (bp->b_flags & B_MALLOC) {
origbuf = bp->b_data;
origbufsize = bp->b_bufsize;
bp->b_data = (caddr_t) buffers_kva + (bp - buf) * MAXBSIZE;
bufspace -= bp->b_bufsize;
bufmallocspace -= bp->b_bufsize;
bp->b_bufsize = 0;
bp->b_flags &= ~B_MALLOC;
newbsize = round_page(newbsize);
}
vm_hold_load_pages(
bp,
(vm_offset_t) bp->b_data + bp->b_bufsize,
(vm_offset_t) bp->b_data + newbsize);
if (origbuf) {
bcopy(origbuf, bp->b_data, origbufsize);
free(origbuf, M_TEMP);
}
}
} else {
vm_page_t m;
@ -1092,6 +1186,9 @@ allocbuf(struct buf * bp, int size)
newbsize = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
desiredpages = (round_page(newbsize) >> PAGE_SHIFT);
if (bp->b_flags & B_MALLOC)
panic("allocbuf: VMIO buffer can't be malloced");
if (newbsize < bp->b_bufsize) {
if (desiredpages < bp->b_npages) {
for (i = desiredpages; i < bp->b_npages; i++) {
@ -1206,9 +1303,6 @@ allocbuf(struct buf * bp, int size)
bp->b_pages[pageindex] = m;
curbpnpages = pageindex + 1;
}
/*
bp->b_data = buffers_kva + (bp - buf) * MAXBSIZE;
*/
bp->b_data = (caddr_t) trunc_page(bp->b_data);
bp->b_npages = curbpnpages;
pmap_qenter((vm_offset_t) bp->b_data,
@ -1217,6 +1311,8 @@ allocbuf(struct buf * bp, int size)
}
}
}
if (bp->b_flags & B_VMIO)
vmiospace += bp->b_bufsize;
bufspace += (newbsize - bp->b_bufsize);
bp->b_bufsize = newbsize;
bp->b_bcount = size;

View File

@ -33,7 +33,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_cluster.c 8.7 (Berkeley) 2/13/94
* $Id: vfs_cluster.c,v 1.33 1996/01/20 23:24:16 dyson Exp $
* $Id: vfs_cluster.c,v 1.34 1996/01/28 18:25:54 dyson Exp $
*/
#include <sys/param.h>
@ -294,7 +294,7 @@ cluster_rbuild(vp, filesize, lbn, blkno, size, run)
}
tbp = getblk(vp, lbn, size, 0, 0);
if (tbp->b_flags & B_CACHE)
if (tbp->b_flags & (B_CACHE|B_MALLOC))
return tbp;
tbp->b_blkno = blkno;
@ -591,7 +591,7 @@ cluster_wbuild(vp, size, start_lbn, len)
* potentially pull it back up if the cluster was terminated
* prematurely--too much hassle.
*/
if (((tbp->b_flags & B_CLUSTEROK) != B_CLUSTEROK) ||
if (((tbp->b_flags & (B_CLUSTEROK|B_MALLOC)) != B_CLUSTEROK) ||
(tbp->b_bcount != tbp->b_bufsize) ||
(tbp->b_bcount != size) ||
len == 1) {