svn commit: r356435 - head/sys/kern

Mateusz Guzik mjg at FreeBSD.org
Tue Jan 7 04:34:04 UTC 2020


Author: mjg
Date: Tue Jan  7 04:34:03 2020
New Revision: 356435
URL: https://svnweb.freebsd.org/changeset/base/356435

Log:
  vfs: prevent numvnodes and freevnodes re-reads when appropriate
  
  Otherwise in code like this:
  if (numvnodes > desiredvnodes)
  	vnlru_free_locked(numvnodes - desiredvnodes, NULL);
  
  numvnodes can drop below desiredvnodes prior to the call and if the
  compiler generated another read the subtraction would get a negative
  value.

Modified:
  head/sys/kern/vfs_subr.c

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c	Tue Jan  7 04:33:14 2020	(r356434)
+++ head/sys/kern/vfs_subr.c	Tue Jan  7 04:34:03 2020	(r356435)
@@ -1211,16 +1211,19 @@ vnlru_free(int count, struct vfsops *mnt_op)
 static int
 vspace(void)
 {
+	u_long rnumvnodes, rfreevnodes;
 	int space;
 
 	gapvnodes = imax(desiredvnodes - wantfreevnodes, 100);
 	vhiwat = gapvnodes / 11; /* 9% -- just under the 10% in vlrureclaim() */
 	vlowat = vhiwat / 2;
-	if (numvnodes > desiredvnodes)
+	rnumvnodes = atomic_load_long(&numvnodes);
+	rfreevnodes = atomic_load_long(&freevnodes);
+	if (rnumvnodes > desiredvnodes)
 		return (0);
-	space = desiredvnodes - numvnodes;
+	space = desiredvnodes - rnumvnodes;
 	if (freevnodes > wantfreevnodes)
-		space += freevnodes - wantfreevnodes;
+		space += rfreevnodes - wantfreevnodes;
 	return (space);
 }
 
@@ -1292,6 +1295,7 @@ static int vnlruproc_sig;
 static void
 vnlru_proc(void)
 {
+	u_long rnumvnodes, rfreevnodes;
 	struct mount *mp, *nmp;
 	unsigned long onumvnodes;
 	int done, force, trigger, usevnodes, vsp;
@@ -1304,13 +1308,14 @@ vnlru_proc(void)
 	for (;;) {
 		kproc_suspend_check(vnlruproc);
 		mtx_lock(&vnode_free_list_mtx);
+		rnumvnodes = atomic_load_long(&numvnodes);
 		/*
 		 * If numvnodes is too large (due to desiredvnodes being
 		 * adjusted using its sysctl, or emergency growth), first
 		 * try to reduce it by discarding from the free list.
 		 */
-		if (numvnodes > desiredvnodes)
-			vnlru_free_locked(numvnodes - desiredvnodes, NULL);
+		if (rnumvnodes > desiredvnodes)
+			vnlru_free_locked(rnumvnodes - desiredvnodes, NULL);
 		/*
 		 * Sleep if the vnode cache is in a good state.  This is
 		 * when it is not over-full and has space for about a 4%
@@ -1332,7 +1337,10 @@ vnlru_proc(void)
 		}
 		mtx_unlock(&vnode_free_list_mtx);
 		done = 0;
-		onumvnodes = numvnodes;
+		rnumvnodes = atomic_load_long(&numvnodes);
+		rfreevnodes = atomic_load_long(&freevnodes);
+
+		onumvnodes = rnumvnodes;
 		/*
 		 * Calculate parameters for recycling.  These are the same
 		 * throughout the loop to give some semblance of fairness.
@@ -1340,10 +1348,10 @@ vnlru_proc(void)
 		 * of resident pages.  We aren't trying to free memory; we
 		 * are trying to recycle or at least free vnodes.
 		 */
-		if (numvnodes <= desiredvnodes)
-			usevnodes = numvnodes - freevnodes;
+		if (rnumvnodes <= desiredvnodes)
+			usevnodes = rnumvnodes - rfreevnodes;
 		else
-			usevnodes = numvnodes;
+			usevnodes = rnumvnodes;
 		if (usevnodes <= 0)
 			usevnodes = 1;
 		/*
@@ -1516,14 +1524,17 @@ getnewvnode_wait(int suspended)
 void
 getnewvnode_reserve(u_int count)
 {
+	u_long rnumvnodes, rfreevnodes;
 	struct thread *td;
 
 	/* Pre-adjust like the pre-adjust in getnewvnode(), with any count. */
 	/* XXX no longer so quick, but this part is not racy. */
 	mtx_lock(&vnode_free_list_mtx);
-	if (numvnodes + count > desiredvnodes && freevnodes > wantfreevnodes)
-		vnlru_free_locked(ulmin(numvnodes + count - desiredvnodes,
-		    freevnodes - wantfreevnodes), NULL);
+	rnumvnodes = atomic_load_long(&numvnodes);
+	rfreevnodes = atomic_load_long(&freevnodes);
+	if (rnumvnodes + count > desiredvnodes && rfreevnodes > wantfreevnodes)
+		vnlru_free_locked(ulmin(rnumvnodes + count - desiredvnodes,
+		    rfreevnodes - wantfreevnodes), NULL);
 	mtx_unlock(&vnode_free_list_mtx);
 
 	td = curthread;


More information about the svn-src-all mailing list