summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient/nfs_bio.c
diff options
context:
space:
mode:
authordg <dg@FreeBSD.org>1995-05-21 21:39:31 +0000
committerdg <dg@FreeBSD.org>1995-05-21 21:39:31 +0000
commit2045200a00d5a826198657a527d69a42e76d7b98 (patch)
tree07e1ad65c2ce70cb5c077eecec53a0a1544d9f49 /sys/nfsclient/nfs_bio.c
parent3af82d16aabbc7028c07a0cf9039673cb89f0755 (diff)
downloadFreeBSD-src-2045200a00d5a826198657a527d69a42e76d7b98.zip
FreeBSD-src-2045200a00d5a826198657a527d69a42e76d7b98.tar.gz
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
Diffstat (limited to 'sys/nfsclient/nfs_bio.c')
-rw-r--r--sys/nfsclient/nfs_bio.c98
1 files changed, 64 insertions, 34 deletions
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index ebbab31..057ffb6 100644
--- a/sys/nfsclient/nfs_bio.c
+++ b/sys/nfsclient/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;
OpenPOWER on IntegriCloud