summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2007-07-03 18:30:55 +0000
committerjhb <jhb@FreeBSD.org>2007-07-03 18:30:55 +0000
commit788b235895ff7154d4548cecaa697384662eeaaf (patch)
tree8869bd5d3dd765504610ed7c731db937ff7a746b /sys/nfsclient
parentc88cac4c418f97044c4063d61485f404a44d14e7 (diff)
downloadFreeBSD-src-788b235895ff7154d4548cecaa697384662eeaaf.zip
FreeBSD-src-788b235895ff7154d4548cecaa697384662eeaaf.tar.gz
Fix up NFS client write error handling. Errors are split into
recoverable and unrecoverable. For the former, we redirty the buffer and hang onto it for future retries. For the latter (eg. ESTALE), we discard the buffer and return the error back to the user on the next syscall. This fixes a number of vfs panics and fixes having a large number of dirty buffers (that cannot be written out and reclaimed) from hanging around. Thanks to ups@ for discussions on this issue. Reported by: kris, Kai, others Approved by: re (kensmith)
Diffstat (limited to 'sys/nfsclient')
-rw-r--r--sys/nfsclient/nfs_bio.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index 147f190..e1a7453 100644
--- a/sys/nfsclient/nfs_bio.c
+++ b/sys/nfsclient/nfs_bio.c
@@ -1714,6 +1714,19 @@ nfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td)
* the vp's paging queues so we cannot call bdirty(). The
* bp in this case is not an NFS cache block so we should
* be safe. XXX
+ *
+ * The logic below breaks up errors into recoverable and
+ * unrecoverable. For the former, we clear B_INVAL|B_NOCACHE
+ * and keep the buffer around for potential write retries.
+ * For the latter (eg ESTALE), we toss the buffer away (B_INVAL)
+ * and save the error in the nfsnode. This is less than ideal
+ * but necessary. Keeping such buffers around could potentially
+ * cause buffer exhaustion eventually (they can never be written
+ * out, so will get constantly be re-dirtied). It also causes
+ * all sorts of vfs panics. For non-recoverable write errors,
+ * also invalidate the attrcache, so we'll be forced to go over
+ * the wire for this object, returning an error to user on next
+ * call (most of the time).
*/
if (error == EINTR || error == EIO || error == ETIMEDOUT
|| (!error && (bp->b_flags & B_NEEDCOMMIT))) {
@@ -1731,9 +1744,11 @@ nfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td)
} else {
if (error) {
bp->b_ioflags |= BIO_ERROR;
+ bp->b_flags |= B_INVAL;
bp->b_error = np->n_error = error;
mtx_lock(&np->n_mtx);
np->n_flag |= NWRITEERR;
+ np->n_attrstamp = 0;
mtx_unlock(&np->n_mtx);
}
bp->b_dirtyoff = bp->b_dirtyend = 0;
OpenPOWER on IntegriCloud