in case of blocksize mismatch dmu_assign_arcbuf() releases passed
abuf internally, including the pages. osd_bufs_put() can't detect
this and may call __free_page() on inappropriate pages (which can
be allocated to someone else already).
Change-Id: I454e56ee3de3d201a14e6ba7b4beabaad42d82ae
Signed-off-by: Alex Zhuravlev <alexey.zhuravlev@intel.com>
Reviewed-on: https://review.whamcloud.com/27950
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Jinshan Xiong <jinshan.xiong@intel.com>
Reviewed-by: Nathaniel Clark <nathaniel.l.clark@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
dmu_buf_rele((void *)ptr, osd_0copy_tag);
atomic_dec(&osd->od_zerocopy_pin);
} else if (lnb[i].lnb_data != NULL) {
dmu_buf_rele((void *)ptr, osd_0copy_tag);
atomic_dec(&osd->od_zerocopy_pin);
} else if (lnb[i].lnb_data != NULL) {
+ int j, apages, abufsz;
+ abufsz = arc_buf_size(lnb[i].lnb_data);
+ apages = abufsz / PAGE_SIZE;
+ /* these references to pages must be invalidated
+ * to prevent access in osd_bufs_put() */
+ for (j = 0; j < apages; j++)
+ lnb[i + j].lnb_page = NULL;
dmu_return_arcbuf(lnb[i].lnb_data);
atomic_dec(&osd->od_zerocopy_loan);
}
dmu_return_arcbuf(lnb[i].lnb_data);
atomic_dec(&osd->od_zerocopy_loan);
}
+ if (new_size < lnb[i].lnb_file_offset + lnb[i].lnb_len)
+ new_size = lnb[i].lnb_file_offset + lnb[i].lnb_len;
+ if (lnb[i].lnb_page == NULL)
+ continue;
+
if (lnb[i].lnb_page->mapping == (void *)obj) {
osd_dmu_write(osd, obj->oo_dn, lnb[i].lnb_file_offset,
lnb[i].lnb_len, kmap(lnb[i].lnb_page),
oh->ot_tx);
kunmap(lnb[i].lnb_page);
if (lnb[i].lnb_page->mapping == (void *)obj) {
osd_dmu_write(osd, obj->oo_dn, lnb[i].lnb_file_offset,
lnb[i].lnb_len, kmap(lnb[i].lnb_page),
oh->ot_tx);
kunmap(lnb[i].lnb_page);
+ iosize += lnb[i].lnb_len;
} else if (lnb[i].lnb_data) {
} else if (lnb[i].lnb_data) {
LASSERT(((unsigned long)lnb[i].lnb_data & 1) == 0);
/* buffer loaned for zerocopy, try to use it.
* notice that dmu_assign_arcbuf() is smart
* enough to recognize changed blocksize
* in this case it fallbacks to dmu_write() */
LASSERT(((unsigned long)lnb[i].lnb_data & 1) == 0);
/* buffer loaned for zerocopy, try to use it.
* notice that dmu_assign_arcbuf() is smart
* enough to recognize changed blocksize
* in this case it fallbacks to dmu_write() */
+ abufsz = arc_buf_size(lnb[i].lnb_data);
+ LASSERT(abufsz & PAGE_MASK);
+ apages = abufsz / PAGE_SIZE;
+ LASSERT(i + apages <= npages);
+ /* these references to pages must be invalidated
+ * to prevent access in osd_bufs_put() */
+ for (j = 0; j < apages; j++)
+ lnb[i + j].lnb_page = NULL;
dmu_assign_arcbuf(&obj->oo_dn->dn_bonus->db,
lnb[i].lnb_file_offset,
lnb[i].lnb_data, oh->ot_tx);
dmu_assign_arcbuf(&obj->oo_dn->dn_bonus->db,
lnb[i].lnb_file_offset,
lnb[i].lnb_data, oh->ot_tx);
* will be releasing it - bad! */
lnb[i].lnb_data = NULL;
atomic_dec(&osd->od_zerocopy_loan);
* will be releasing it - bad! */
lnb[i].lnb_data = NULL;
atomic_dec(&osd->od_zerocopy_loan);
- if (new_size < lnb[i].lnb_file_offset + lnb[i].lnb_len)
- new_size = lnb[i].lnb_file_offset + lnb[i].lnb_len;
- iosize += lnb[i].lnb_len;
}
up_read(&obj->oo_guard);
}
up_read(&obj->oo_guard);