On 9/29/26 07:48, Karl Mehltretter wrote:
> get_sg_table() merges physically contiguous pages without accounting
> for the mapping device's maximum segment size. This affects both
> importer mappings and the udmabuf misc device mapping used for CPU
> access.
>
> With DMA_API_DEBUG enabled, DMA_BUF_IOCTL_SYNC on a 64 MiB udmabuf
> reports:
>
> DMA-API: misc udmabuf: mapping sg segment longer than device claims to
> support [len=65884160] [max=65536]
>
> Use sg_alloc_table_from_pages_segment() with the mapping device's
> maximum segment size. Return -EINVAL if the limit is smaller than
> PAGE_SIZE because the page-based allocator cannot honor it.
>
> Before commit 5bf888673e0d ("udmabuf: Do not create malformed
> scatterlists"), each entry covered one page.
>
> Fixes: 5bf888673e0d ("udmabuf: Do not create malformed scatterlists")
> Reviewed-by: Jason Gunthorpe <[email protected]>
Reviewed-by: Christian König <[email protected]>
> Assisted-by: LLM
> Signed-off-by: Karl Mehltretter <[email protected]>
> ---
>
> Notes:
> Changes in v2:
> - Return -EINVAL when the maximum segment size reported by the device is
> smaller than PAGE_SIZE instead of clamping it. (Christian)
> - Add Jason Gunthorpe's Reviewed-by tag.
>
> Tested on v7.3-rc4-70-gfe2ec83746e5 in QEMU (x86_64, TCG) with
> DMA_API_DEBUG (all_errors=1) and DMABUF_DEBUG, A/B against the same
> base:
>
> before after
> DMA_BUF_IOCTL_SYNC, 64 MiB udmabuf 1 report 0
> vivid import, 4 MiB udmabuf 2 reports 0
> vivid import, 2 MiB hugetlb udmabuf 2 reports 0
> frames captured 5/5 5/5
>
> vb2-dma-contig rejected the non-contiguous import in both runs.
>
> For v2, a focused importer advertising PAGE_SIZE / 2 returned
> -EINVAL under KASAN and DMA_API_DEBUG. No warning, BUG, or DMA-API
> report was emitted.
>
> drivers/dma-buf/udmabuf.c | 13 ++++++++++---
> 1 file changed, 10 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
> index df6dd00462423..018937435356e 100644
> --- a/drivers/dma-buf/udmabuf.c
> +++ b/drivers/dma-buf/udmabuf.c
> @@ -133,15 +133,22 @@ static struct sg_table *get_sg_table(struct device
> *dev, struct dma_buf *buf,
> {
> struct udmabuf *ubuf = buf->priv;
> struct sg_table *sg;
> + unsigned int max_segment;
> int ret;
>
> + max_segment = dma_get_max_seg_size(dev);
> + /* The SG allocator requires a segment limit of at least PAGE_SIZE. */
> + if (max_segment < PAGE_SIZE)
> + return ERR_PTR(-EINVAL);
> +
> sg = kzalloc_obj(*sg);
> if (!sg)
> return ERR_PTR(-ENOMEM);
>
> - ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, 0,
> - ubuf->pagecount << PAGE_SHIFT,
> - GFP_KERNEL);
> + ret = sg_alloc_table_from_pages_segment(sg, ubuf->pages,
> ubuf->pagecount,
> + 0, ubuf->pagecount <<
> PAGE_SHIFT,
> + max_segment,
> + GFP_KERNEL);
> if (ret < 0)
> goto err_alloc;
>
>
> base-commit: fe2ec83746e501645709761605c2464a44fd2929