summaryrefslogtreecommitdiffstats
path: root/sys/nfs/nfs_bio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/nfs/nfs_bio.c')
-rw-r--r--sys/nfs/nfs_bio.c292
1 files changed, 181 insertions, 111 deletions
diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c
index f929012..f9ae8b6 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.13 1995/05/21 21:39:21 davidg Exp $
+ * $Id: nfs_bio.c,v 1.14 1995/05/30 08:12:35 rgrimes Exp $
*/
#include <sys/param.h>
@@ -49,16 +49,30 @@
#include <vm/vm.h>
-#include <nfs/nfsnode.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsmount.h>
#include <nfs/nqnfs.h>
+#include <nfs/nfsnode.h>
struct buf *nfs_getcacheblk();
extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
extern int nfs_numasync;
+extern struct nfsstats nfsstats;
+
+/*
+ * Ifdefs for FreeBSD-current's merged VM/buffer cache. It is unfortunate
+ * that this isn't done inside getblk() and brelse() so these calls
+ * wouldn't need to be here.
+ */
+#ifdef B_VMIO
+#define vnode_pager_uncache(vp)
+#else
+#define vfs_busy_pages(bp, f)
+#define vfs_unbusy_pages(bp)
+#define vfs_dirty_pages(bp)
+#endif
/*
* Vnode op for read using bio
@@ -72,29 +86,28 @@ nfs_bioread(vp, uio, ioflag, cred)
struct ucred *cred;
{
register struct nfsnode *np = VTONFS(vp);
- register int biosize, diff;
+ register int biosize, diff, i;
struct buf *bp = 0, *rabp;
struct vattr vattr;
struct proc *p;
- struct nfsmount *nmp;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
daddr_t lbn, rabn;
int bufsize;
int nra, error = 0, n = 0, on = 0, not_readin;
+ nfsquad_t tquad;
-#ifdef lint
- ioflag = ioflag;
-#endif /* lint */
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_READ)
panic("nfs_read mode");
#endif
if (uio->uio_resid == 0)
return (0);
- if (uio->uio_offset < 0 && vp->v_type != VDIR)
+ if (uio->uio_offset < 0)
return (EINVAL);
- nmp = VFSTONFS(vp->v_mount);
- biosize = NFS_MAXDGRAMDATA;
p = uio->uio_procp;
+ if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
+ (void)nfs_fsinfo(nmp, vp, cred, p);
+ biosize = nmp->nm_rsize;
/*
* For nfs, cache consistency can only be maintained approximately.
* Although RFC1094 does not specify the criteria, the following is
@@ -107,8 +120,6 @@ nfs_bioread(vp, uio, ioflag, cred)
* server, so flush all of the file's data out of the cache.
* Then force a getattr rpc to ensure that you have up to date
* attributes.
- * The mount flag NFSMNT_MYWRITE says "Assume that my writes are
- * the ones changing the modify time.
* NB: This implies that cache data can be read when up to
* NFS_ATTRTIMEO seconds out of date. If you find that you need current
* attributes this could be forced by setting n_attrstamp to 0 before
@@ -116,14 +127,15 @@ nfs_bioread(vp, uio, ioflag, cred)
*/
if ((nmp->nm_flag & NFSMNT_NQNFS) == 0 && vp->v_type != VLNK) {
if (np->n_flag & NMODIFIED) {
- if ((nmp->nm_flag & NFSMNT_MYWRITE) == 0 ||
- vp->v_type != VREG) {
+ if (vp->v_type != VREG) {
+ if (vp->v_type != VDIR)
+ panic("nfs: bioread, not dir");
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
}
np->n_attrstamp = 0;
- np->n_direofoffset = 0;
error = VOP_GETATTR(vp, &vattr, cred, p);
if (error)
return (error);
@@ -133,7 +145,8 @@ nfs_bioread(vp, uio, ioflag, cred)
if (error)
return (error);
if (np->n_mtime != vattr.va_mtime.ts_sec) {
- np->n_direofoffset = 0;
+ if (vp->v_type == VDIR)
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
@@ -147,27 +160,24 @@ nfs_bioread(vp, uio, ioflag, cred)
* Get a valid lease. If cached data is stale, flush it.
*/
if (nmp->nm_flag & NFSMNT_NQNFS) {
- if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
+ if (NQNFS_CKINVALID(vp, np, ND_READ)) {
do {
- error = nqnfs_getlease(vp, NQL_READ, cred, p);
+ error = nqnfs_getlease(vp, ND_READ, cred, p);
} while (error == NQNFS_EXPIRED);
if (error)
return (error);
if (np->n_lrev != np->n_brev ||
(np->n_flag & NQNFSNONCACHE) ||
((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) {
- if (vp->v_type == VDIR) {
- np->n_direofoffset = 0;
- cache_purge(vp);
- }
+ if (vp->v_type == VDIR)
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
np->n_brev = np->n_lrev;
}
} else if (vp->v_type == VDIR && (np->n_flag & NMODIFIED)) {
- np->n_direofoffset = 0;
- cache_purge(vp);
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
@@ -176,33 +186,27 @@ nfs_bioread(vp, uio, ioflag, cred)
if (np->n_flag & NQNFSNONCACHE) {
switch (vp->v_type) {
case VREG:
- error = nfs_readrpc(vp, uio, cred);
- break;
+ return (nfs_readrpc(vp, uio, cred));
case VLNK:
- error = nfs_readlinkrpc(vp, uio, cred);
- break;
+ return (nfs_readlinkrpc(vp, uio, cred));
case VDIR:
- error = nfs_readdirrpc(vp, uio, cred);
break;
default:
printf(" NQNFSNONCACHE: type %x unexpected\n",
vp->v_type);
- break;
};
- return (error);
}
switch (vp->v_type) {
case VREG:
nfsstats.biocache_reads++;
lbn = uio->uio_offset / biosize;
- on = uio->uio_offset & (biosize-1);
+ on = uio->uio_offset & (biosize - 1);
not_readin = 1;
/*
* Start the read ahead(s), as required.
*/
- if (nfs_numasync > 0 && nmp->nm_readahead > 0 &&
- lbn == vp->v_lastr + 1) {
+ if (nfs_numasync > 0 && nmp->nm_readahead > 0) {
for (nra = 0; nra < nmp->nm_readahead &&
(lbn + 1 + nra) * biosize < np->n_size; nra++) {
rabn = lbn + 1 + nra;
@@ -296,32 +300,55 @@ again:
break;
case VDIR:
nfsstats.biocache_readdirs++;
- lbn = (daddr_t)uio->uio_offset;
+ lbn = uio->uio_offset / NFS_DIRBLKSIZ;
+ on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, p);
if (!bp)
- return (EINTR);
-
+ 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) {
+ 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++) {
+ 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);
+ }
+ }
}
+ if (error)
+ return (error);
+ }
}
/*
* If not eof and read aheads are enabled, start one.
* (You need the current block first, so that you have the
- * directory offset cookie of the next block.
+ * directory offset cookie of the next block.)
*/
- rabn = bp->b_blkno;
if (nfs_numasync > 0 && nmp->nm_readahead > 0 &&
- rabn != 0 && rabn != np->n_direofoffset &&
- !incore(vp, rabn)) {
- rabp = nfs_getcacheblk(vp, rabn, NFS_DIRBLKSIZ, p);
+ (np->n_direofoffset == 0 ||
+ (lbn + 1) * NFS_DIRBLKSIZ < np->n_direofoffset) &&
+ !(np->n_flag & NQNFSNONCACHE) &&
+ !incore(vp, lbn + 1)) {
+ rabp = nfs_getcacheblk(vp, lbn + 1, NFS_DIRBLKSIZ, p);
if (rabp) {
if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
rabp->b_flags |= (B_READ | B_ASYNC);
@@ -336,11 +363,10 @@ again:
}
}
}
- on = 0;
- n = min(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid);
+ n = min(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on);
break;
default:
- printf(" nfsbioread: type %x unexpected\n",vp->v_type);
+ printf(" nfs_bioread: type %x unexpected\n",vp->v_type);
break;
};
@@ -354,11 +380,11 @@ again:
n = 0;
break;
case VDIR:
- uio->uio_offset = bp->b_blkno;
+ if (np->n_flag & NQNFSNONCACHE)
+ bp->b_flags |= B_INVAL;
break;
default:
- printf(" nfsbioread: type %x unexpected\n",vp->v_type);
- break;
+ printf(" nfs_bioread: type %x unexpected\n",vp->v_type);
}
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n > 0);
@@ -386,10 +412,10 @@ nfs_write(ap)
int ioflag = ap->a_ioflag;
struct buf *bp;
struct vattr vattr;
- struct nfsmount *nmp;
- daddr_t lbn;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ daddr_t lbn, bn;
int bufsize;
- int n, on, error = 0;
+ int n, on, error = 0, iomode, must_commit;
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_WRITE)
@@ -403,6 +429,8 @@ nfs_write(ap)
np->n_flag &= ~NWRITEERR;
return (np->n_error);
}
+ if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
+ (void)nfs_fsinfo(nmp, vp, cred, p);
if (ioflag & (IO_APPEND | IO_SYNC)) {
if (np->n_flag & NMODIFIED) {
np->n_attrstamp = 0;
@@ -418,7 +446,6 @@ nfs_write(ap)
uio->uio_offset = np->n_size;
}
}
- nmp = VFSTONFS(vp->v_mount);
if (uio->uio_offset < 0)
return (EINVAL);
if (uio->uio_resid == 0)
@@ -437,7 +464,7 @@ nfs_write(ap)
* will be the same size within a filesystem. nfs_writerpc will
* still use nm_wsize when sizing the rpc's.
*/
- biosize = NFS_MAXDGRAMDATA;
+ biosize = nmp->nm_rsize;
do {
/*
@@ -445,12 +472,11 @@ nfs_write(ap)
*/
/*
* Check for a valid write lease.
- * If non-cachable, just do the rpc
*/
if ((nmp->nm_flag & NFSMNT_NQNFS) &&
- NQNFS_CKINVALID(vp, np, NQL_WRITE)) {
+ NQNFS_CKINVALID(vp, np, ND_WRITE)) {
do {
- error = nqnfs_getlease(vp, NQL_WRITE, cred, p);
+ error = nqnfs_getlease(vp, ND_WRITE, cred, p);
} while (error == NQNFS_EXPIRED);
if (error)
return (error);
@@ -462,8 +488,13 @@ nfs_write(ap)
np->n_brev = np->n_lrev;
}
}
- if (np->n_flag & NQNFSNONCACHE)
- return (nfs_writerpc(vp, uio, cred, ioflag));
+ if ((np->n_flag & NQNFSNONCACHE) && uio->uio_iovcnt == 1) {
+ iomode = NFSV3WRITE_FILESYNC;
+ error = nfs_writerpc(vp, uio, cred, &iomode, &must_commit);
+ if (must_commit)
+ nfs_clearcommit(vp->v_mount);
+ return (error);
+ }
nfsstats.biocache_writes++;
lbn = uio->uio_offset / biosize;
on = uio->uio_offset & (biosize-1);
@@ -509,9 +540,9 @@ again:
* In case getblk() and/or bwrite() delayed us.
*/
if ((nmp->nm_flag & NFSMNT_NQNFS) &&
- NQNFS_CKINVALID(vp, np, NQL_WRITE)) {
+ NQNFS_CKINVALID(vp, np, ND_WRITE)) {
do {
- error = nqnfs_getlease(vp, NQL_WRITE, cred, p);
+ error = nqnfs_getlease(vp, ND_WRITE, cred, p);
} while (error == NQNFS_EXPIRED);
if (error) {
brelse(bp);
@@ -540,7 +571,6 @@ again:
bp->b_dirtyoff = on;
bp->b_dirtyend = on + n;
}
-#ifndef notdef
if (bp->b_validend == 0 || bp->b_validend < bp->b_dirtyoff ||
bp->b_validoff > bp->b_dirtyend) {
bp->b_validoff = bp->b_dirtyoff;
@@ -549,13 +579,6 @@ again:
bp->b_validoff = min(bp->b_validoff, bp->b_dirtyoff);
bp->b_validend = max(bp->b_validend, bp->b_dirtyend);
}
-#else
- bp->b_validoff = bp->b_dirtyoff;
- bp->b_validend = bp->b_dirtyend;
-#endif
- if (ioflag & IO_APPEND)
- bp->b_flags |= B_APPENDWRITE;
-
/*
* If the lease is non-cachable or IO_SYNC do bwrite().
*/
@@ -564,10 +587,16 @@ again:
error = VOP_BWRITE(bp);
if (error)
return (error);
+ if (np->n_flag & NQNFSNONCACHE) {
+ error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ if (error)
+ return (error);
+ }
} else if ((n + on) == biosize &&
(nmp->nm_flag & NFSMNT_NQNFS) == 0) {
bp->b_proc = (struct proc *)0;
- bawrite(bp);
+ bp->b_flags |= B_ASYNC;
+ (void)nfs_writebp(bp, 0);
} else
bdwrite(bp);
} while (uio->uio_resid > 0 && n > 0);
@@ -590,6 +619,7 @@ nfs_getcacheblk(vp, bn, size, p)
{
register struct buf *bp;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ int biosize = nmp->nm_rsize;
if (nmp->nm_flag & NFSMNT_INT) {
bp = getblk(vp, bn, size, PCATCH, 0);
@@ -602,7 +632,7 @@ nfs_getcacheblk(vp, bn, size, p)
bp = getblk(vp, bn, size, 0, 0);
if( vp->v_type == VREG)
- bp->b_blkno = (bn * NFS_MAXDGRAMDATA) / DEV_BSIZE;
+ bp->b_blkno = (bn * biosize) / DEV_BSIZE;
return (bp);
}
@@ -689,6 +719,7 @@ nfs_asyncio(bp, cred)
bp->b_rcred = cred;
}
} else {
+ bp->b_flags |= B_WRITEINPROG;
if (bp->b_wcred == NOCRED && cred != NOCRED) {
crhold(cred);
bp->b_wcred = cred;
@@ -700,7 +731,25 @@ nfs_asyncio(bp, cred)
wakeup((caddr_t)&nfs_iodwant[i]);
return (0);
}
- return (EIO);
+
+ /*
+ * If it is a read or a write already marked B_WRITEINPROG or B_NOCACHE
+ * return EIO so the process will call nfs_doio() and do it
+ * synchronously.
+ */
+ if (bp->b_flags & (B_READ | B_WRITEINPROG | B_NOCACHE))
+ return (EIO);
+
+ /*
+ * Just turn the async write into a delayed write, instead of
+ * doing in synchronously. Hopefully, at least one of the nfsiods
+ * is currently doing a write for this file and will pick up the
+ * delayed writes before going back to sleep.
+ */
+ bp->b_flags |= B_DELWRI;
+ reassignbuf(bp, bp->b_vp);
+ biodone(bp);
+ return (0);
}
/*
@@ -717,9 +766,10 @@ nfs_doio(bp, cr, p)
register struct vnode *vp;
struct nfsnode *np;
struct nfsmount *nmp;
- int error = 0, diff, len;
+ int error = 0, diff, len, iomode, must_commit = 0;
struct uio uio;
struct iovec io;
+ nfsquad_t tquad;
vp = bp->b_vp;
np = VTONFS(vp);
@@ -740,15 +790,18 @@ nfs_doio(bp, cr, p)
io.iov_len = uiop->uio_resid = bp->b_bcount;
/* mapping was done by vmapbuf() */
io.iov_base = bp->b_data;
- uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
if (bp->b_flags & B_READ) {
uiop->uio_rw = UIO_READ;
nfsstats.read_physios++;
error = nfs_readrpc(vp, uiop, cr);
} else {
+ int com;
+
+ iomode = NFSV3WRITE_DATASYNC;
uiop->uio_rw = UIO_WRITE;
nfsstats.write_physios++;
- error = nfs_writerpc(vp, uiop, cr,0);
+ error = nfs_writerpc(vp, uiop, cr, &iomode, &com);
}
if (error) {
bp->b_flags |= B_ERROR;
@@ -760,7 +813,7 @@ nfs_doio(bp, cr, p)
uiop->uio_rw = UIO_READ;
switch (vp->v_type) {
case VREG:
- uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
nfsstats.read_bios++;
error = nfs_readrpc(vp, uiop, cr);
if (!error) {
@@ -773,7 +826,7 @@ nfs_doio(bp, cr, p)
* Just zero fill the rest of the valid area.
*/
diff = bp->b_bcount - uiop->uio_resid;
- len = np->n_size - (bp->b_blkno * DEV_BSIZE
+ len = np->n_size - (((u_quad_t)bp->b_blkno) * DEV_BSIZE
+ diff);
if (len > 0) {
len = min(len, uiop->uio_resid);
@@ -786,31 +839,34 @@ nfs_doio(bp, cr, p)
}
if (p && (vp->v_flag & VTEXT) &&
(((nmp->nm_flag & NFSMNT_NQNFS) &&
- NQNFS_CKINVALID(vp, np, NQL_READ) &&
+ NQNFS_CKINVALID(vp, np, ND_READ) &&
np->n_lrev != np->n_brev) ||
(!(nmp->nm_flag & NFSMNT_NQNFS) &&
np->n_mtime != np->n_vattr.va_mtime.ts_sec))) {
uprintf("Process killed due to text file modification\n");
psignal(p, SIGKILL);
+#ifdef __NetBSD__
+ p->p_holdcnt++;
+#else
p->p_flag |= P_NOSWAP;
+#endif
}
break;
case VLNK:
- uiop->uio_offset = 0;
+ uiop->uio_offset = (off_t)0;
nfsstats.readlink_bios++;
error = nfs_readlinkrpc(vp, uiop, cr);
break;
case VDIR:
- uiop->uio_offset = bp->b_lblkno;
nfsstats.readdir_bios++;
- if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS)
- error = nfs_readdirlookrpc(vp, uiop, cr);
- else
- error = nfs_readdirrpc(vp, uiop, cr);
- /*
- * Save offset cookie in b_blkno.
- */
- bp->b_blkno = uiop->uio_offset;
+ uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
+ if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
+ error = nfs_readdirplusrpc(vp, uiop, cr);
+ if (error == NFSERR_NOTSUPP)
+ nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
+ }
+ if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
+ error = nfs_readdirrpc(vp, uiop, cr);
break;
default:
printf("nfs_doio: type %x unexpected\n",vp->v_type);
@@ -821,32 +877,44 @@ nfs_doio(bp, cr, p)
bp->b_error = error;
}
} else {
-
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;
+ - bp->b_dirtyoff;
+ uiop->uio_offset = ((off_t)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);
+ if ((bp->b_flags & (B_ASYNC | B_NEEDCOMMIT | B_NOCACHE)) == B_ASYNC)
+ iomode = NFSV3WRITE_UNSTABLE;
+ else
+ iomode = NFSV3WRITE_FILESYNC;
+ bp->b_flags |= B_WRITEINPROG;
+ error = nfs_writerpc(vp, uiop, cr, &iomode, &must_commit);
+ if (!error && iomode == NFSV3WRITE_UNSTABLE)
+ bp->b_flags |= B_NEEDCOMMIT;
else
- error = nfs_writerpc(vp, uiop, cr, 0);
- bp->b_flags &= ~(B_WRITEINPROG | B_APPENDWRITE);
+ bp->b_flags &= ~B_NEEDCOMMIT;
+ bp->b_flags &= ~B_WRITEINPROG;
- /*
- * For an interrupted write, the buffer is still valid and the
- * write hasn't been pushed to the server yet, so we can't set
- * B_ERROR and report the interruption by setting B_EINTR. For
- * the B_ASYNC case, B_EINTR is not relevant, so the rpc attempt
- * is essentially a noop.
- */
- if (error == EINTR) {
+ /*
+ * For an interrupted write, the buffer is still valid
+ * and the write hasn't been pushed to the server yet,
+ * so we can't set B_ERROR and report the interruption
+ * by setting B_EINTR. For the B_ASYNC case, B_EINTR
+ * is not relevant, so the rpc attempt is essentially
+ * a noop. For the case of a V3 write rpc not being
+ * committed to stable storage, the block is still
+ * dirty and requires either a commit rpc or another
+ * write rpc with iomode == NFSV3WRITE_FILESYNC before
+ * the block is reused. This is indicated by setting
+ * the B_DELWRI and B_NEEDCOMMIT flags.
+ */
+ if (error == EINTR
+ || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
bp->b_flags &= ~(B_INVAL|B_NOCACHE);
bp->b_flags |= B_DELWRI;
@@ -874,6 +942,8 @@ nfs_doio(bp, cr, p)
}
}
bp->b_resid = uiop->uio_resid;
+ if (must_commit)
+ nfs_clearcommit(vp->v_mount);
biodone(bp);
return (error);
}
OpenPOWER on IntegriCloud