Various NFS fixes:

Make vfs_bio buffer mgmt work better.
	Buffers were being used after brelse.
	Make nfs_getpages work independently of other NFS
		interfaces.  This eliminates some difficult
		recursion problems and decreases pagefault
		overhead.
	Remove an erroneous vfs_unbusy_pages.
	Fix a reentrancy problem, with nfs_vinvalbuf when
		vnode is already being rundown.
	Reassignbuf wasn't being called when needed under
		certain circumstances.

	(Thanks to Bill Paul for help.)
This commit is contained in:
John Dyson 1998-01-25 06:24:09 +00:00
parent 8447a0aed7
commit 33b90a70cd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=32755
3 changed files with 163 additions and 177 deletions

View File

@ -11,7 +11,7 @@
* 2. Absolutely no warranty of function or purpose is made by the author
* John S. Dyson.
*
* $Id: vfs_bio.c,v 1.144 1998/01/22 17:29:51 dyson Exp $
* $Id: vfs_bio.c,v 1.145 1998/01/24 02:01:20 dyson Exp $
*/
/*
@ -639,7 +639,11 @@ brelse(struct buf * bp)
}
if (bp->b_flags & (B_INVAL | B_RELBUF))
vfs_vmio_release(bp);
} else if (bp->b_flags & B_VMIO) {
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???");

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95
* $Id: nfs_bio.c,v 1.45 1997/12/08 00:59:08 dyson Exp $
* $Id: nfs_bio.c,v 1.46 1998/01/06 05:21:38 dyson Exp $
*/
@ -76,49 +76,41 @@ int
nfs_getpages(ap)
struct vop_getpages_args *ap;
{
int i, bsize;
vm_object_t obj;
int pcount;
struct uio auio;
struct iovec aiov;
int error;
int i, pcount, error;
struct uio uio;
struct iovec iov;
vm_page_t m;
vm_offset_t kva;
if ((ap->a_vp->v_object) == NULL) {
printf("nfs_getpages: called with non-merged cache vnode??\n");
return EOPNOTSUPP;
}
m = ap->a_m[ap->a_reqpage];
kva = vm_pager_map_page(m);
iov.iov_base = (caddr_t) kva;
iov.iov_len = PAGE_SIZE;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = IDX_TO_OFF(m->pindex);
uio.uio_resid = PAGE_SIZE;
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_rw = UIO_READ;
uio.uio_procp = curproc;
error = nfs_readrpc(ap->a_vp, &uio, curproc->p_ucred);
vm_pager_unmap_page(kva);
pcount = round_page(ap->a_count) / PAGE_SIZE;
obj = ap->a_m[ap->a_reqpage]->object;
bsize = ap->a_vp->v_mount->mnt_stat.f_iosize;
for (i = 0; i < pcount; i++) {
if (i != ap->a_reqpage) {
vnode_pager_freepage(ap->a_m[i]);
}
}
m = ap->a_m[ap->a_reqpage];
m->busy++;
m->flags &= ~PG_BUSY;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
aiov.iov_base = 0;
aiov.iov_len = PAGE_SIZE;
auio.uio_resid = PAGE_SIZE;
auio.uio_offset = IDX_TO_OFF(m->pindex);
auio.uio_segflg = UIO_NOCOPY;
auio.uio_rw = UIO_READ;
auio.uio_procp = curproc;
error = nfs_bioread(ap->a_vp, &auio, IO_NODELOCKED, curproc->p_ucred, 1);
m->flags |= PG_BUSY;
m->busy--;
if (error && (auio.uio_resid == PAGE_SIZE))
if (error && (uio.uio_resid == PAGE_SIZE))
return VM_PAGER_ERROR;
return 0;
}
@ -315,15 +307,15 @@ nfs_bioread(vp, uio, ioflag, cred, getpages)
goto again;
}
if ((bp->b_flags & B_CACHE) == 0) {
bp->b_flags |= B_READ;
bp->b_flags &= ~(B_DONE | B_ERROR | B_INVAL);
not_readin = 0;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
brelse(bp);
return (error);
}
bp->b_flags |= B_READ;
bp->b_flags &= ~(B_DONE | B_ERROR | B_INVAL);
not_readin = 0;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
brelse(bp);
return (error);
}
}
if (bufsize > on) {
n = min((unsigned)(bufsize - on), uio->uio_resid);
@ -358,14 +350,14 @@ nfs_bioread(vp, uio, ioflag, cred, getpages)
if (!bp)
return (EINTR);
if ((bp->b_flags & B_CACHE) == 0) {
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
bp->b_flags |= B_ERROR;
brelse(bp);
return (error);
}
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
bp->b_flags |= B_ERROR;
brelse(bp);
return (error);
}
}
n = min(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
on = 0;
@ -385,34 +377,30 @@ nfs_bioread(vp, uio, ioflag, cred, getpages)
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
vfs_unbusy_pages(bp);
brelse(bp);
while (error == NFSERR_BAD_COOKIE) {
nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, 0, cred, p, 1);
/*
* Yuck! The directory has been modified on the
* server. The only way to get the block is by
* reading from the beginning to get all the
* offset cookies.
*/
for (i = 0; i <= lbn && !error; i++) {
if (np->n_direofoffset
&& (i * NFS_DIRBLKSIZ) >= np->n_direofoffset)
while (error == NFSERR_BAD_COOKIE) {
nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, 0, cred, p, 1);
/*
* Yuck! The directory has been modified on the
* server. The only way to get the block is by
* reading from the beginning to get all the
* offset cookies.
*/
for (i = 0; i <= lbn && !error; i++) {
if (np->n_direofoffset
&& (i * NFS_DIRBLKSIZ) >= np->n_direofoffset)
return (0);
bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, p);
if (!bp)
return (EINTR);
if ((bp->b_flags & B_DONE) == 0) {
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
vfs_unbusy_pages(bp);
brelse(bp);
} else if (i < lbn)
brelse(bp);
bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, p);
if (!bp)
return (EINTR);
if ((bp->b_flags & B_DONE) == 0) {
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
brelse(bp);
} else if (i < lbn) {
brelse(bp);
}
}
}
@ -473,7 +461,7 @@ nfs_bioread(vp, uio, ioflag, cred, getpages)
default:
printf(" nfs_bioread: type %x unexpected\n",vp->v_type);
}
brelse(bp);
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n > 0);
return (error);
}
@ -709,8 +697,11 @@ nfs_getcacheblk(vp, bn, size, p)
struct proc *p;
{
register struct buf *bp;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
int biosize = vp->v_mount->mnt_stat.f_iosize;
struct mount *mp;
struct nfsmount *nmp;
mp = vp->v_mount;
nmp = VFSTONFS(mp);
if (nmp->nm_flag & NFSMNT_INT) {
bp = getblk(vp, bn, size, PCATCH, 0);
@ -722,8 +713,11 @@ nfs_getcacheblk(vp, bn, size, p)
} else
bp = getblk(vp, bn, size, 0, 0);
if( vp->v_type == VREG)
if( vp->v_type == VREG) {
int biosize;
biosize = mp->mnt_stat.f_iosize;
bp->b_blkno = (bn * biosize) / DEV_BSIZE;
}
return (bp);
}
@ -744,6 +738,10 @@ nfs_vinvalbuf(vp, flags, cred, p, intrflg)
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
int error = 0, slpflag, slptimeo;
if (vp->v_flag & VXLOCK) {
return (0);
}
if ((nmp->nm_flag & NFSMNT_INT) == 0)
intrflg = 0;
if (intrflg) {
@ -1070,16 +1068,9 @@ nfs_doio(bp, cr, p)
bp->b_flags &= ~(B_INVAL|B_NOCACHE);
++numdirtybuffers;
bp->b_flags |= B_DELWRI;
/*
* Since for the B_ASYNC case, nfs_bwrite() has reassigned the
* buffer to the clean list, we have to reassign it back to the
* dirty one. Ugh.
*/
if (bp->b_flags & B_ASYNC)
reassignbuf(bp, vp);
else
bp->b_flags |= B_EINTR;
reassignbuf(bp, vp);
if ((bp->b_flags & B_ASYNC) == 0)
bp->b_flags |= B_EINTR;
} else {
if (error) {
bp->b_flags |= B_ERROR;

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95
* $Id: nfs_bio.c,v 1.45 1997/12/08 00:59:08 dyson Exp $
* $Id: nfs_bio.c,v 1.46 1998/01/06 05:21:38 dyson Exp $
*/
@ -76,49 +76,41 @@ int
nfs_getpages(ap)
struct vop_getpages_args *ap;
{
int i, bsize;
vm_object_t obj;
int pcount;
struct uio auio;
struct iovec aiov;
int error;
int i, pcount, error;
struct uio uio;
struct iovec iov;
vm_page_t m;
vm_offset_t kva;
if ((ap->a_vp->v_object) == NULL) {
printf("nfs_getpages: called with non-merged cache vnode??\n");
return EOPNOTSUPP;
}
m = ap->a_m[ap->a_reqpage];
kva = vm_pager_map_page(m);
iov.iov_base = (caddr_t) kva;
iov.iov_len = PAGE_SIZE;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = IDX_TO_OFF(m->pindex);
uio.uio_resid = PAGE_SIZE;
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_rw = UIO_READ;
uio.uio_procp = curproc;
error = nfs_readrpc(ap->a_vp, &uio, curproc->p_ucred);
vm_pager_unmap_page(kva);
pcount = round_page(ap->a_count) / PAGE_SIZE;
obj = ap->a_m[ap->a_reqpage]->object;
bsize = ap->a_vp->v_mount->mnt_stat.f_iosize;
for (i = 0; i < pcount; i++) {
if (i != ap->a_reqpage) {
vnode_pager_freepage(ap->a_m[i]);
}
}
m = ap->a_m[ap->a_reqpage];
m->busy++;
m->flags &= ~PG_BUSY;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
aiov.iov_base = 0;
aiov.iov_len = PAGE_SIZE;
auio.uio_resid = PAGE_SIZE;
auio.uio_offset = IDX_TO_OFF(m->pindex);
auio.uio_segflg = UIO_NOCOPY;
auio.uio_rw = UIO_READ;
auio.uio_procp = curproc;
error = nfs_bioread(ap->a_vp, &auio, IO_NODELOCKED, curproc->p_ucred, 1);
m->flags |= PG_BUSY;
m->busy--;
if (error && (auio.uio_resid == PAGE_SIZE))
if (error && (uio.uio_resid == PAGE_SIZE))
return VM_PAGER_ERROR;
return 0;
}
@ -315,15 +307,15 @@ nfs_bioread(vp, uio, ioflag, cred, getpages)
goto again;
}
if ((bp->b_flags & B_CACHE) == 0) {
bp->b_flags |= B_READ;
bp->b_flags &= ~(B_DONE | B_ERROR | B_INVAL);
not_readin = 0;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
brelse(bp);
return (error);
}
bp->b_flags |= B_READ;
bp->b_flags &= ~(B_DONE | B_ERROR | B_INVAL);
not_readin = 0;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
brelse(bp);
return (error);
}
}
if (bufsize > on) {
n = min((unsigned)(bufsize - on), uio->uio_resid);
@ -358,14 +350,14 @@ nfs_bioread(vp, uio, ioflag, cred, getpages)
if (!bp)
return (EINTR);
if ((bp->b_flags & B_CACHE) == 0) {
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
bp->b_flags |= B_ERROR;
brelse(bp);
return (error);
}
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
bp->b_flags |= B_ERROR;
brelse(bp);
return (error);
}
}
n = min(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
on = 0;
@ -385,34 +377,30 @@ nfs_bioread(vp, uio, ioflag, cred, getpages)
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
vfs_unbusy_pages(bp);
brelse(bp);
while (error == NFSERR_BAD_COOKIE) {
nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, 0, cred, p, 1);
/*
* Yuck! The directory has been modified on the
* server. The only way to get the block is by
* reading from the beginning to get all the
* offset cookies.
*/
for (i = 0; i <= lbn && !error; i++) {
if (np->n_direofoffset
&& (i * NFS_DIRBLKSIZ) >= np->n_direofoffset)
while (error == NFSERR_BAD_COOKIE) {
nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, 0, cred, p, 1);
/*
* Yuck! The directory has been modified on the
* server. The only way to get the block is by
* reading from the beginning to get all the
* offset cookies.
*/
for (i = 0; i <= lbn && !error; i++) {
if (np->n_direofoffset
&& (i * NFS_DIRBLKSIZ) >= np->n_direofoffset)
return (0);
bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, p);
if (!bp)
return (EINTR);
if ((bp->b_flags & B_DONE) == 0) {
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
vfs_unbusy_pages(bp);
brelse(bp);
} else if (i < lbn)
brelse(bp);
bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, p);
if (!bp)
return (EINTR);
if ((bp->b_flags & B_DONE) == 0) {
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
error = nfs_doio(bp, cred, p);
if (error) {
brelse(bp);
} else if (i < lbn) {
brelse(bp);
}
}
}
@ -473,7 +461,7 @@ nfs_bioread(vp, uio, ioflag, cred, getpages)
default:
printf(" nfs_bioread: type %x unexpected\n",vp->v_type);
}
brelse(bp);
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n > 0);
return (error);
}
@ -709,8 +697,11 @@ nfs_getcacheblk(vp, bn, size, p)
struct proc *p;
{
register struct buf *bp;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
int biosize = vp->v_mount->mnt_stat.f_iosize;
struct mount *mp;
struct nfsmount *nmp;
mp = vp->v_mount;
nmp = VFSTONFS(mp);
if (nmp->nm_flag & NFSMNT_INT) {
bp = getblk(vp, bn, size, PCATCH, 0);
@ -722,8 +713,11 @@ nfs_getcacheblk(vp, bn, size, p)
} else
bp = getblk(vp, bn, size, 0, 0);
if( vp->v_type == VREG)
if( vp->v_type == VREG) {
int biosize;
biosize = mp->mnt_stat.f_iosize;
bp->b_blkno = (bn * biosize) / DEV_BSIZE;
}
return (bp);
}
@ -744,6 +738,10 @@ nfs_vinvalbuf(vp, flags, cred, p, intrflg)
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
int error = 0, slpflag, slptimeo;
if (vp->v_flag & VXLOCK) {
return (0);
}
if ((nmp->nm_flag & NFSMNT_INT) == 0)
intrflg = 0;
if (intrflg) {
@ -1070,16 +1068,9 @@ nfs_doio(bp, cr, p)
bp->b_flags &= ~(B_INVAL|B_NOCACHE);
++numdirtybuffers;
bp->b_flags |= B_DELWRI;
/*
* Since for the B_ASYNC case, nfs_bwrite() has reassigned the
* buffer to the clean list, we have to reassign it back to the
* dirty one. Ugh.
*/
if (bp->b_flags & B_ASYNC)
reassignbuf(bp, vp);
else
bp->b_flags |= B_EINTR;
reassignbuf(bp, vp);
if ((bp->b_flags & B_ASYNC) == 0)
bp->b_flags |= B_EINTR;
} else {
if (error) {
bp->b_flags |= B_ERROR;