Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 27 Sep 2015 05:16:07 +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: r288299 - head/sys/kern
Message-ID:  <201509270516.t8R5G7s2091316@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Sun Sep 27 05:16:06 2015
New Revision: 288299
URL: https://svnweb.freebsd.org/changeset/base/288299

Log:
   - Collapse vfs_vmio_truncate & vfs_vmio_release into a single function.
   - Allow vfs_vmio_invalidate() to free the pages, leaving us with a
     single loop and bufobj lock when B_NOCACHE/B_INVAL is used.
   - Eliminate the special B_ASYNC handling on free that has not been
     relevant for some time.
   - Remove the extraneous page busy from vfs_vmio_truncate().
  
  Reviewed by:	kib
  Tested by:	pho
  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	Sun Sep 27 04:55:43 2015	(r288298)
+++ head/sys/kern/vfs_bio.c	Sun Sep 27 05:16:06 2015	(r288299)
@@ -111,7 +111,6 @@ static void vfs_page_set_validclean(stru
 static void vfs_clean_pages_dirty_buf(struct buf *bp);
 static void vfs_setdirty_locked_object(struct buf *bp);
 static void vfs_vmio_invalidate(struct buf *bp);
-static void vfs_vmio_release(struct buf *bp);
 static void vfs_vmio_truncate(struct buf *bp, int npages);
 static void vfs_vmio_extend(struct buf *bp, int npages, int size);
 static int vfs_bio_clcheck(struct vnode *vp, int size,
@@ -1830,20 +1829,19 @@ brelse(struct buf *bp)
 			bdirtysub();
 		bp->b_flags &= ~(B_DELWRI | B_CACHE);
 		if ((bp->b_flags & B_VMIO) == 0) {
-			if (bp->b_bufsize)
-				allocbuf(bp, 0);
+			allocbuf(bp, 0);
 			if (bp->b_vp)
 				brelvp(bp);
 		}
 	}
 
 	/*
-	 * We must clear B_RELBUF if B_DELWRI is set.  If vfs_vmio_release() 
+	 * We must clear B_RELBUF if B_DELWRI is set.  If vfs_vmio_truncate() 
 	 * is called with B_DELWRI set, the underlying pages may wind up
 	 * getting freed causing a previous write (bdwrite()) to get 'lost'
 	 * because pages associated with a B_DELWRI bp are marked clean.
 	 * 
-	 * We still allow the B_INVAL case to call vfs_vmio_release(), even
+	 * We still allow the B_INVAL case to call vfs_vmio_truncate(), even
 	 * if B_DELWRI is set.
 	 */
 	if (bp->b_flags & B_DELWRI)
@@ -1870,14 +1868,13 @@ brelse(struct buf *bp)
 	    (bp->b_ioflags & BIO_ERROR && bp->b_iocmd == BIO_READ)) &&
 	    !(bp->b_vp->v_mount != NULL &&
 	    (bp->b_vp->v_mount->mnt_vfc->vfc_flags & VFCF_NETWORK) != 0 &&
-	    !vn_isdisk(bp->b_vp, NULL) && (bp->b_flags & B_DELWRI)))
+	    !vn_isdisk(bp->b_vp, NULL) && (bp->b_flags & B_DELWRI))) {
 		vfs_vmio_invalidate(bp);
+		allocbuf(bp, 0);
+	}
 
 	if ((bp->b_flags & (B_INVAL | B_RELBUF)) != 0) {
-		if (bp->b_flags & B_VMIO)
-			vfs_vmio_release(bp);
-		if (bp->b_bufsize != 0)
-			allocbuf(bp, 0);
+		allocbuf(bp, 0);
 		if (bp->b_vp != NULL)
 			brelvp(bp);
 	}
@@ -2059,8 +2056,41 @@ vfs_vmio_iodone(struct buf *bp)
 }
 
 /*
+ * Unwire a page held by a buf and place it on the appropriate vm queue.
+ */
+static void
+vfs_vmio_unwire(struct buf *bp, vm_page_t m)
+{
+	bool freed;
+
+	vm_page_lock(m);
+	if (vm_page_unwire(m, PQ_NONE)) {
+		/*
+		 * Determine if the page should be freed before adding
+		 * it to the inactive queue.
+		 */
+		if (m->valid == 0) {
+			freed = !vm_page_busied(m);
+			if (freed)
+				vm_page_free(m);
+		} else if ((bp->b_flags & B_DIRECT) != 0)
+			freed = vm_page_try_to_free(m);
+		else
+			freed = false;
+		if (!freed) {
+			/*
+			 * In order to maintain LRU page ordering, put
+			 * the page at the tail of the inactive queue.
+			 */
+			vm_page_deactivate(m);
+		}
+	}
+	vm_page_unlock(m);
+}
+
+/*
  * Perform page invalidation when a buffer is released.  The fully invalid
- * pages will be reclaimed later in vfs_vmio_release().
+ * pages will be reclaimed later in vfs_vmio_truncate().
  */
 static void
 vfs_vmio_invalidate(struct buf *bp)
@@ -2069,6 +2099,11 @@ vfs_vmio_invalidate(struct buf *bp)
 	vm_page_t m;
 	int i, resid, poffset, presid;
 
+	if (buf_mapped(bp)) {
+		BUF_CHECK_MAPPED(bp);
+		pmap_qremove(trunc_page((vm_offset_t)bp->b_data), bp->b_npages);
+	} else
+		BUF_CHECK_UNMAPPED(bp);
 	/*
 	 * Get the base offset and length of the buffer.  Note that 
 	 * in the VMIO case if the buffer block size is not
@@ -2089,6 +2124,7 @@ vfs_vmio_invalidate(struct buf *bp)
 		m = bp->b_pages[i];
 		if (m == bogus_page)
 			panic("vfs_vmio_invalidate: Unexpected bogus page.");
+		bp->b_pages[i] = NULL;
 
 		presid = resid > (PAGE_SIZE - poffset) ?
 		    (PAGE_SIZE - poffset) : resid;
@@ -2101,63 +2137,12 @@ vfs_vmio_invalidate(struct buf *bp)
 		}
 		if (pmap_page_wired_mappings(m) == 0)
 			vm_page_set_invalid(m, poffset, presid);
+		vfs_vmio_unwire(bp, m);
 		resid -= presid;
 		poffset = 0;
 	}
 	VM_OBJECT_WUNLOCK(obj);
-}
-
-/* Give pages used by the bp back to the VM system (where possible) */
-static void
-vfs_vmio_release(struct buf *bp)
-{
-	vm_object_t obj;
-	vm_page_t m;
-	int i;
-	bool freed;
-
-	if (buf_mapped(bp)) {
-		BUF_CHECK_MAPPED(bp);
-		pmap_qremove(trunc_page((vm_offset_t)bp->b_data), bp->b_npages);
-	} else
-		BUF_CHECK_UNMAPPED(bp);
-	obj = bp->b_bufobj->bo_object;
-	if (obj != NULL)
-		VM_OBJECT_WLOCK(obj);
-	for (i = 0; i < bp->b_npages; i++) {
-		m = bp->b_pages[i];
-		bp->b_pages[i] = NULL;
-		vm_page_lock(m);
-		if (vm_page_unwire(m, PQ_NONE)) {
-			/*
-			 * Determine if the page should be freed before adding
-			 * it to the inactive queue.
-			 */
-			if ((bp->b_flags & B_ASYNC) == 0 && m->valid == 0) {
-				freed = !vm_page_busied(m);
-				if (freed)
-					vm_page_free(m);
-			} else if ((bp->b_flags & B_DIRECT) != 0)
-				freed = vm_page_try_to_free(m);
-			else
-				freed = false;
-			if (!freed) {
-				/*
-				 * In order to maintain LRU page ordering, put
-				 * the page at the tail of the inactive queue.
-				 */
-				vm_page_deactivate(m);
-			}
-		}
-		vm_page_unlock(m);
-	}
-	if (obj != NULL)
-		VM_OBJECT_WUNLOCK(obj);
-	
-	if (bp->b_bufsize)
-		bufspaceadjust(bp, 0);
 	bp->b_npages = 0;
-	bp->b_flags &= ~B_VMIO;
 }
 
 /*
@@ -2166,6 +2151,7 @@ vfs_vmio_release(struct buf *bp)
 static void
 vfs_vmio_truncate(struct buf *bp, int desiredpages)
 {
+	vm_object_t obj;
 	vm_page_t m;
 	int i;
 
@@ -2178,22 +2164,17 @@ vfs_vmio_truncate(struct buf *bp, int de
 		    (desiredpages << PAGE_SHIFT), bp->b_npages - desiredpages);
 	} else
 		BUF_CHECK_UNMAPPED(bp);
-	VM_OBJECT_WLOCK(bp->b_bufobj->bo_object);
+	obj = bp->b_bufobj->bo_object;
+	if (obj != NULL)
+		VM_OBJECT_WLOCK(obj);
 	for (i = desiredpages; i < bp->b_npages; i++) {
-		/*
-		 * The page is not freed here -- it is the responsibility of 
-		 * vnode_pager_setsize.
-		 */
 		m = bp->b_pages[i];
 		KASSERT(m != bogus_page, ("allocbuf: bogus page found"));
-		while (vm_page_sleep_if_busy(m, "biodep"))
-			continue;
 		bp->b_pages[i] = NULL;
-		vm_page_lock(m);
-		vm_page_unwire(m, PQ_INACTIVE);
-		vm_page_unlock(m);
+		vfs_vmio_unwire(bp, m);
 	}
-	VM_OBJECT_WUNLOCK(bp->b_bufobj->bo_object);
+	if (obj != NULL)
+		VM_OBJECT_WUNLOCK(obj);
 	bp->b_npages = desiredpages;
 }
 
@@ -2478,11 +2459,12 @@ getnewbuf_reuse_bp(struct buf *bp, int q
 	KASSERT((bp->b_flags & B_DELWRI) == 0,
 	    ("delwri buffer %p found in queue %d", bp, qindex));
 
+	/*
+	 * When recycling a clean buffer we have to truncate it and
+	 * release the vnode.
+	 */
 	if (qindex == QUEUE_CLEAN) {
-		if (bp->b_flags & B_VMIO) {
-			bp->b_flags &= ~B_ASYNC;
-			vfs_vmio_release(bp);
-		}
+		allocbuf(bp, 0);
 		if (bp->b_vp != NULL)
 			brelvp(bp);
 	}
@@ -2491,7 +2473,6 @@ getnewbuf_reuse_bp(struct buf *bp, int q
 	 * Get the rest of the buffer freed up.  b_kva* is still valid
 	 * after this operation.
 	 */
-
 	if (bp->b_rcred != NOCRED) {
 		crfree(bp->b_rcred);
 		bp->b_rcred = NOCRED;
@@ -2508,9 +2489,8 @@ getnewbuf_reuse_bp(struct buf *bp, int q
 	    bp, bp->b_vp, qindex));
 	KASSERT((bp->b_xflags & (BX_VNCLEAN|BX_VNDIRTY)) == 0,
 	    ("bp: %p still on a buffer list. xflags %X", bp, bp->b_xflags));
-
-	if (bp->b_bufsize)
-		allocbuf(bp, 0);
+	KASSERT(bp->b_npages == 0,
+	    ("bp: %p still has %d vm pages\n", bp, bp->b_npages));
 
 	bp->b_flags = 0;
 	bp->b_ioflags = 0;
@@ -3426,8 +3406,7 @@ loop:
 		 * cleared.  If the size has not changed, B_CACHE remains
 		 * unchanged from its previous state.
 		 */
-		if (bp->b_bcount != size)
-			allocbuf(bp, size);
+		allocbuf(bp, size);
 
 		KASSERT(bp->b_offset != NOOFFSET, 
 		    ("getblk: no buffer offset"));
@@ -3678,6 +3657,9 @@ allocbuf(struct buf *bp, int size)
 
 	BUF_ASSERT_HELD(bp);
 
+	if (bp->b_bcount == size)
+		return (1);
+
 	if (bp->b_kvasize != 0 && bp->b_kvasize < size)
 		panic("allocbuf: buffer too small");
 
@@ -3716,7 +3698,7 @@ allocbuf(struct buf *bp, int size)
 		bufspaceadjust(bp, newbsize);
 	}
 	bp->b_bcount = size;		/* requested buffer size. */
-	return 1;
+	return (1);
 }
 
 extern int inflight_transient_maps;



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