Author: rmacklem
Date: Wed Jul  3 00:19:03 2013
New Revision: 252528
URL: http://svnweb.freebsd.org/changeset/base/252528

Log:
  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 (d...@dglawrence.com)
  Tested by:    David G. Lawrence (to be done soon)
  Reviewed by:  kib
  MFC after:    1 week

Modified:
  head/sys/fs/nfsclient/nfs_clport.c

Modified: head/sys/fs/nfsclient/nfs_clport.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clport.c  Tue Jul  2 21:07:08 2013        
(r252527)
+++ head/sys/fs/nfsclient/nfs_clport.c  Wed Jul  3 00:19:03 2013        
(r252528)
@@ -433,6 +433,7 @@ nfscl_loadattrcache(struct vnode **vpp, 
                                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, 
                                        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;
                }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to