svn commit: r193303 - in head/sys: kern vm

Alan Cox alc at FreeBSD.org
Tue Jun 2 08:02:28 UTC 2009


Author: alc
Date: Tue Jun  2 08:02:27 2009
New Revision: 193303
URL: http://svn.freebsd.org/changeset/base/193303

Log:
  Correct a boundary case error in the management of a page's dirty bits by
  shm_dotruncate() and vnode_pager_setsize().  Specifically, if the length of
  a shared memory object or a file is truncated such that the length modulo
  the page size is between 1 and 511, then all of the page's dirty bits were
  cleared.  Now, a dirty bit is cleared only if the corresponding block is
  truncated in its entirety.

Modified:
  head/sys/kern/uipc_shm.c
  head/sys/vm/vnode_pager.c

Modified: head/sys/kern/uipc_shm.c
==============================================================================
--- head/sys/kern/uipc_shm.c	Tue Jun  2 07:35:51 2009	(r193302)
+++ head/sys/kern/uipc_shm.c	Tue Jun  2 08:02:27 2009	(r193303)
@@ -274,7 +274,7 @@ shm_dotruncate(struct shmfd *shmfd, off_
 		/*
 		 * If the last page is partially mapped, then zero out
 		 * the garbage at the end of the page.  See comments
-		 * in vnode_page_setsize() for more details.
+		 * in vnode_pager_setsize() for more details.
 		 *
 		 * XXXJHB: This handles in memory pages, but what about
 		 * a page swapped out to disk?
@@ -286,10 +286,23 @@ shm_dotruncate(struct shmfd *shmfd, off_
 			int size = PAGE_SIZE - base;
 
 			pmap_zero_page_area(m, base, size);
+
+			/*
+			 * Update the valid bits to reflect the blocks that
+			 * have been zeroed.  Some of these valid bits may
+			 * have already been set.
+			 */
+			vm_page_set_valid(m, base, size);
+
+			/*
+			 * Round "base" to the next block boundary so that the
+			 * dirty bit for a partially zeroed block is not
+			 * cleared.
+			 */
+			base = roundup2(base, DEV_BSIZE);
+
 			vm_page_lock_queues();
-			vm_page_set_validclean(m, base, size);
-			if (m->dirty != 0)
-				m->dirty = VM_PAGE_BITS_ALL;
+			vm_page_clear_dirty(m, base, PAGE_SIZE - base);
 			vm_page_unlock_queues();
 		} else if ((length & PAGE_MASK) &&
 		    __predict_false(object->cache != NULL)) {

Modified: head/sys/vm/vnode_pager.c
==============================================================================
--- head/sys/vm/vnode_pager.c	Tue Jun  2 07:35:51 2009	(r193302)
+++ head/sys/vm/vnode_pager.c	Tue Jun  2 08:02:27 2009	(r193303)
@@ -403,22 +403,28 @@ vnode_pager_setsize(vp, nsize)
 			pmap_zero_page_area(m, base, size);
 
 			/*
-			 * Clear out partial-page dirty bits.  This
-			 * has the side effect of setting the valid
-			 * bits, but that is ok.  There are a bunch
-			 * of places in the VM system where we expected
-			 * m->dirty == VM_PAGE_BITS_ALL.  The file EOF
-			 * case is one of them.  If the page is still
-			 * partially dirty, make it fully dirty.
+			 * Update the valid bits to reflect the blocks that
+			 * have been zeroed.  Some of these valid bits may
+			 * have already been set.
+			 */
+			vm_page_set_valid(m, base, size);
+
+			/*
+			 * Round "base" to the next block boundary so that the
+			 * dirty bit for a partially zeroed block is not
+			 * cleared.
+			 */
+			base = roundup2(base, DEV_BSIZE);
+
+			/*
+			 * Clear out partial-page dirty bits.
 			 *
 			 * note that we do not clear out the valid
 			 * bits.  This would prevent bogus_page
 			 * replacement from working properly.
 			 */
 			vm_page_lock_queues();
-			vm_page_set_validclean(m, base, size);
-			if (m->dirty != 0)
-				m->dirty = VM_PAGE_BITS_ALL;
+			vm_page_clear_dirty(m, base, PAGE_SIZE - base);
 			vm_page_unlock_queues();
 		} else if ((nsize & PAGE_MASK) &&
 		    __predict_false(object->cache != NULL)) {


More information about the svn-src-head mailing list