Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Jul 2015 20:24:10 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r285981 - head/sys/kern
Message-ID:  <201507282024.t6SKOAgg015176@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Tue Jul 28 20:24:09 2015
New Revision: 285981
URL: https://svnweb.freebsd.org/changeset/base/285981

Log:
   - Eliminate the EMPTYKVA queue.  It served as a cache of KVA allocations
     attached to bufs to avoid the overhead of the vm.  This purposes is now
     better served by vmem.  Freeing the kva immediately when a buf is
     destroyed leads to lower fragmentation and a much simpler scan algorithm.
  
  Reviewed by:	kib
  Sponsored by:	EMC / Isilon Storage Division

Modified:
  head/sys/kern/vfs_bio.c

Modified: head/sys/kern/vfs_bio.c
==============================================================================
--- head/sys/kern/vfs_bio.c	Tue Jul 28 19:59:22 2015	(r285980)
+++ head/sys/kern/vfs_bio.c	Tue Jul 28 20:24:09 2015	(r285981)
@@ -309,13 +309,12 @@ static int bdirtywait;
 /*
  * Definitions for the buffer free lists.
  */
-#define BUFFER_QUEUES	5	/* number of free buffer queues */
+#define BUFFER_QUEUES	4	/* number of free buffer queues */
 
 #define QUEUE_NONE	0	/* on no queue */
 #define QUEUE_CLEAN	1	/* non-B_DELWRI buffers */
 #define QUEUE_DIRTY	2	/* B_DELWRI buffers */
-#define QUEUE_EMPTYKVA	3	/* empty buffer headers w/KVA assignment */
-#define QUEUE_EMPTY	4	/* empty buffer headers */
+#define QUEUE_EMPTY	3	/* empty buffer headers */
 #define QUEUE_SENTINEL	1024	/* not an queue index, but mark for sentinel */
 
 /* Queues for free buffers with various properties */
@@ -1862,10 +1861,8 @@ brelse(struct buf *bp)
 		bp->b_xflags &= ~(BX_BKGRDWRITE | BX_ALTDATA);
 		if (bp->b_vflags & BV_BKGRDINPROG)
 			panic("losing buffer 1");
-		if (bp->b_kvasize)
-			qindex = QUEUE_EMPTYKVA;
-		else
-			qindex = QUEUE_EMPTY;
+		bufkvafree(bp);
+		qindex = QUEUE_EMPTY;
 		bp->b_flags |= B_AGE;
 	/* buffers with junk contents */
 	} else if (bp->b_flags & (B_INVAL | B_NOCACHE | B_RELBUF) ||
@@ -2251,8 +2248,6 @@ getnewbuf_reuse_bp(struct buf *bp, int q
 	LIST_INIT(&bp->b_dep);
 }
 
-static int flushingbufs;
-
 static struct buf *
 getnewbuf_scan(int maxsize, int defrag, int unmapped, int metadata)
 {
@@ -2261,64 +2256,25 @@ getnewbuf_scan(int maxsize, int defrag, 
 
 	KASSERT(!unmapped || !defrag, ("both unmapped and defrag"));
 
-	pass = 1;
+	pass = 0;
 restart:
-	atomic_add_int(&getnewbufrestarts, 1);
+	if (pass != 0)
+		atomic_add_int(&getnewbufrestarts, 1);
 
-	/*
-	 * Setup for scan.  If we do not have enough free buffers,
-	 * we setup a degenerate case that immediately fails.  Note
-	 * that if we are specially marked process, we are allowed to
-	 * dip into our reserves.
-	 *
-	 * The scanning sequence is nominally: EMPTY->EMPTYKVA->CLEAN
-	 * for the allocation of the mapped buffer.  For unmapped, the
-	 * easiest is to start with EMPTY outright.
-	 *
-	 * We start with EMPTYKVA.  If the list is empty we backup to EMPTY.
-	 * However, there are a number of cases (defragging, reusing, ...)
-	 * where we cannot backup.
-	 */
 	nbp = NULL;
 	mtx_lock(&bqclean);
-	if (!defrag && unmapped) {
-		nqindex = QUEUE_EMPTY;
-		nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTY]);
-	}
-	if (nbp == NULL) {
-		nqindex = QUEUE_EMPTYKVA;
-		nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTYKVA]);
-	}
-
 	/*
-	 * If no EMPTYKVA buffers and we are either defragging or
-	 * reusing, locate a CLEAN buffer to free or reuse.  If
-	 * bufspace useage is low skip this step so we can allocate a
-	 * new buffer.
+	 * If we're not defragging or low on bufspace attempt to make a new
+	 * buf from a header.
 	 */
-	if (nbp == NULL && (defrag || bufspace >= lobufspace)) {
-		nqindex = QUEUE_CLEAN;
-		nbp = TAILQ_FIRST(&bufqueues[QUEUE_CLEAN]);
-	}
-
-	/*
-	 * If we could not find or were not allowed to reuse a CLEAN
-	 * buffer, check to see if it is ok to use an EMPTY buffer.
-	 * We can only use an EMPTY buffer if allocating its KVA would
-	 * not otherwise run us out of buffer space.  No KVA is needed
-	 * for the unmapped allocation.
-	 */
-	if (nbp == NULL && defrag == 0 && (bufspace + maxsize < hibufspace ||
-	    metadata)) {
+	if (defrag == 0 && bufspace + maxsize < hibufspace) {
 		nqindex = QUEUE_EMPTY;
-		nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTY]);
+		nbp = TAILQ_FIRST(&bufqueues[nqindex]);
 	}
-
 	/*
-	 * All available buffers might be clean, retry ignoring the
-	 * lobufspace as the last resort.
+	 * All available buffers might be clean or we need to start recycling.
 	 */
-	if (nbp == NULL && !TAILQ_EMPTY(&bufqueues[QUEUE_CLEAN])) {
+	if (nbp == NULL) {
 		nqindex = QUEUE_CLEAN;
 		nbp = TAILQ_FIRST(&bufqueues[QUEUE_CLEAN]);
 	}
@@ -2332,28 +2288,21 @@ restart:
 
 		/*
 		 * Calculate next bp (we can only use it if we do not
-		 * block or do other fancy things).
+		 * release the bqlock)
 		 */
 		if ((nbp = TAILQ_NEXT(bp, b_freelist)) == NULL) {
 			switch (qindex) {
 			case QUEUE_EMPTY:
-				nqindex = QUEUE_EMPTYKVA;
-				nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTYKVA]);
-				if (nbp != NULL)
-					break;
-				/* FALLTHROUGH */
-			case QUEUE_EMPTYKVA:
 				nqindex = QUEUE_CLEAN;
-				nbp = TAILQ_FIRST(&bufqueues[QUEUE_CLEAN]);
+				nbp = TAILQ_FIRST(&bufqueues[nqindex]);
 				if (nbp != NULL)
 					break;
 				/* FALLTHROUGH */
 			case QUEUE_CLEAN:
-				if (metadata && pass == 1) {
-					pass = 2;
+				if (metadata && pass == 0) {
+					pass = 1;
 					nqindex = QUEUE_EMPTY;
-					nbp = TAILQ_FIRST(
-					    &bufqueues[QUEUE_EMPTY]);
+					nbp = TAILQ_FIRST(&bufqueues[nqindex]);
 				}
 				/*
 				 * nbp is NULL. 
@@ -2399,11 +2348,11 @@ restart:
 
 		bremfreel(bp);
 		mtx_unlock(&bqclean);
+
 		/*
 		 * NOTE:  nbp is now entirely invalid.  We can only restart
 		 * the scan from this point on.
 		 */
-
 		getnewbuf_reuse_bp(bp, qindex);
 		mtx_assert(&bqclean, MA_NOTOWNED);
 
@@ -2412,7 +2361,6 @@ restart:
 		 */
 		if (defrag) {
 			bp->b_flags |= B_INVAL;
-			bufkvafree(bp);
 			brelse(bp);
 			defrag = 0;
 			goto restart;
@@ -2424,7 +2372,6 @@ restart:
 		 */
 		if (qindex == QUEUE_CLEAN && BUF_LOCKWAITERS(bp)) {
 			bp->b_flags |= B_INVAL;
-			bufkvafree(bp);
 			brelse(bp);
 			goto restart;
 		}
@@ -2437,16 +2384,11 @@ restart:
 		 * KVM space.  This occurs in rare situations when multiple
 		 * processes are blocked in getnewbuf() or allocbuf().
 		 */
-		if (bufspace >= hibufspace)
-			flushingbufs = 1;
-		if (flushingbufs && bp->b_kvasize != 0) {
+		if (bufspace >= hibufspace && bp->b_kvasize != 0) {
 			bp->b_flags |= B_INVAL;
-			bufkvafree(bp);
 			brelse(bp);
 			goto restart;
 		}
-		if (bufspace < lobufspace)
-			flushingbufs = 0;
 		break;
 	}
 	return (bp);
@@ -2492,7 +2434,6 @@ getnewbuf(struct vnode *vp, int slpflag,
 	 * async I/O rather then sync I/O.
 	 */
 	atomic_add_int(&getnewbufcalls, 1);
-	atomic_subtract_int(&getnewbufrestarts, 1);
 restart:
 	bp = getnewbuf_scan(maxsize, defrag, (gbflags & (GB_UNMAPPED |
 	    GB_KVAALLOC)) == GB_UNMAPPED, metadata);



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