Rework cluster_rbuild() to use buffers with the file system block size.
From Alasdair Baird.
This commit is contained in:
parent
6957bd875c
commit
36918f312f
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vfs_cluster.c,v 1.20 1998/10/16 14:29:40 bouyer Exp $ */
|
||||
/* $NetBSD: vfs_cluster.c,v 1.21 1998/11/08 18:18:31 mycroft Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
|
@ -57,20 +57,12 @@ struct ctldebug debug13 = { "doreallocblks", &doreallocblks };
|
|||
/*
|
||||
* Local declarations
|
||||
*/
|
||||
struct buf *cluster_newbuf __P((struct vnode *, struct buf *, long, daddr_t,
|
||||
daddr_t, long, int));
|
||||
struct buf *cluster_rbuild __P((struct vnode *, u_quad_t, struct buf *,
|
||||
daddr_t, daddr_t, long, int, long));
|
||||
void cluster_wbuild __P((struct vnode *, struct buf *, long,
|
||||
daddr_t, int, daddr_t));
|
||||
struct cluster_save *cluster_collectbufs __P((struct vnode *, struct buf *));
|
||||
|
||||
/*
|
||||
* Instrument how many times a read cluster was aborted due to
|
||||
* not being able to push memory out of a buffer.
|
||||
*/
|
||||
u_long cluster_rbuild_too_much_memory;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* Set to 1 if reads of block zero should cause readahead to be done.
|
||||
|
@ -135,7 +127,7 @@ cluster_read(vp, filesize, lblkno, size, cred, bpp)
|
|||
error = 0;
|
||||
flags = B_READ;
|
||||
*bpp = bp = getblk(vp, lblkno, size, 0, 0);
|
||||
if (bp->b_flags & B_CACHE) {
|
||||
if (bp->b_flags & (B_DONE | B_DELWRI)) {
|
||||
/*
|
||||
* Desired block is in cache; do any readahead ASYNC.
|
||||
* Case 1, 2.
|
||||
|
@ -206,10 +198,12 @@ cluster_read(vp, filesize, lblkno, size, cred, bpp)
|
|||
bp->b_blkno = blkno;
|
||||
/* Case 5: check how many blocks to read ahead */
|
||||
++ioblkno;
|
||||
if ((u_quad_t)(ioblkno + 1) * (u_quad_t)size >
|
||||
filesize ||
|
||||
incore(vp, ioblkno) || (error = VOP_BMAP(vp,
|
||||
ioblkno, NULL, &blkno, &num_ra)) || blkno == -1)
|
||||
if (((u_quad_t)(ioblkno + 1) * (u_quad_t)size >
|
||||
filesize) ||
|
||||
incore(vp, ioblkno) ||
|
||||
(error = VOP_BMAP(vp, ioblkno, NULL,
|
||||
&blkno, &num_ra)) ||
|
||||
blkno == -1)
|
||||
goto skip_readahead;
|
||||
/*
|
||||
* Adjust readahead as above.
|
||||
|
@ -274,7 +268,7 @@ skip_readahead:
|
|||
if (rbp == NULL)
|
||||
rbp = bp;
|
||||
if (rbp)
|
||||
vp->v_maxra = rbp->b_lblkno + (rbp->b_bufsize / size) - 1;
|
||||
vp->v_maxra = rbp->b_lblkno + (rbp->b_bcount / size) - 1;
|
||||
|
||||
if (bp)
|
||||
return(biowait(bp));
|
||||
|
@ -297,7 +291,7 @@ cluster_rbuild(vp, filesize, bp, lbn, blkno, size, run, flags)
|
|||
int run;
|
||||
long flags;
|
||||
{
|
||||
struct cluster_save *b_save;
|
||||
struct cluster_save *b_save = 0;
|
||||
struct buf *tbp;
|
||||
daddr_t bn;
|
||||
int i, inc;
|
||||
|
@ -315,117 +309,109 @@ cluster_rbuild(vp, filesize, bp, lbn, blkno, size, run, flags)
|
|||
bp->b_blkno = blkno;
|
||||
bp->b_flags |= flags;
|
||||
}
|
||||
return(bp);
|
||||
return (bp);
|
||||
}
|
||||
|
||||
bp = cluster_newbuf(vp, bp, flags, blkno, lbn, size, run + 1);
|
||||
if (!bp)
|
||||
bp = getblk(vp, lbn, size, 0, 0);
|
||||
bp->b_blkno = blkno;
|
||||
|
||||
/*
|
||||
* If initial component of the cluster is already
|
||||
* in core, terminate the cluster early.
|
||||
*/
|
||||
if (bp->b_flags & (B_DONE | B_DELWRI))
|
||||
return (bp);
|
||||
|
||||
b_save = malloc(sizeof(struct buf *) * run + sizeof(struct cluster_save),
|
||||
M_SEGMENT, M_WAITOK);
|
||||
b_save->bs_bufsize = b_save->bs_bcount = size;
|
||||
b_save->bs_nchildren = 0;
|
||||
b_save->bs_children = (struct buf **)(b_save + 1);
|
||||
b_save->bs_saveaddr = bp->b_saveaddr;
|
||||
bp->b_saveaddr = (caddr_t) b_save;
|
||||
bp->b_flags |= flags;
|
||||
|
||||
/*
|
||||
* If block size is not a multiple of page size there
|
||||
* is no way of doing the necessary page moving, so
|
||||
* terminate early.
|
||||
*/
|
||||
if (size != roundup(size, CLBYTES))
|
||||
return (bp);
|
||||
|
||||
inc = btodb(size);
|
||||
for (bn = blkno + inc, i = 1; i <= run; ++i, bn += inc) {
|
||||
/*
|
||||
* A component of the cluster is already in core,
|
||||
* If a component of the cluster is already in core,
|
||||
* terminate the cluster early.
|
||||
*/
|
||||
if (incore(vp, lbn + i))
|
||||
break;
|
||||
tbp = getblk(vp, lbn + i, 0, 0, 0);
|
||||
/*
|
||||
* getblk may return some memory in the buffer if there were
|
||||
* no empty buffers to shed it to. If there is currently
|
||||
* memory in the buffer, we move it down size bytes to make
|
||||
* room for the valid pages that cluster_callback will insert.
|
||||
* We do this now so we don't have to do it at interrupt time
|
||||
* in the callback routine.
|
||||
*/
|
||||
if (tbp->b_bufsize != 0) {
|
||||
caddr_t bdata = (char *)tbp->b_data;
|
||||
|
||||
/*
|
||||
* No room in the buffer to add another page,
|
||||
* terminate the cluster early.
|
||||
*/
|
||||
if (tbp->b_bufsize + size > MAXBSIZE) {
|
||||
/*
|
||||
* Instrument this; we used to crash if
|
||||
* DIAGNOSTIC, but this can happen a lot
|
||||
* with big buffer caches.
|
||||
*/
|
||||
cluster_rbuild_too_much_memory++;
|
||||
brelse(tbp);
|
||||
break;
|
||||
}
|
||||
if (tbp->b_bufsize > size) {
|
||||
/*
|
||||
* XXX if the source and destination regions
|
||||
* overlap we have to copy backward to avoid
|
||||
* clobbering any valid pages (i.e. pagemove
|
||||
* implementations typically can't handle
|
||||
* overlap).
|
||||
*/
|
||||
bdata += tbp->b_bufsize;
|
||||
while (bdata > (char *)tbp->b_data) {
|
||||
bdata -= CLBYTES;
|
||||
pagemove(bdata, bdata + size, CLBYTES);
|
||||
}
|
||||
} else
|
||||
pagemove(bdata, bdata + size, tbp->b_bufsize);
|
||||
tbp = getblk(vp, lbn + i, size, 0, 0);
|
||||
if (tbp->b_flags & (B_DONE | B_DELWRI)) {
|
||||
brelse(tbp);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are excess pages in the cluster buffer and
|
||||
* this buffer can take some of them, then shift some
|
||||
* of the excess to here.
|
||||
*/
|
||||
if (bp->b_bufsize > (i * size)) {
|
||||
int freespace = MAXBSIZE - tbp->b_bufsize;
|
||||
|
||||
if (freespace > 0) {
|
||||
int nbytes = bp->b_bufsize - (i * size);
|
||||
if (nbytes > freespace)
|
||||
nbytes = freespace;
|
||||
|
||||
/* move pages and update sizes */
|
||||
pagemove(bp->b_data + bp->b_bufsize - nbytes,
|
||||
tbp->b_data + tbp->b_bufsize,
|
||||
nbytes);
|
||||
bp->b_bufsize -= nbytes;
|
||||
tbp->b_bufsize += nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there there is no space for forming a composite
|
||||
* cluster buffer with this one, terminate.
|
||||
*/
|
||||
if (bp->b_bufsize + size > MAXBSIZE) {
|
||||
brelse(tbp);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Have good candidate for cluster; make sure cluster
|
||||
* save area is allocated etc.
|
||||
*/
|
||||
if (b_save == 0) {
|
||||
bp->b_iodone = cluster_callback;
|
||||
bp->b_flags |= B_CALL;
|
||||
|
||||
b_save = malloc(sizeof(struct buf *) * run +
|
||||
sizeof(struct cluster_save),
|
||||
M_SEGMENT, M_WAITOK);
|
||||
b_save->bs_bufsize = b_save->bs_bcount = size;
|
||||
b_save->bs_nchildren = 0;
|
||||
b_save->bs_children = (struct buf **)(b_save + 1);
|
||||
b_save->bs_saveaddr = bp->b_saveaddr;
|
||||
|
||||
bp->b_saveaddr = (caddr_t) b_save;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move pages to the cluster buffer and update
|
||||
* its size appropriately.
|
||||
*/
|
||||
pagemove(tbp->b_data, bp->b_data + bp->b_bufsize, size);
|
||||
bp->b_bcount += size;
|
||||
bp->b_bufsize += size;
|
||||
|
||||
tbp->b_bufsize -= size;
|
||||
tbp->b_blkno = bn;
|
||||
tbp->b_flags |= flags | B_READ | B_ASYNC;
|
||||
++b_save->bs_nchildren;
|
||||
b_save->bs_children[i - 1] = tbp;
|
||||
}
|
||||
/*
|
||||
* The cluster may have been terminated early, adjust the cluster
|
||||
* buffer size accordingly. If no cluster could be formed,
|
||||
* deallocate the cluster save info.
|
||||
*/
|
||||
if (i <= run) {
|
||||
if (i == 1) {
|
||||
bp->b_saveaddr = b_save->bs_saveaddr;
|
||||
bp->b_flags &= ~B_CALL;
|
||||
bp->b_iodone = NULL;
|
||||
free(b_save, M_SEGMENT);
|
||||
}
|
||||
allocbuf(bp, size * i);
|
||||
}
|
||||
return(bp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Either get a new buffer or grow the existing one.
|
||||
*/
|
||||
struct buf *
|
||||
cluster_newbuf(vp, bp, flags, blkno, lblkno, size, run)
|
||||
struct vnode *vp;
|
||||
struct buf *bp;
|
||||
long flags;
|
||||
daddr_t blkno;
|
||||
daddr_t lblkno;
|
||||
long size;
|
||||
int run;
|
||||
{
|
||||
if (!bp) {
|
||||
bp = getblk(vp, lblkno, size, 0, 0);
|
||||
if (bp->b_flags & (B_DONE | B_DELWRI)) {
|
||||
bp->b_blkno = blkno;
|
||||
return(bp);
|
||||
}
|
||||
b_save->bs_children[b_save->bs_nchildren++] = tbp;
|
||||
}
|
||||
allocbuf(bp, run * size);
|
||||
bp->b_blkno = blkno;
|
||||
bp->b_iodone = cluster_callback;
|
||||
bp->b_flags |= flags | B_CALL;
|
||||
|
||||
return(bp);
|
||||
}
|
||||
|
||||
|
@ -440,7 +426,7 @@ cluster_callback(bp)
|
|||
struct buf *bp;
|
||||
{
|
||||
struct cluster_save *b_save;
|
||||
struct buf **bpp, *tbp;
|
||||
struct buf *tbp;
|
||||
long bsize;
|
||||
caddr_t cp;
|
||||
int error = 0;
|
||||
|
@ -455,13 +441,13 @@ cluster_callback(bp)
|
|||
bp->b_saveaddr = b_save->bs_saveaddr;
|
||||
|
||||
bsize = b_save->bs_bufsize;
|
||||
cp = (char *)bp->b_data + bsize;
|
||||
cp = (char *)bp->b_data + bsize * b_save->bs_nchildren;
|
||||
/*
|
||||
* Move memory from the large cluster buffer into the component
|
||||
* buffers and mark IO as done on these.
|
||||
* buffers in reverse order and mark IO as done on these.
|
||||
*/
|
||||
for (bpp = b_save->bs_children; b_save->bs_nchildren--; ++bpp) {
|
||||
tbp = *bpp;
|
||||
while (b_save->bs_nchildren--) {
|
||||
tbp = b_save->bs_children[b_save->bs_nchildren];
|
||||
pagemove(cp, tbp->b_data, bsize);
|
||||
tbp->b_bufsize += bsize;
|
||||
tbp->b_bcount = bsize;
|
||||
|
@ -471,7 +457,7 @@ cluster_callback(bp)
|
|||
}
|
||||
biodone(tbp);
|
||||
bp->b_bufsize -= bsize;
|
||||
cp += bsize;
|
||||
cp -= bsize;
|
||||
}
|
||||
/*
|
||||
* If there was excess memory in the cluster buffer,
|
||||
|
@ -480,11 +466,15 @@ cluster_callback(bp)
|
|||
if (bp->b_bufsize != bsize) {
|
||||
if (bp->b_bufsize < bsize)
|
||||
panic("cluster_callback: too little memory");
|
||||
pagemove(cp, (char *)bp->b_data + bsize, bp->b_bufsize - bsize);
|
||||
pagemove((char *)bp->b_data + bp->b_bcount,
|
||||
(char *)bp->b_data + bsize,
|
||||
bp->b_bufsize - bsize);
|
||||
}
|
||||
bp->b_bcount = bsize;
|
||||
|
||||
bp->b_iodone = NULL;
|
||||
free(b_save, M_SEGMENT);
|
||||
|
||||
if (bp->b_flags & B_ASYNC)
|
||||
brelse(bp);
|
||||
else {
|
||||
|
|
Loading…
Reference in New Issue