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.

Signed-off-by: Jason Gunthorpe <[email protected]>
---
 drivers/iommu/iommufd/io_pagetable.c | 43 +++++++++++++++++++++-------
 drivers/iommu/iommufd/io_pagetable.h |  4 ++-
 drivers/iommu/iommufd/pages.c        | 13 ++++-----
 3 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/iommufd/io_pagetable.c 
b/drivers/iommu/iommufd/io_pagetable.c
index 0bf6ca77888c0f..44a0a7c79388d8 100644
--- a/drivers/iommu/iommufd/io_pagetable.c
+++ b/drivers/iommu/iommufd/io_pagetable.c
@@ -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 {
diff --git a/drivers/iommu/iommufd/io_pagetable.h 
b/drivers/iommu/iommufd/io_pagetable.h
index 81c6093beee2a5..e033d44b0feb60 100644
--- a/drivers/iommu/iommufd/io_pagetable.h
+++ b/drivers/iommu/iommufd/io_pagetable.h
@@ -264,7 +264,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,
diff --git a/drivers/iommu/iommufd/pages.c b/drivers/iommu/iommufd/pages.c
index 935184dc68be32..410ddce4e99d8f 100644
--- a/drivers/iommu/iommufd/pages.c
+++ b/drivers/iommu/iommufd/pages.c
@@ -1412,22 +1412,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;
 }
-- 
2.43.0

Reply via email to