Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 22 Sep 2015 18:16:52 +0000 (UTC)
From:      Alan Cox <alc@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r288122 - in head/sys: kern vm
Message-ID:  <201509221816.t8MIGqxV069276@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: alc
Date: Tue Sep 22 18:16:52 2015
New Revision: 288122
URL: https://svnweb.freebsd.org/changeset/base/288122

Log:
  Change vm_page_unwire() such that it (1) accepts PQ_NONE as the specified
  queue and (2) returns a Boolean indicating whether the page's wire count
  transitioned to zero.
  
  Exploit this change in vfs_vmio_release() to avoid pointlessly enqueueing
  a page that is about to be freed.
  
  (An earlier version of this change was developed by attilio@ and kmacy@.
  Any errors in this version are my own.)
  
  Reviewed by:	kib
  Sponsored by:	EMC / Isilon Storage Division

Modified:
  head/sys/kern/vfs_bio.c
  head/sys/vm/vm_page.c
  head/sys/vm/vm_page.h

Modified: head/sys/kern/vfs_bio.c
==============================================================================
--- head/sys/kern/vfs_bio.c	Tue Sep 22 17:34:51 2015	(r288121)
+++ head/sys/kern/vfs_bio.c	Tue Sep 22 18:16:52 2015	(r288122)
@@ -2076,6 +2076,7 @@ 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);
@@ -2088,23 +2089,28 @@ vfs_vmio_release(struct buf *bp)
 	for (i = 0; i < bp->b_npages; i++) {
 		m = bp->b_pages[i];
 		bp->b_pages[i] = NULL;
-		/*
-		 * In order to keep page LRU ordering consistent, put
-		 * everything on the inactive queue.
-		 */
 		vm_page_lock(m);
-		vm_page_unwire(m, PQ_INACTIVE);
-
-		/*
-		 * Might as well free the page if we can and it has
-		 * no valid data.  We also free the page if the
-		 * buffer was used for direct I/O
-		 */
-		if ((bp->b_flags & B_ASYNC) == 0 && !m->valid) {
-			if (m->wire_count == 0 && !vm_page_busied(m))
-				vm_page_free(m);
-		} else if (bp->b_flags & B_DIRECT)
-			vm_page_try_to_free(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)

Modified: head/sys/vm/vm_page.c
==============================================================================
--- head/sys/vm/vm_page.c	Tue Sep 22 17:34:51 2015	(r288121)
+++ head/sys/vm/vm_page.c	Tue Sep 22 18:16:52 2015	(r288122)
@@ -2476,42 +2476,46 @@ vm_page_wire(vm_page_t m)
 /*
  * vm_page_unwire:
  *
- * Release one wiring of the specified page, potentially enabling it to be
- * paged again.  If paging is enabled, then the value of the parameter
- * "queue" determines the queue to which the page is added.
- *
- * However, unless the page belongs to an object, it is not enqueued because
- * it cannot be paged out.
+ * Release one wiring of the specified page, potentially allowing it to be
+ * paged out.  Returns TRUE if the number of wirings transitions to zero and
+ * FALSE otherwise.
+ *
+ * Only managed pages belonging to an object can be paged out.  If the number
+ * of wirings transitions to zero and the page is eligible for page out, then
+ * the page is added to the specified paging queue (unless PQ_NONE is
+ * specified).
  *
  * If a page is fictitious, then its wire count must always be one.
  *
  * A managed page must be locked.
  */
-void
+boolean_t
 vm_page_unwire(vm_page_t m, uint8_t queue)
 {
 
-	KASSERT(queue < PQ_COUNT,
+	KASSERT(queue < PQ_COUNT || queue == PQ_NONE,
 	    ("vm_page_unwire: invalid queue %u request for page %p",
 	    queue, m));
 	if ((m->oflags & VPO_UNMANAGED) == 0)
-		vm_page_lock_assert(m, MA_OWNED);
+		vm_page_assert_locked(m);
 	if ((m->flags & PG_FICTITIOUS) != 0) {
 		KASSERT(m->wire_count == 1,
 	    ("vm_page_unwire: fictitious page %p's wire count isn't one", m));
-		return;
+		return (FALSE);
 	}
 	if (m->wire_count > 0) {
 		m->wire_count--;
 		if (m->wire_count == 0) {
 			atomic_subtract_int(&vm_cnt.v_wire_count, 1);
-			if ((m->oflags & VPO_UNMANAGED) != 0 ||
-			    m->object == NULL)
-				return;
-			if (queue == PQ_INACTIVE)
-				m->flags &= ~PG_WINATCFLS;
-			vm_page_enqueue(queue, m);
-		}
+			if ((m->oflags & VPO_UNMANAGED) == 0 &&
+			    m->object != NULL && queue != PQ_NONE) {
+				if (queue == PQ_INACTIVE)
+					m->flags &= ~PG_WINATCFLS;
+				vm_page_enqueue(queue, m);
+			}
+			return (TRUE);
+		} else
+			return (FALSE);
 	} else
 		panic("vm_page_unwire: page %p's wire count is zero", m);
 }

Modified: head/sys/vm/vm_page.h
==============================================================================
--- head/sys/vm/vm_page.h	Tue Sep 22 17:34:51 2015	(r288121)
+++ head/sys/vm/vm_page.h	Tue Sep 22 18:16:52 2015	(r288122)
@@ -480,7 +480,7 @@ vm_offset_t vm_page_startup(vm_offset_t 
 void vm_page_sunbusy(vm_page_t m);
 int vm_page_trysbusy(vm_page_t m);
 void vm_page_unhold_pages(vm_page_t *ma, int count);
-void vm_page_unwire (vm_page_t m, uint8_t queue);
+boolean_t vm_page_unwire(vm_page_t m, uint8_t queue);
 void vm_page_updatefake(vm_page_t m, vm_paddr_t paddr, vm_memattr_t memattr);
 void vm_page_wire (vm_page_t);
 void vm_page_xunbusy_hard(vm_page_t m);



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