summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2013-07-03 00:19:03 +0000
committerrmacklem <rmacklem@FreeBSD.org>2013-07-03 00:19:03 +0000
commit8b2d48c78bd39caaabb4d27ae7a55277f366cb11 (patch)
treea3d86df4315ef098997ba62658e33c5e67023cca /sys/fs
parentf267001deec080ed066c932f80bfb869edddde59 (diff)
downloadFreeBSD-src-8b2d48c78bd39caaabb4d27ae7a55277f366cb11.zip
FreeBSD-src-8b2d48c78bd39caaabb4d27ae7a55277f366cb11.tar.gz
A problem with the old NFS client where large writes to large files
would sometimes result in a corrupted file was reported via email. This problem appears to have been caused by r251719 (reverting r251719 fixed the problem). Although I have not been able to reproduce this problem, I suspect it is caused by another thread increasing np->n_size after the mtx_unlock(&np->n_mtx) but before the vnode_pager_setsize() call. Since the np->n_mtx mutex serializes updates to np->n_size, doing the vnode_pager_setsize() with the mutex locked appears to avoid the problem. Unfortunately, vnode_pager_setsize() where the new size is smaller, cannot be called with a mutex held. This patch returns the semantics to be close to pre-r251719 (actually pre-r248567, r248581, r248567 for the new client) such that the call to vnode_pager_setsize() is only delayed until after the mutex is unlocked when np->n_size is shrinking. Since the file is growing when being written, I believe this will fix the corruption. A better solution might be to replace the mutex with a sleep lock, but that is a non-trivial conversion, so this fix is hoped to be sufficient in the meantime. Reported by: David G. Lawrence (dg@dglawrence.com) Tested by: David G. Lawrence (to be done soon) Reviewed by: kib MFC after: 1 week
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/nfsclient/nfs_clport.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index b2ed50a..d7b082b 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -433,6 +433,7 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
vap->va_size = np->n_size;
np->n_attrstamp = 0;
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
+ vnode_pager_setsize(vp, np->n_size);
} else if (np->n_flag & NMODIFIED) {
/*
* We've modified the file: Use the larger
@@ -444,12 +445,22 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
np->n_size = vap->va_size;
np->n_flag |= NSIZECHANGED;
}
+ vnode_pager_setsize(vp, np->n_size);
+ } else if (vap->va_size < np->n_size) {
+ /*
+ * When shrinking the size, the call to
+ * vnode_pager_setsize() cannot be done
+ * with the mutex held, so delay it until
+ * after the mtx_unlock call.
+ */
+ nsize = np->n_size = vap->va_size;
+ np->n_flag |= NSIZECHANGED;
+ setnsize = 1;
} else {
np->n_size = vap->va_size;
np->n_flag |= NSIZECHANGED;
+ vnode_pager_setsize(vp, np->n_size);
}
- setnsize = 1;
- nsize = vap->va_size;
} else {
np->n_size = vap->va_size;
}
OpenPOWER on IntegriCloud