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 <arei...@bigpond.net.au>, delphij
  Tested by:    Andrew Reilly <arei...@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;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to