From 20caa3320be53c538856202682b7879f8f2c11e4 Mon Sep 17 00:00:00 2001 From: rmacklem Date: Fri, 12 Jul 2013 00:59:03 +0000 Subject: [PATCH] MFC: r252673 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 such that the call to the 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. Tested by: remy.nonnenmacher@activnetworks.com git-svn-id: svn://svn.freebsd.org/base/stable/8@253229 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/nfsclient/nfs_subs.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sys/nfsclient/nfs_subs.c b/sys/nfsclient/nfs_subs.c index 059eb14ac..412024d66 100644 --- a/sys/nfsclient/nfs_subs.c +++ b/sys/nfsclient/nfs_subs.c @@ -595,6 +595,7 @@ nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 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 @@ -606,12 +607,22 @@ nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 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; } -- 2.45.0