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@bigpond.net.au>, delphij Tested by: Andrew Reilly <areilly@bigpond.net.au> Requested by: many MFC after: 1 week
This commit is contained in:
parent
a8d82e59ae
commit
80919a9e8a
@ -1732,17 +1732,21 @@ dmu_read_pages(objset_t *os, uint64_t object, vm_page_t *ma, int count,
|
||||
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_t *ma, int count,
|
||||
* 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_t *ma, int count,
|
||||
}
|
||||
#endif
|
||||
if (pgoff != 0) {
|
||||
ASSERT(m != bogus_page);
|
||||
bzero(va + pgoff, PAGESIZE - pgoff);
|
||||
zfs_unmap_page(sf);
|
||||
m->valid = VM_PAGE_BITS_ALL;
|
||||
|
Loading…
Reference in New Issue
Block a user