Re: [PATCH V4 04/10] iommufd: Add an ioctl IOMMU_IOAS_GET_PA to query PA from IOVA

Jacob Pan
2026-05-04T22:30:46Z

Hi Alex,

On Thu, 16 Apr 2026 13:32:57 -0600
Alex Williamson <alex@shazbot.org> wrote:

> From: Alex Williamson <alex@shazbot.org>
> To: Jacob Pan <jacob.pan@linux.microsoft.com>
> Cc: linux-kernel@vger.kernel.org, "iommu@lists.linux.dev"
> <iommu@lists.linux.dev>, Jason Gunthorpe <jgg@nvidia.com>, Joerg
> Roedel <joro@8bytes.org>, Mostafa Saleh <smostafa@google.com>, David
> Matlack <dmatlack@google.com>, Robin Murphy <robin.murphy@arm.com>,
> Nicolin Chen <nicolinc@nvidia.com>, "Tian, Kevin"
> <kevin.tian@intel.com>, Yi Liu <yi.l.liu@intel.com>,
> skhawaja@google.com, pasha.tatashin@soleen.com, Will Deacon
> <will@kernel.org>, Baolu Lu <baolu.lu@linux.intel.com>,
> alex@shazbot.org Subject: Re: [PATCH V4 04/10] iommufd: Add an ioctl
> IOMMU_IOAS_GET_PA to query PA from IOVA Date: Thu, 16 Apr 2026
> 13:32:57 -0600 X-Mailer: Claws Mail 4.3.1 (GTK 3.24.51;
> x86_64-pc-linux-gnu)
>
> On Tue, 14 Apr 2026 14:14:06 -0700
> Jacob Pan <jacob.pan@linux.microsoft.com> wrote:
>
> > To support no-IOMMU mode where userspace drivers perform unsafe DMA
> > using physical addresses, introduce a new API to retrieve the
> > physical address of a user-allocated DMA buffer that has been
> > mapped to an IOVA via IOAS. The mapping is backed by mock I/O page
> > tables maintained by generic IOMMUPT framework.
> >
> > Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> > Signed-off-by: Jacob Pan <jacob.pan@linux.microsoft.com>
> > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> > ---
> > v4:
> > - Fix unaligned IOVA length (Sashiko)
> > v2:
> > - Scan the contiguous physical-address span beyond the first
> > page and return its length. ---
> > drivers/iommu/iommufd/io_pagetable.c | 60
> > +++++++++++++++++++++++++ drivers/iommu/iommufd/ioas.c |
> > 25 +++++++++++ drivers/iommu/iommufd/iommufd_private.h | 3 ++
> > drivers/iommu/iommufd/main.c | 3 ++
> > include/uapi/linux/iommufd.h | 25 +++++++++++
> > 5 files changed, 116 insertions(+)
> >
> > diff --git a/drivers/iommu/iommufd/io_pagetable.c
> > b/drivers/iommu/iommufd/io_pagetable.c index
> > ee003bb2f647..04336a8e12f5 100644 ---
> > a/drivers/iommu/iommufd/io_pagetable.c +++
> > b/drivers/iommu/iommufd/io_pagetable.c @@ -849,6 +849,66 @@ int
> > iopt_unmap_iova(struct io_pagetable *iopt, unsigned long iova,
> > return iopt_unmap_iova_range(iopt, iova, iova_last, unmapped); }
> >
> > +int iopt_get_phys(struct io_pagetable *iopt, unsigned long iova,
> > u64 *paddr,
> > + u64 *length)
> > +{
> > + struct iopt_area *area;
> > + u64 tmp_length = 0;
> > + u64 tmp_paddr = 0;
> > + int rc = 0;
> > +
> > + if (!IS_ENABLED(CONFIG_VFIO_NOIOMMU))
> > + return -EOPNOTSUPP;
> > +
> > + down_read(&iopt->iova_rwsem);
> > + area = iopt_area_iter_first(iopt, iova, iova);
> > + if (!area || !area->pages) {
> > + rc = -ENOENT;
> > + goto unlock_exit;
> > + }
> > +
> > + if (!area->storage_domain ||
> > + area->storage_domain->owner != &iommufd_noiommu_ops) {
> > + rc = -EOPNOTSUPP;
> > + goto unlock_exit;
> > + }
> > +
> > + *paddr = iommu_iova_to_phys(area->storage_domain, iova);
> > + if (!*paddr) {
> > + rc = -EINVAL;
> > + goto unlock_exit;
> > + }
> > +
> > + tmp_length = PAGE_SIZE - offset_in_page(iova);
> > + tmp_paddr = *paddr;
> > + /*
> > + * Scan the domain for the contiguous physical address
> > length so that
> > + * userspace search can be optimized for fewer ioctls.
> > + */
> > + while (iova < iopt_area_last_iova(area)) {
> > + unsigned long next_iova;
> > + u64 next_paddr;
> > +
> > + if (check_add_overflow(iova, PAGE_SIZE,
> > &next_iova))
> > + break;
> > +
> > + next_paddr =
> > iommu_iova_to_phys(area->storage_domain, next_iova); +
> > + if (!next_paddr || next_paddr != tmp_paddr +
> > PAGE_SIZE)
> > + break;
> > +
> > + iova = next_iova;
> > + tmp_paddr += PAGE_SIZE;
> > + tmp_length += PAGE_SIZE;
> > + }
> > + *length = tmp_length;
>
> If next_iova exceeds iopt_area_last_iova(area) AND exists in
> storage_domain AND happens to be physically contiguous, tmp_length is
> advanced and the return length exceeds the mapping. Otherwise this
> also always does an iommu_iova_to_phys() one iteration beyond the area
> last iova. Thanks,
>
you are right, let me add a check.
@@ -892,6 +892,9 @@ int iopt_get_phys(struct io_pagetable *iopt, unsigned long iova, u64 *paddr,
if (check_add_overflow(iova, PAGE_SIZE, &next_iova))
break;

+ if (next_iova > iopt_area_last_iova(area))
+ break;
+
next_paddr = iommu_iova_to_phys(area->storage_domain,
next_iova);