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

Reply via email to