svn commit: r334203 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs

Andriy Gapon avg at FreeBSD.org
Fri May 25 07:29:54 UTC 2018


Author: avg
Date: Fri May 25 07:29:52 2018
New Revision: 334203
URL: https://svnweb.freebsd.org/changeset/base/334203

Log:
  fix zfs_getpages crash when called from sendfile, followup to r329363
  
  It turns out that sendfile_swapin() has an optimization where it may
  insert pointers to bogus_page into the page array that it passes to
  VOP_GETPAGES.  That happens to work with buffer cache, because it
  extensively uses bogus_page internally, so it has the necessary checks.
  However, ZFS did not expect bogus_page as VOP_GETPAGES(9) does not
  document such a (ab)use of bogus_page.
  
  So, this commit adds checks and handling of bogus_page.
  
  I expect that use of bogus_page with VOP_GETPAGES will get documented
  sooner rather than later.
  
  Reported by:	Andrew Reilly <areilly at bigpond.net.au>, delphij
  Tested by:	Andrew Reilly <areilly at bigpond.net.au>
  Requested by:	many
  MFC after:	1 week

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c	Fri May 25 06:26:07 2018	(r334202)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c	Fri May 25 07:29:52 2018	(r334203)
@@ -1732,17 +1732,21 @@ dmu_read_pages(objset_t *os, uint64_t object, vm_page_
 	for (mi = 0, di = 0; mi < count && di < numbufs; ) {
 		if (pgoff == 0) {
 			m = ma[mi];
-			vm_page_assert_xbusied(m);
-			ASSERT(m->valid == 0);
-			ASSERT(m->dirty == 0);
-			ASSERT(!pmap_page_is_mapped(m));
-			va = zfs_map_page(m, &sf);
+			if (m != bogus_page) {
+				vm_page_assert_xbusied(m);
+				ASSERT(m->valid == 0);
+				ASSERT(m->dirty == 0);
+				ASSERT(!pmap_page_is_mapped(m));
+				va = zfs_map_page(m, &sf);
+			}
 		}
 		if (bufoff == 0)
 			db = dbp[di];
 
-		ASSERT3U(IDX_TO_OFF(m->pindex) + pgoff, ==,
-		    db->db_offset + bufoff);
+		if (m != bogus_page) {
+			ASSERT3U(IDX_TO_OFF(m->pindex) + pgoff, ==,
+			    db->db_offset + bufoff);
+		}
 
 		/*
 		 * We do not need to clamp the copy size by the file
@@ -1750,13 +1754,16 @@ dmu_read_pages(objset_t *os, uint64_t object, vm_page_
 		 * end of file anyway.
 		 */
 		tocpy = MIN(db->db_size - bufoff, PAGESIZE - pgoff);
-		bcopy((char *)db->db_data + bufoff, va + pgoff, tocpy);
+		if (m != bogus_page)
+			bcopy((char *)db->db_data + bufoff, va + pgoff, tocpy);
 
 		pgoff += tocpy;
 		ASSERT(pgoff <= PAGESIZE);
 		if (pgoff == PAGESIZE) {
-			zfs_unmap_page(sf);
-			m->valid = VM_PAGE_BITS_ALL;
+			if (m != bogus_page) {
+				zfs_unmap_page(sf);
+				m->valid = VM_PAGE_BITS_ALL;
+			}
 			ASSERT(mi < count);
 			mi++;
 			pgoff = 0;
@@ -1801,6 +1808,7 @@ dmu_read_pages(objset_t *os, uint64_t object, vm_page_
 	}
 #endif
 	if (pgoff != 0) {
+		ASSERT(m != bogus_page);
 		bzero(va + pgoff, PAGESIZE - pgoff);
 		zfs_unmap_page(sf);
 		m->valid = VM_PAGE_BITS_ALL;


More information about the svn-src-all mailing list