aboutsummaryrefslogtreecommitdiff
path: root/sys/nfs/nfs_bio.c
diff options
context:
space:
mode:
authorDavid Greenman <dg@FreeBSD.org>1995-05-21 21:39:31 +0000
committerDavid Greenman <dg@FreeBSD.org>1995-05-21 21:39:31 +0000
commit61f5d510623c7fd6aa5335cf8c5b785915365c8d (patch)
tree07e1ad65c2ce70cb5c077eecec53a0a1544d9f49 /sys/nfs/nfs_bio.c
parentd6f9f66840bc9b9f0007c1f89139a2d653ef767a (diff)
downloadsrc-61f5d510623c7fd6aa5335cf8c5b785915365c8d.tar.gz
src-61f5d510623c7fd6aa5335cf8c5b785915365c8d.zip
Changes to fix the following bugs:
1) Files weren't properly synced on filesystems other than UFS. In some cases, this lead to lost data. Most likely would be noticed on NFS. The fix is to make the VM page sync/object_clean general rather than in each filesystem. 2) Mixing regular and mmaped file I/O on NFS was very broken. It caused chunks of files to end up as zeroes rather than the intended contents. The fix was to fix several race conditions and to kludge up the "b_dirtyoff" and "b_dirtyend" that NFS relies upon - paying attention to page modifications that occurred via the mmapping. Reviewed by: David Greenman Submitted by: John Dyson
Notes
Notes: svn path=/head/; revision=8692
Diffstat (limited to 'sys/nfs/nfs_bio.c')
-rw-r--r--sys/nfs/nfs_bio.c98
1 files changed, 64 insertions, 34 deletions
diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c
index ebbab310fe9f..057ffb6d598f 100644
--- a/sys/nfs/nfs_bio.c
+++ b/sys/nfs/nfs_bio.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_bio.c 8.5 (Berkeley) 1/4/94
- * $Id: nfs_bio.c,v 1.11 1995/03/04 03:24:34 davidg Exp $
+ * $Id: nfs_bio.c,v 1.12 1995/04/16 05:05:25 davidg Exp $
*/
#include <sys/param.h>
@@ -78,6 +78,7 @@ nfs_bioread(vp, uio, ioflag, cred)
struct proc *p;
struct nfsmount *nmp;
daddr_t lbn, rabn;
+ int bufsize;
int nra, error = 0, n = 0, on = 0, not_readin;
#ifdef lint
@@ -209,7 +210,7 @@ nfs_bioread(vp, uio, ioflag, cred)
rabp = nfs_getcacheblk(vp, rabn, biosize, p);
if (!rabp)
return (EINTR);
- if ((rabp->b_flags & B_DELWRI) == 0) {
+ if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
rabp->b_flags |= (B_READ | B_ASYNC);
vfs_busy_pages(rabp, 0);
if (nfs_asyncio(rabp, cred)) {
@@ -231,7 +232,12 @@ nfs_bioread(vp, uio, ioflag, cred)
* as required.
*/
again:
- bp = nfs_getcacheblk(vp, lbn, biosize, p);
+ bufsize = biosize;
+ if ((lbn + 1) * biosize > np->n_size) {
+ bufsize = np->n_size - lbn * biosize;
+ bufsize = (bufsize + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
+ }
+ bp = nfs_getcacheblk(vp, lbn, bufsize, p);
if (!bp)
return (EINTR);
if ((bp->b_flags & B_CACHE) == 0) {
@@ -244,7 +250,11 @@ again:
return (error);
}
}
- n = min((unsigned)(biosize - on), uio->uio_resid);
+ if (bufsize > on) {
+ n = min((unsigned)(bufsize - on), uio->uio_resid);
+ } else {
+ n = 0;
+ }
diff = np->n_size - uio->uio_offset;
if (diff < n)
n = diff;
@@ -313,7 +323,7 @@ again:
!incore(vp, rabn)) {
rabp = nfs_getcacheblk(vp, rabn, NFS_DIRBLKSIZ, p);
if (rabp) {
- if ((rabp->b_flags & B_CACHE) == 0) {
+ if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
rabp->b_flags |= (B_READ | B_ASYNC);
vfs_busy_pages(rabp, 0);
if (nfs_asyncio(rabp, cred)) {
@@ -378,6 +388,7 @@ nfs_write(ap)
struct vattr vattr;
struct nfsmount *nmp;
daddr_t lbn;
+ int bufsize;
int n, on, error = 0;
#ifdef DIAGNOSTIC
@@ -458,7 +469,16 @@ nfs_write(ap)
on = uio->uio_offset & (biosize-1);
n = min((unsigned)(biosize - on), uio->uio_resid);
again:
- bp = nfs_getcacheblk(vp, lbn, biosize, p);
+ if (uio->uio_offset + n > np->n_size) {
+ np->n_size = uio->uio_offset + n;
+ vnode_pager_setsize(vp, (u_long)np->n_size);
+ }
+ bufsize = biosize;
+ if ((lbn + 1) * biosize > np->n_size) {
+ bufsize = np->n_size - lbn * biosize;
+ bufsize = (bufsize + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
+ }
+ bp = nfs_getcacheblk(vp, lbn, bufsize, p);
if (!bp)
return (EINTR);
if (bp->b_wcred == NOCRED) {
@@ -466,9 +486,9 @@ again:
bp->b_wcred = cred;
}
np->n_flag |= NMODIFIED;
- if (uio->uio_offset + n > np->n_size) {
- np->n_size = uio->uio_offset + n;
- vnode_pager_setsize(vp, (u_long)np->n_size);
+
+ if ((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend > np->n_size) {
+ bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
}
/*
@@ -801,18 +821,23 @@ nfs_doio(bp, cr, p)
bp->b_error = error;
}
} else {
- io.iov_len = uiop->uio_resid = bp->b_dirtyend
- - bp->b_dirtyoff;
- uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
- + bp->b_dirtyoff;
- io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
- uiop->uio_rw = UIO_WRITE;
- nfsstats.write_bios++;
- if (bp->b_flags & B_APPENDWRITE)
- error = nfs_writerpc(vp, uiop, cr, IO_APPEND);
- else
- error = nfs_writerpc(vp, uiop, cr, 0);
- bp->b_flags &= ~(B_WRITEINPROG | B_APPENDWRITE);
+
+ if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
+ bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
+
+ if (bp->b_dirtyend > bp->b_dirtyoff) {
+ io.iov_len = uiop->uio_resid = bp->b_dirtyend
+ - bp->b_dirtyoff;
+ uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
+ + bp->b_dirtyoff;
+ io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
+ uiop->uio_rw = UIO_WRITE;
+ nfsstats.write_bios++;
+ if (bp->b_flags & B_APPENDWRITE)
+ error = nfs_writerpc(vp, uiop, cr, IO_APPEND);
+ else
+ error = nfs_writerpc(vp, uiop, cr, 0);
+ bp->b_flags &= ~(B_WRITEINPROG | B_APPENDWRITE);
/*
* For an interrupted write, the buffer is still valid and the
@@ -821,26 +846,31 @@ nfs_doio(bp, cr, p)
* the B_ASYNC case, B_EINTR is not relevant, so the rpc attempt
* is essentially a noop.
*/
- if (error == EINTR) {
- bp->b_flags &= ~B_INVAL;
- bp->b_flags |= B_DELWRI;
+ if (error == EINTR) {
+ bp->b_flags &= ~(B_INVAL|B_NOCACHE);
+ 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;
- } else {
- if (error) {
- bp->b_flags |= B_ERROR;
- bp->b_error = np->n_error = error;
- np->n_flag |= NWRITEERR;
+ if (bp->b_flags & B_ASYNC)
+ reassignbuf(bp, vp);
+ else
+ bp->b_flags |= B_EINTR;
+ } else {
+ if (error) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = np->n_error = error;
+ np->n_flag |= NWRITEERR;
+ }
+ bp->b_dirtyoff = bp->b_dirtyend = 0;
}
- bp->b_dirtyoff = bp->b_dirtyend = 0;
+ } else {
+ bp->b_resid = 0;
+ biodone(bp);
+ return (0);
}
}
bp->b_resid = uiop->uio_resid;