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