Using a sg_set_folio() loop for every 4K results in a malformed scatterlist because sg_set_folio() has an issue with offsets > PAGE_SIZE and because scatterlist expects the creator to build a list which consolidates any physical contiguity.
sg_alloc_table_from_pages() creates a valid scatterlist directly from a struct page array, so go back to that.
Remove the offsets allocation and just store an array of tail pages as it did before the below commit. Everything wants that anyhow.
Fixes: 0c8b91ef5100 ("udmabuf: add back support for mapping hugetlb pages") Reported-by: Julian Orth ju.orth@gmail.com Closes: https://lore.kernel.org/all/20260308-scatterlist-v1-1-39c4566b0bba@gmail.com... Signed-off-by: Jason Gunthorpe jgg@nvidia.com --- drivers/dma-buf/udmabuf.c | 49 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 36 deletions(-)
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 94b8ecb892bb17..5d687860445137 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -26,10 +26,10 @@ MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is
struct udmabuf { pgoff_t pagecount; - struct folio **folios; + struct page **pages;
/** - * Unlike folios, pinned_folios is only used for unpin. + * Unlike pages, pinned_folios is only used for unpin. * So, nr_pinned is not the same to pagecount, the pinned_folios * only set each folio which already pinned when udmabuf_create. * Note that, since a folio may be pinned multiple times, each folio @@ -41,7 +41,6 @@ struct udmabuf {
struct sg_table *sg; struct miscdevice *device; - pgoff_t *offsets; };
static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) @@ -55,8 +54,7 @@ static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) if (pgoff >= ubuf->pagecount) return VM_FAULT_SIGBUS;
- pfn = folio_pfn(ubuf->folios[pgoff]); - pfn += ubuf->offsets[pgoff] >> PAGE_SHIFT; + pfn = page_to_pfn(ubuf->pages[pgoff]);
ret = vmf_insert_pfn(vma, vmf->address, pfn); if (ret & VM_FAULT_ERROR) @@ -73,8 +71,7 @@ static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) if (WARN_ON(pgoff >= ubuf->pagecount)) break;
- pfn = folio_pfn(ubuf->folios[pgoff]); - pfn += ubuf->offsets[pgoff] >> PAGE_SHIFT; + pfn = page_to_pfn(ubuf->pages[pgoff]);
/** * If the below vmf_insert_pfn() fails, we do not return an @@ -109,22 +106,11 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) static int vmap_udmabuf(struct dma_buf *buf, struct iosys_map *map) { struct udmabuf *ubuf = buf->priv; - struct page **pages; void *vaddr; - pgoff_t pg;
dma_resv_assert_held(buf->resv);
- pages = kvmalloc_objs(*pages, ubuf->pagecount); - if (!pages) - return -ENOMEM; - - for (pg = 0; pg < ubuf->pagecount; pg++) - pages[pg] = folio_page(ubuf->folios[pg], - ubuf->offsets[pg] >> PAGE_SHIFT); - - vaddr = vm_map_ram(pages, ubuf->pagecount, -1); - kvfree(pages); + vaddr = vm_map_ram(ubuf->pages, ubuf->pagecount, -1); if (!vaddr) return -EINVAL;
@@ -146,22 +132,18 @@ static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf, { struct udmabuf *ubuf = buf->priv; struct sg_table *sg; - struct scatterlist *sgl; - unsigned int i = 0; int ret;
sg = kzalloc_obj(*sg); if (!sg) return ERR_PTR(-ENOMEM);
- ret = sg_alloc_table(sg, ubuf->pagecount, GFP_KERNEL); + ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, 0, + ubuf->pagecount << PAGE_SHIFT, + GFP_KERNEL); if (ret < 0) goto err_alloc;
- for_each_sg(sg->sgl, sgl, ubuf->pagecount, i) - sg_set_folio(sgl, ubuf->folios[i], PAGE_SIZE, - ubuf->offsets[i]); - ret = dma_map_sgtable(dev, sg, direction, 0); if (ret < 0) goto err_map; @@ -207,12 +189,8 @@ static void unpin_all_folios(struct udmabuf *ubuf)
static __always_inline int init_udmabuf(struct udmabuf *ubuf, pgoff_t pgcnt) { - ubuf->folios = kvmalloc_objs(*ubuf->folios, pgcnt); - if (!ubuf->folios) - return -ENOMEM; - - ubuf->offsets = kvzalloc_objs(*ubuf->offsets, pgcnt); - if (!ubuf->offsets) + ubuf->pages = kvmalloc_objs(*ubuf->pages, pgcnt); + if (!ubuf->pages) return -ENOMEM;
ubuf->pinned_folios = kvmalloc_objs(*ubuf->pinned_folios, pgcnt); @@ -225,8 +203,7 @@ static __always_inline int init_udmabuf(struct udmabuf *ubuf, pgoff_t pgcnt) static __always_inline void deinit_udmabuf(struct udmabuf *ubuf) { unpin_all_folios(ubuf); - kvfree(ubuf->offsets); - kvfree(ubuf->folios); + kvfree(ubuf->pages); }
static void release_udmabuf(struct dma_buf *buf) @@ -344,8 +321,8 @@ static long udmabuf_pin_folios(struct udmabuf *ubuf, struct file *memfd, ubuf->pinned_folios[nr_pinned++] = folios[cur_folio];
for (; subpgoff < fsize; subpgoff += PAGE_SIZE) { - ubuf->folios[upgcnt] = folios[cur_folio]; - ubuf->offsets[upgcnt] = subpgoff; + ubuf->pages[upgcnt] = folio_page(folios[cur_folio], + subpgoff >> PAGE_SHIFT); ++upgcnt;
if (++cur_pgcnt >= pgcnt)
base-commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681
linaro-mm-sig@lists.linaro.org