diff options
author | dfr <dfr@FreeBSD.org> | 1997-05-19 14:36:56 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 1997-05-19 14:36:56 +0000 |
commit | d7e320b30e346cf2c6e56f2137bd257b8f8278e7 (patch) | |
tree | afc51a58d727816c7b373ca2288b232ae4d5dd97 /sys/nfsclient/nfs_bio.c | |
parent | 9d3c1b4d788c8e5f07a10319b51b2125f3731f85 (diff) | |
download | FreeBSD-src-d7e320b30e346cf2c6e56f2137bd257b8f8278e7.zip FreeBSD-src-d7e320b30e346cf2c6e56f2137bd257b8f8278e7.tar.gz |
Fix a few bugs with NFS and mmap caused by NFS' use of b_validoff
and b_validend. The changes to vfs_bio.c are a bit ugly but hopefully
can be tidied up later by a slight redesign.
PR: kern/2573, kern/2754, kern/3046 (possibly)
Reviewed by: dyson
Diffstat (limited to 'sys/nfsclient/nfs_bio.c')
-rw-r--r-- | sys/nfsclient/nfs_bio.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index bc550fc..2a02371 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 - * $Id: nfs_bio.c,v 1.36 1997/04/19 14:28:36 dfr Exp $ + * $Id: nfs_bio.c,v 1.37 1997/05/13 19:41:32 dfr Exp $ */ @@ -52,6 +52,11 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_extern.h> +#include <vm/vm_prot.h> +#include <vm/vm_page.h> +#include <vm/vm_object.h> +#include <vm/vm_pager.h> +#include <vm/vnode_pager.h> #include <nfs/rpcv2.h> #include <nfs/nfsproto.h> @@ -67,15 +72,70 @@ extern int nfs_numasync; extern struct nfsstats nfsstats; /* + * Vnode op for VM getpages. + */ +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; + vm_page_t m; + + if (!(ap->a_vp->v_flag & VVMIO)) { + printf("nfs_getpages: called with non-VMIO vnode??\n"); + return EOPNOTSUPP; + } + + 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 = MAXBSIZE; + auio.uio_resid = MAXBSIZE; + 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 == MAXBSIZE)) + return VM_PAGER_ERROR; + return 0; +} + +/* * Vnode op for read using bio * Any similarity to readip() is purely coincidental */ int -nfs_bioread(vp, uio, ioflag, cred) +nfs_bioread(vp, uio, ioflag, cred, getpages) register struct vnode *vp; register struct uio *uio; int ioflag; struct ucred *cred; + int getpages; { register struct nfsnode *np = VTONFS(vp); register int biosize, diff, i; @@ -235,6 +295,27 @@ again: bp = nfs_getcacheblk(vp, lbn, bufsize, p); if (!bp) return (EINTR); + /* + * If we are being called from nfs_getpages, we must + * make sure the buffer is a vmio buffer. The vp will + * already be setup for vmio but there may be some old + * non-vmio buffers attached to it. + */ + if (getpages && !(bp->b_flags & B_VMIO)) { +#ifdef DIAGNOSTIC + printf("nfs_bioread: non vmio buf found, discarding\n"); +#endif + bp->b_flags |= B_NOCACHE; + bp->b_flags |= B_INVAFTERWRITE; + if (bp->b_dirtyend > 0) { + if ((bp->b_flags & B_DELWRI) == 0) + panic("nfsbioread"); + if (VOP_BWRITE(bp) == EINTR) + return (EINTR); + } else + brelse(bp); + goto again; + } if ((bp->b_flags & B_CACHE) == 0) { bp->b_flags |= B_READ; bp->b_flags &= ~(B_DONE | B_ERROR | B_INVAL); |