]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommufd: Accept a DMABUF through IOMMU_IOAS_MAP_FILE
authorJason Gunthorpe <jgg@nvidia.com>
Fri, 21 Nov 2025 15:51:05 +0000 (11:51 -0400)
committerJason Gunthorpe <jgg@nvidia.com>
Tue, 25 Nov 2025 15:30:16 +0000 (11:30 -0400)
Finally call iopt_alloc_dmabuf_pages() if the user passed in a DMABUF
through IOMMU_IOAS_MAP_FILE. This makes the feature visible to userspace.

Link: https://patch.msgid.link/r/8-v2-b2c110338e3f+5c2-iommufd_dmabuf_jgg@nvidia.com
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Shuai Xue <xueshuai@linux.alibaba.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/iommu/iommufd/io_pagetable.c
drivers/iommu/iommufd/io_pagetable.h
drivers/iommu/iommufd/pages.c

index 0bf6ca77888c0f6bea3ae32aeeb22c8e739a1a2f..44a0a7c79388d808f3ae5aaa2b951af23e2d9aa1 100644 (file)
@@ -8,6 +8,7 @@
  * The datastructure uses the iopt_pages to optimize the storage of the PFNs
  * between the domains and xarray.
  */
+#include <linux/dma-buf.h>
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/file.h>
@@ -484,19 +485,41 @@ int iopt_map_file_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt,
                        unsigned int flags)
 {
        struct iopt_pages *pages;
-       struct file *file;
+       struct dma_buf *dmabuf;
+       unsigned long start_byte;
+       unsigned long last;
 
-       file = fget(fd);
-       if (!file)
-               return -EBADF;
+       if (!length)
+               return -EINVAL;
+       if (check_add_overflow(start, length - 1, &last))
+               return -EOVERFLOW;
+
+       start_byte = start - ALIGN_DOWN(start, PAGE_SIZE);
+       dmabuf = dma_buf_get(fd);
+       if (!IS_ERR(dmabuf)) {
+               pages = iopt_alloc_dmabuf_pages(ictx, dmabuf, start_byte, start,
+                                               length,
+                                               iommu_prot & IOMMU_WRITE);
+               if (IS_ERR(pages)) {
+                       dma_buf_put(dmabuf);
+                       return PTR_ERR(pages);
+               }
+       } else {
+               struct file *file;
+
+               file = fget(fd);
+               if (!file)
+                       return -EBADF;
+
+               pages = iopt_alloc_file_pages(file, start_byte, start, length,
+                                             iommu_prot & IOMMU_WRITE);
+               fput(file);
+               if (IS_ERR(pages))
+                       return PTR_ERR(pages);
+       }
 
-       pages = iopt_alloc_file_pages(file, start, length,
-                                     iommu_prot & IOMMU_WRITE);
-       fput(file);
-       if (IS_ERR(pages))
-               return PTR_ERR(pages);
        return iopt_map_common(ictx, iopt, pages, iova, length,
-                              start - pages->start, iommu_prot, flags);
+                              start_byte, iommu_prot, flags);
 }
 
 struct iova_bitmap_fn_arg {
index 8f8d583e0243761c726eee36de0db218855961af..14cd052fd3204e94684eebe230b97ec72d384ac3 100644 (file)
@@ -265,7 +265,9 @@ static inline bool iopt_dmabuf_revoked(struct iopt_pages *pages)
 
 struct iopt_pages *iopt_alloc_user_pages(void __user *uptr,
                                         unsigned long length, bool writable);
-struct iopt_pages *iopt_alloc_file_pages(struct file *file, unsigned long start,
+struct iopt_pages *iopt_alloc_file_pages(struct file *file,
+                                        unsigned long start_byte,
+                                        unsigned long start,
                                         unsigned long length, bool writable);
 struct iopt_pages *iopt_alloc_dmabuf_pages(struct iommufd_ctx *ictx,
                                           struct dma_buf *dmabuf,
index a2574eabb93df10e6686a2b2e632310be33113ee..c73456833d04d6fa5bcff8713265e8019c49b390 100644 (file)
@@ -1413,22 +1413,19 @@ struct iopt_pages *iopt_alloc_user_pages(void __user *uptr,
        return pages;
 }
 
-struct iopt_pages *iopt_alloc_file_pages(struct file *file, unsigned long start,
+struct iopt_pages *iopt_alloc_file_pages(struct file *file,
+                                        unsigned long start_byte,
+                                        unsigned long start,
                                         unsigned long length, bool writable)
 
 {
        struct iopt_pages *pages;
-       unsigned long start_down = ALIGN_DOWN(start, PAGE_SIZE);
-       unsigned long end;
-
-       if (length && check_add_overflow(start, length - 1, &end))
-               return ERR_PTR(-EOVERFLOW);
 
-       pages = iopt_alloc_pages(start - start_down, length, writable);
+       pages = iopt_alloc_pages(start_byte, length, writable);
        if (IS_ERR(pages))
                return pages;
        pages->file = get_file(file);
-       pages->start = start_down;
+       pages->start = start - start_byte;
        pages->type = IOPT_ADDRESS_FILE;
        return pages;
 }