Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 17 Sep 2019 18:41:40 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r352457 - head/sys/fs/nfsclient
Message-ID:  <201909171841.x8HIfeUj054292@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Tue Sep 17 18:41:39 2019
New Revision: 352457
URL: https://svnweb.freebsd.org/changeset/base/352457

Log:
  Further refine r352393, only call vnode_pager_setsize() outside the
  node lock when shrinking.
  
  This is similar to r252528, applied to the above commit.
  
  Apparently there is a race which makes necessary at least to keep the
  n_size and pager size consistent when extending.  Current suspect is
  that iod threads perform vnode_pager_setsize() without taking the
  vnode lock, which corrupts the file content.
  
  Reported and tested by:	Masachika ISHIZUKA <ish@amail.plala.or.jp>
  Discussed with:	rmacklem (related issues)
  Sponsored by:	The FreeBSD Foundation
  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 Sep 17 18:36:29 2019	(r352456)
+++ head/sys/fs/nfsclient/nfs_clport.c	Tue Sep 17 18:41:39 2019	(r352457)
@@ -414,12 +414,12 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvatt
 	struct nfsnode *np;
 	struct nfsmount *nmp;
 	struct timespec mtime_save;
+	vm_object_t object;
 	u_quad_t nsize;
-	int setnsize, error, force_fid_err;
+	int error, force_fid_err;
+	bool setnsize;
 
 	error = 0;
-	setnsize = 0;
-	nsize = 0;
 
 	/*
 	 * If v_type == VNON it is a new node, so fill in the v_type,
@@ -511,8 +511,7 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvatt
 				 * zero np->n_attrstamp to indicate that
 				 * the attributes are stale.
 				 */
-				nsize = vap->va_size = np->n_size;
-				setnsize = 1;
+				vap->va_size = np->n_size;
 				np->n_attrstamp = 0;
 				KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
 			} else if (np->n_flag & NMODIFIED) {
@@ -526,22 +525,9 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvatt
 					np->n_size = vap->va_size;
 					np->n_flag |= NSIZECHANGED;
 				}
-				nsize = np->n_size;
-				setnsize = 1;
-			} 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 {
-				nsize = np->n_size = vap->va_size;
+				np->n_size = vap->va_size;
 				np->n_flag |= NSIZECHANGED;
-				setnsize = 1;
 			}
 		} else {
 			np->n_size = vap->va_size;
@@ -579,6 +565,23 @@ out:
 	if (np->n_attrstamp != 0)
 		KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, vap, error);
 #endif
+	nsize = vap->va_size;
+	object = vp->v_object;
+	setnsize = false;
+	if (object != NULL) {
+		if (OFF_TO_IDX(nsize + PAGE_MASK) < object->size) {
+			/*
+			 * When shrinking the size, the call to
+			 * vnode_pager_setsize() cannot be done with
+			 * the mutex held, because we might need to
+			 * wait for a busy page.  Delay it until after
+			 * the node is unlocked.
+			 */
+			setnsize = true;
+		} else {
+			vnode_pager_setsize(vp, nsize);
+		}
+	}
 	NFSUNLOCKNODE(np);
 	if (setnsize)
 		vnode_pager_setsize(vp, nsize);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201909171841.x8HIfeUj054292>