diff --git a/module/os/linux/zfs/abd_os.c b/module/os/linux/zfs/abd_os.c index 18f2426fbbfc..9d55d614cb4d 100644 --- a/module/os/linux/zfs/abd_os.c +++ b/module/os/linux/zfs/abd_os.c @@ -911,11 +911,20 @@ abd_iter_map(struct abd_iter *aiter) aiter->iter_mapsize = aiter->iter_abd->abd_size - offset; paddr = ABD_LINEAR_BUF(aiter->iter_abd); } else { + struct page *page; + offset = aiter->iter_offset; aiter->iter_mapsize = MIN(aiter->iter_sg->length - offset, aiter->iter_abd->abd_size - aiter->iter_pos); - paddr = zfs_kmap_local(sg_page(aiter->iter_sg)); + page = sg_page(aiter->iter_sg); + if (PageHighMem(page)) { + page = nth_page(page, offset / PAGE_SIZE); + offset &= PAGE_SIZE - 1; + aiter->iter_mapsize = MIN(aiter->iter_mapsize, + PAGE_SIZE - offset); + } + paddr = zfs_kmap_local(page); } aiter->iter_mapaddr = (char *)paddr + offset; @@ -933,8 +942,15 @@ abd_iter_unmap(struct abd_iter *aiter) return; if (!abd_is_linear(aiter->iter_abd)) { + struct page *page; + size_t offset = aiter->iter_offset; + + page = sg_page(aiter->iter_sg); + if (PageHighMem(page)) + offset &= PAGE_SIZE - 1; + /* LINTED E_FUNC_SET_NOT_USED */ - zfs_kunmap_local(aiter->iter_mapaddr - aiter->iter_offset); + zfs_kunmap_local(aiter->iter_mapaddr - offset); } ASSERT3P(aiter->iter_mapaddr, !=, NULL); diff --git a/module/os/linux/zfs/zfs_uio.c b/module/os/linux/zfs/zfs_uio.c index d282f6d95ddf..8f9b161995f4 100644 --- a/module/os/linux/zfs/zfs_uio.c +++ b/module/os/linux/zfs/zfs_uio.c @@ -100,15 +100,17 @@ zfs_uiomove_bvec_impl(void *p, size_t n, zfs_uio_rw_t rw, zfs_uio_t *uio) while (n && uio->uio_resid) { void *paddr; - cnt = MIN(bv->bv_len - skip, n); + size_t offset = bv->bv_offset + skip; + cnt = MIN(PAGE_SIZE - (offset & ~PAGE_MASK), + MIN(bv->bv_len - skip, n)); - paddr = zfs_kmap_local(bv->bv_page); + paddr = zfs_kmap_local(bv->bv_page + (offset >> PAGE_SHIFT)); if (rw == UIO_READ) { /* Copy from buffer 'p' to the bvec data */ - memcpy(paddr + bv->bv_offset + skip, p, cnt); + memcpy(paddr + (offset & ~PAGE_MASK), p, cnt); } else { /* Copy from bvec data to buffer 'p' */ - memcpy(p, paddr + bv->bv_offset + skip, cnt); + memcpy(p, paddr + (offset & ~PAGE_MASK), cnt); } zfs_kunmap_local(paddr); diff --git a/module/zfs/abd.c b/module/zfs/abd.c index bf9b13c30509..120adc494c80 100644 --- a/module/zfs/abd.c +++ b/module/zfs/abd.c @@ -1111,13 +1111,6 @@ abd_raidz_gen_iterate(abd_t **cabds, abd_t *dabd, size_t off, func_raidz_gen(caddrs, daddr, len, dlen); - for (i = parity-1; i >= 0; i--) { - abd_iter_unmap(&caiters[i]); - c_cabds[i] = - abd_advance_abd_iter(cabds[i], c_cabds[i], - &caiters[i], len); - } - if (dsize > 0) { abd_iter_unmap(&daiter); c_dabd = @@ -1126,6 +1119,13 @@ abd_raidz_gen_iterate(abd_t **cabds, abd_t *dabd, size_t off, dsize -= dlen; } + for (i = parity-1; i >= 0; i--) { + abd_iter_unmap(&caiters[i]); + c_cabds[i] = + abd_advance_abd_iter(cabds[i], c_cabds[i], + &caiters[i], len); + } + csize -= len; } abd_exit_critical(flags);