On 10/5/26 11:55, Fred Griffoul wrote: > From: Fred Griffoul <[email protected]> > > iommufd and KVM write physical addresses into their own page tables. > To do so, they must ask the exporter which frames back an offset of a > dma-buf, whether that memory is RAM or MMIO, and whether it may be > written.
Well filling page tables by the importer is an absolutely clear NO-GO for the DMA-buf design, we have gotten down that path already and it took us years to remove this functionality again. The problem you are facing here is that dma_buf_mmap() doesn't work because you don't have a VMA. I can understand the reasoning that you don't want to have a VMA, but I don't think that this is a valid justification to add complexity to DMA-buf and especially bring an approach back which we have already deprecated. A possible solution might be Jasons patch set to directly negotiate exposing PCI BAR regions as DMA-buf, but that certainly needs more discussion. But the approach outlined here is an absolutely clear NAK from my side. Regards, Christian. > > Add a get_phys() operation. The importer passes an offset and a maximum > length. The exporter reports one run: the frames that start at the > offset, are backed and physically contiguous, and share one attribute > word. The run never exceeds the length. The exporter may end it early, > so importers must not assume that it is the longest possible run. > > get_phys() returns -ENOENT when the byte at the offset is not backed, > and -ENODEV when the buffer is revoked. The caller holds the > reservation, and either pins the attachment or handles revocation. A > reported frame stays valid until an invalidation that covers it > returns. > > The attribute word holds the memory type and a READONLY flag. Zero > means writable RAM. Importers refuse unknown types, reserved bits and > unknown flags, so attributes added later fail safely. Two flag bits are > reserved: one for holes and one for confidential memory. > > Convert vfio-pci, the iommufd selftest exporter and the KVM sample. > iommufd behaves as before: it maps a buffer only when one writable run > covers all of it. > > Signed-off-by: Fred Griffoul <[email protected]> > --- > drivers/dma-buf/dma-buf.c | 47 +++++++++++ > drivers/iommu/iommufd/iommufd_private.h | 8 -- > drivers/iommu/iommufd/iommufd_test.h | 16 ++++ > drivers/iommu/iommufd/pages.c | 74 ++++------------- > drivers/iommu/iommufd/selftest.c | 106 ++++++++++++++++++++---- > drivers/vfio/pci/vfio_pci_dmabuf.c | 58 ++++++------- > include/linux/dma-buf.h | 54 ++++++++++++ > include/linux/vfio_pci_core.h | 3 - > samples/kvm/gmem_provider.c | 39 ++++----- > 9 files changed, 267 insertions(+), 138 deletions(-) > > diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c > index d504c636dc29..66b85d53ed22 100644 > --- a/drivers/dma-buf/dma-buf.c > +++ b/drivers/dma-buf/dma-buf.c > @@ -1389,6 +1389,53 @@ void dma_buf_invalidate_mappings(struct dma_buf > *dmabuf) > } > EXPORT_SYMBOL_NS_GPL(dma_buf_invalidate_mappings, "DMA_BUF"); > > +/** > + * dma_buf_get_phys - describe the run that starts at an offset > + * @attach: attachment to query > + * @offset: first buffer byte to describe > + * @len: maximum number of bytes to describe > + * @phys: physical address and length of the run > + * @attr: DMA_BUF_PHYS_ATTR_* word of the run > + * > + * A run is the longest stretch of backed bytes starting at @offset whose > + * frames are physically contiguous and share one attribute word. On success > + * *@phys starts at the byte at @offset and covers at most @len bytes; it may > + * be shorter than the run. > + * > + * The dma-buf reservation must be held. The attachment must be pinned or > have > + * revocable importer operations. A frame remains valid until a covering > + * invalidation callback returns; the exporter must invalidate a changed > range > + * before reusing its old frames. > + * > + * Returns: > + * > + * 0 on success, -ENOENT if the byte at @offset is not backed, -ENODEV if the > + * buffer is revoked, -EOPNOTSUPP if the exporter cannot describe itself this > + * way, or another negative error code. > + */ > +int dma_buf_get_phys(struct dma_buf_attachment *attach, u64 offset, u64 len, > + struct phys_vec *phys, u32 *attr) > +{ > + u64 end; > + int ret; > + > + if (WARN_ON_ONCE(!attach || !attach->dmabuf || !phys || !attr)) > + return -EINVAL; > + if (!len || check_add_overflow(offset, len, &end) || > + end > attach->dmabuf->size) > + return -EINVAL; > + > + dma_resv_assert_held(attach->dmabuf->resv); > + if (!attach->dmabuf->ops->get_phys) > + return -EOPNOTSUPP; > + > + ret = attach->dmabuf->ops->get_phys(attach, offset, len, phys, attr); > + if (!ret && WARN_ON_ONCE(!phys->len || phys->len > len)) > + return -EIO; > + return ret; > +} > +EXPORT_SYMBOL_NS_GPL(dma_buf_get_phys, "DMA_BUF"); > + > /** > * DOC: cpu access > * > diff --git a/drivers/iommu/iommufd/iommufd_private.h > b/drivers/iommu/iommufd/iommufd_private.h > index 43fbc5bed8de..5cded585c227 100644 > --- a/drivers/iommu/iommufd/iommufd_private.h > +++ b/drivers/iommu/iommufd/iommufd_private.h > @@ -716,8 +716,6 @@ bool iommufd_should_fail(void); > int __init iommufd_test_init(void); > void iommufd_test_exit(void); > bool iommufd_selftest_is_mock_dev(struct device *dev); > -int iommufd_test_dma_buf_iommufd_map(struct dma_buf_attachment *attachment, > - struct phys_vec *phys); > #else > static inline void iommufd_test_syz_conv_iova_id(struct iommufd_ucmd *ucmd, > unsigned int ioas_id, > @@ -739,11 +737,5 @@ static inline bool iommufd_selftest_is_mock_dev(struct > device *dev) > { > return false; > } > -static inline int > -iommufd_test_dma_buf_iommufd_map(struct dma_buf_attachment *attachment, > - struct phys_vec *phys) > -{ > - return -EOPNOTSUPP; > -} > #endif > #endif > diff --git a/drivers/iommu/iommufd/iommufd_test.h > b/drivers/iommu/iommufd/iommufd_test.h > index 52b78cbcc920..28fd9c43edc4 100644 > --- a/drivers/iommu/iommufd/iommufd_test.h > +++ b/drivers/iommu/iommufd/iommufd_test.h > @@ -31,6 +31,8 @@ enum { > IOMMU_TEST_OP_PASID_CHECK_HWPT, > IOMMU_TEST_OP_DMABUF_GET, > IOMMU_TEST_OP_DMABUF_REVOKE, > + IOMMU_TEST_OP_MD_CHECK_MAPPED, > + IOMMU_TEST_OP_MD_IOVA_TO_PHYS, > }; > > enum { > @@ -193,6 +195,20 @@ struct iommu_test_cmd { > __s32 dmabuf_fd; > __u32 revoked; > } dmabuf_revoke; > + struct { > + /* > + * 1: every page in [iova, iova+length) must be > mapped; > + * 0: none of them may be. Mixed is an error. > + */ > + __u32 mapped; > + __u32 __reserved; > + __aligned_u64 iova; > + __aligned_u64 length; > + } check_mapped; > + struct { > + __aligned_u64 iova; > + __aligned_u64 out_phys; /* 0 if unmapped */ > + } iova_to_phys; > }; > __u32 last; > }; > diff --git a/drivers/iommu/iommufd/pages.c b/drivers/iommu/iommufd/pages.c > index f9b2ae6d7e96..196d1bb330c2 100644 > --- a/drivers/iommu/iommufd/pages.c > +++ b/drivers/iommu/iommufd/pages.c > @@ -1463,68 +1463,12 @@ static const struct dma_buf_attach_ops > iopt_dmabuf_attach_revoke_ops = { > .invalidate_mappings = iopt_revoke_notify, > }; > > -/* > - * iommufd and vfio have a circular dependency. Future work for a phys > - * based private interconnect will remove this. > - */ > -/* > - * Look up the exporter's phys accessor for iommufd's private-interconnect > - * path. Also fills *is_cpu_ram: true if the exporter's memory is normal > - * cache-coherent RAM (needs BATCH_CPU_MEMORY / IOMMU_CACHE), false for MMIO > - * (needs BATCH_MMIO / IOMMU_MMIO). This will be replaced by a formal > - * exporter op that returns phys + memory type together. > - */ > -static int > -sym_vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment, > - struct phys_vec *phys, bool *is_cpu_ram) > -{ > - typeof(&vfio_pci_dma_buf_iommufd_map) fn; > - int rc; > - > - rc = iommufd_test_dma_buf_iommufd_map(attachment, phys); > - if (rc != -EOPNOTSUPP) { > - *is_cpu_ram = false; /* test hook mimics VFIO MMIO */ > - return rc; > - } > - > - /* > - * Prototype: try the sample gmem provider's dma-buf exporter. This > - * mirrors the vfio-pci private-interconnect hook, and (like it) is > - * meant to be replaced by a formal negotiated exporter op returning > - * phys + memory type. The provider serves RAM, so mark it CPU_RAM. > - */ > - { > - extern int gmem_provider_dma_buf_iommufd_map( > - struct dma_buf_attachment *, struct phys_vec *); > - typeof(&gmem_provider_dma_buf_iommufd_map) gfn; > - > - gfn = symbol_get(gmem_provider_dma_buf_iommufd_map); > - if (gfn) { > - rc = gfn(attachment, phys); > - symbol_put(gmem_provider_dma_buf_iommufd_map); > - if (rc != -EOPNOTSUPP) { > - *is_cpu_ram = true; > - return rc; > - } > - } > - } > - > - if (!IS_ENABLED(CONFIG_VFIO_PCI_DMABUF)) > - return -EOPNOTSUPP; > - > - fn = symbol_get(vfio_pci_dma_buf_iommufd_map); > - if (!fn) > - return -EOPNOTSUPP; > - rc = fn(attachment, phys); > - symbol_put(vfio_pci_dma_buf_iommufd_map); > - *is_cpu_ram = false; /* VFIO PCI dma-buf carries BAR (MMIO) memory > */ > - return rc; > -} > - > static int iopt_map_dmabuf(struct iommufd_ctx *ictx, struct iopt_pages > *pages, > struct dma_buf *dmabuf) > { > struct dma_buf_attachment *attach; > + struct phys_vec pv; > + u32 attr; > int rc; > > attach = dma_buf_dynamic_attach(dmabuf, iommufd_global_device(), > @@ -1546,10 +1490,20 @@ static int iopt_map_dmabuf(struct iommufd_ctx *ictx, > struct iopt_pages *pages, > if (rc) > goto err_detach; > > - rc = sym_vfio_pci_dma_buf_iommufd_map(attach, &pages->dmabuf.phys, > - &pages->dmabuf.is_cpu_ram); > + /* One backed, writable run covering the buffer: refuse the rest. */ > + rc = dma_buf_get_phys(attach, 0, dmabuf->size, &pv, &attr); > + if (rc == -ENOENT) > + rc = -EOPNOTSUPP; > if (rc) > goto err_unpin; > + if (pv.len != dmabuf->size || !dma_buf_phys_attr_known(attr) || > + (attr & DMA_BUF_PHYS_ATTR_FLAGS_MASK)) { > + rc = -EOPNOTSUPP; > + goto err_unpin; > + } > + pages->dmabuf.phys = pv; > + pages->dmabuf.is_cpu_ram = > + dma_buf_phys_attr_type(attr) == DMA_BUF_PHYS_ATTR_RAM; > > dma_resv_unlock(dmabuf->resv); > > diff --git a/drivers/iommu/iommufd/selftest.c > b/drivers/iommu/iommufd/selftest.c > index af07c642a526..0899272d1e66 100644 > --- a/drivers/iommu/iommufd/selftest.c > +++ b/drivers/iommu/iommufd/selftest.c > @@ -1962,32 +1962,31 @@ static void iommufd_test_dma_buf_release(struct > dma_buf *dmabuf) > kfree(priv); > } > > -static const struct dma_buf_ops iommufd_test_dmabuf_ops = { > - .attach = iommufd_test_dma_buf_attach, > - .detach = iommufd_test_dma_buf_detach, > - .map_dma_buf = iommufd_test_dma_buf_map, > - .release = iommufd_test_dma_buf_release, > - .unmap_dma_buf = iommufd_test_dma_buf_unmap, > -}; > - > -int iommufd_test_dma_buf_iommufd_map(struct dma_buf_attachment *attachment, > - struct phys_vec *phys) > +static int iommufd_test_dma_buf_get_phys(struct dma_buf_attachment > *attachment, > + u64 offset, u64 len, > + struct phys_vec *phys, u32 *attr) > { > struct iommufd_test_dma_buf *priv = attachment->dmabuf->priv; > > dma_resv_assert_held(attachment->dmabuf->resv); > - > - if (attachment->dmabuf->ops != &iommufd_test_dmabuf_ops) > - return -EOPNOTSUPP; > - > if (priv->revoked) > return -ENODEV; > > - phys->paddr = virt_to_phys(priv->memory); > - phys->len = priv->length; > + phys->paddr = virt_to_phys(priv->memory) + offset; > + phys->len = len; > + *attr = DMA_BUF_PHYS_ATTR_MMIO; > return 0; > } > > +static const struct dma_buf_ops iommufd_test_dmabuf_ops = { > + .attach = iommufd_test_dma_buf_attach, > + .detach = iommufd_test_dma_buf_detach, > + .map_dma_buf = iommufd_test_dma_buf_map, > + .release = iommufd_test_dma_buf_release, > + .unmap_dma_buf = iommufd_test_dma_buf_unmap, > + .get_phys = iommufd_test_dma_buf_get_phys, > +}; > + > static int iommufd_test_dmabuf_get(struct iommufd_ucmd *ucmd, > unsigned int open_flags, > size_t len) > @@ -2031,6 +2030,73 @@ static int iommufd_test_dmabuf_get(struct iommufd_ucmd > *ucmd, > return rc; > } > > +/* > + * Report the physical address the mock domain resolves @iova to, or 0 if > + * it is unmapped. Lets a test check that two IOVAs share one frame (a > + * scratch substitution) without knowing the frame in advance. > + */ > +static int iommufd_test_md_iova_to_phys(struct iommufd_ucmd *ucmd, > + unsigned int mockpt_id, > + unsigned long iova) > +{ > + struct iommu_test_cmd *cmd = ucmd->cmd; > + struct iommufd_hw_pagetable *hwpt; > + struct mock_iommu_domain *mock; > + unsigned int page_size; > + int rc; > + > + hwpt = get_md_pagetable(ucmd, mockpt_id, &mock); > + if (IS_ERR(hwpt)) > + return PTR_ERR(hwpt); > + > + page_size = 1 << __ffs(mock->domain.pgsize_bitmap); > + if (iova % page_size) { > + rc = -EINVAL; > + goto out_put; > + } > + cmd->iova_to_phys.out_phys = > + mock->domain.ops->iova_to_phys(&mock->domain, iova); > + rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); > +out_put: > + iommufd_put_object(ucmd->ictx, &hwpt->obj); > + return rc; > +} > + > +static int iommufd_test_md_check_mapped(struct iommufd_ucmd *ucmd, > + unsigned int mockpt_id, > + unsigned long iova, size_t length, > + bool mapped) > +{ > + struct iommufd_hw_pagetable *hwpt; > + struct mock_iommu_domain *mock; > + unsigned int page_size; > + int rc = 0; > + > + hwpt = get_md_pagetable(ucmd, mockpt_id, &mock); > + if (IS_ERR(hwpt)) > + return PTR_ERR(hwpt); > + > + page_size = 1 << __ffs(mock->domain.pgsize_bitmap); > + if (iova % page_size || length % page_size || !length) { > + rc = -EINVAL; > + goto out_put; > + } > + > + for (; length; length -= page_size, iova += page_size) { > + bool is_mapped = > + mock->domain.ops->iova_to_phys(&mock->domain, iova) > != 0; > + > + if (is_mapped != mapped) { > + rc = -ENOENT; > + goto out_put; > + } > + } > + > +out_put: > + iommufd_put_object(ucmd->ictx, &hwpt->obj); > + return rc; > +} > + > static int iommufd_test_dmabuf_revoke(struct iommufd_ucmd *ucmd, int fd, > bool revoked) > { > @@ -2143,6 +2209,14 @@ int iommufd_test(struct iommufd_ucmd *ucmd) > return iommufd_test_dmabuf_revoke(ucmd, > > cmd->dmabuf_revoke.dmabuf_fd, > cmd->dmabuf_revoke.revoked); > + case IOMMU_TEST_OP_MD_CHECK_MAPPED: > + return iommufd_test_md_check_mapped(ucmd, cmd->id, > + cmd->check_mapped.iova, > + cmd->check_mapped.length, > + cmd->check_mapped.mapped); > + case IOMMU_TEST_OP_MD_IOVA_TO_PHYS: > + return iommufd_test_md_iova_to_phys(ucmd, cmd->id, > + cmd->iova_to_phys.iova); > default: > return -EOPNOTSUPP; > } > diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c > b/drivers/vfio/pci/vfio_pci_dmabuf.c > index c16f460c01d6..381c3d338e8c 100644 > --- a/drivers/vfio/pci/vfio_pci_dmabuf.c > +++ b/drivers/vfio/pci/vfio_pci_dmabuf.c > @@ -99,46 +99,46 @@ static void vfio_pci_dma_buf_release(struct dma_buf > *dmabuf) > kfree(priv); > } > > -static const struct dma_buf_ops vfio_pci_dmabuf_ops = { > - .attach = vfio_pci_dma_buf_attach, > - .map_dma_buf = vfio_pci_dma_buf_map, > - .unmap_dma_buf = vfio_pci_dma_buf_unmap, > - .release = vfio_pci_dma_buf_release, > -}; > - > /* > - * This is a temporary "private interconnect" between VFIO DMABUF and > iommufd. > - * It allows the two co-operating drivers to exchange the physical address of > - * the BAR. This is to be replaced with a formal DMABUF system for negotiated > - * interconnect types. > + * Report the BAR's physical range for importers which program it into their > own > + * translation tables, such as iommufd. A BAR is MMIO, never cache-coherent > RAM. > * > - * If this function succeeds the following are true: > - * - There is one physical range and it is pointing to MMIO > - * - When move_notify is called it means revoke, not move, vfio_dma_buf_map > - * will fail if it is currently revoked > + * When move_notify is called it means revoke, not move, so this fails while > + * revoked and vfio_dma_buf_map() does the same. > */ > -int vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment, > - struct phys_vec *phys) > +static int vfio_pci_dma_buf_get_phys(struct dma_buf_attachment *attachment, > + u64 offset, u64 len, > + struct phys_vec *phys, u32 *attr) > { > - struct vfio_pci_dma_buf *priv; > + struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv; > + u32 i; > > dma_resv_assert_held(attachment->dmabuf->resv); > - > - if (attachment->dmabuf->ops != &vfio_pci_dmabuf_ops) > - return -EOPNOTSUPP; > - > - priv = attachment->dmabuf->priv; > if (priv->revoked) > return -ENODEV; > > - /* More than one range to iommufd will require proper DMABUF support > */ > - if (priv->nr_ranges != 1) > - return -EOPNOTSUPP; > - > - *phys = priv->phys_vec[0]; > + /* Report from @offset to the end of the BAR range containing it. */ > + for (i = 0; i < priv->nr_ranges; i++) { > + if (offset < priv->phys_vec[i].len) > + break; > + offset -= priv->phys_vec[i].len; > + } > + if (i == priv->nr_ranges) > + return -EINVAL; > + phys->paddr = priv->phys_vec[i].paddr + offset; > + phys->len = min_t(u64, priv->phys_vec[i].len - offset, len); > + *attr = DMA_BUF_PHYS_ATTR_MMIO; > return 0; > } > -EXPORT_SYMBOL_FOR_MODULES(vfio_pci_dma_buf_iommufd_map, "iommufd"); > + > +static const struct dma_buf_ops vfio_pci_dmabuf_ops = { > + .attach = vfio_pci_dma_buf_attach, > + .map_dma_buf = vfio_pci_dma_buf_map, > + .unmap_dma_buf = vfio_pci_dma_buf_unmap, > + .release = vfio_pci_dma_buf_release, > + .get_phys = vfio_pci_dma_buf_get_phys, > +}; > + > > int vfio_pci_core_fill_phys_vec(struct phys_vec *phys_vec, > struct vfio_region_dma_range *dma_ranges, > diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h > index d1203da56fc5..b223962e20c2 100644 > --- a/include/linux/dma-buf.h > +++ b/include/linux/dma-buf.h > @@ -13,6 +13,7 @@ > #ifndef __DMA_BUF_H__ > #define __DMA_BUF_H__ > > +#include <linux/bitfield.h> > #include <linux/iosys-map.h> > #include <linux/file.h> > #include <linux/err.h> > @@ -23,6 +24,7 @@ > #include <linux/dma-fence.h> > #include <linux/wait.h> > #include <linux/pci-p2pdma.h> > +#include <linux/types.h> > > struct device; > struct dma_buf; > @@ -182,6 +184,29 @@ struct dma_buf_ops { > struct sg_table *, > enum dma_data_direction); > > + /** > + * @get_phys: > + * > + * Describe the run that starts at @offset, for an importer that > + * programs its own translation tables. A run is the longest stretch > + * of backed bytes whose frames are physically contiguous and share > + * one attribute word. Report it in *@phys, starting at the byte at > + * @offset and clipped at @offset + @len, with its DMA_BUF_PHYS_ATTR_* > + * word in *@attr. The exporter may stop before the end of the run; > + * importers must not assume the reported run is maximal. > + * > + * Return 0 on success, -ENOENT if the byte at @offset is not backed, > + * -ENODEV if the buffer is revoked, or another negative error. Do not > + * wait for memory to become available. > + * > + * The dma-buf reservation is held. The attachment must be pinned or > + * have revocable importer operations. A reported frame remains valid > + * until a covering invalidation callback returns; an exporter must > + * invalidate every change before reusing an old frame. > + */ > + int (*get_phys)(struct dma_buf_attachment *attach, u64 offset, u64 > len, > + struct phys_vec *phys, u32 *attr); > + > /* TODO: Add try_map_dma_buf version, to return immed with -EBUSY > * if the call would block. > */ > @@ -576,6 +601,35 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment > *, struct sg_table *, > enum dma_data_direction); > void dma_buf_invalidate_mappings(struct dma_buf *dma_buf); > bool dma_buf_attach_revocable(struct dma_buf_attachment *attach); > +/* bits 0-7: memory type (a value, not flags) */ > +#define DMA_BUF_PHYS_ATTR_TYPE_MASK GENMASK(7, 0) > +#define DMA_BUF_PHYS_ATTR_RAM 0x00 /* cache-coherent system RAM > */ > +#define DMA_BUF_PHYS_ATTR_MMIO 0x01 /* device MMIO, uncached */ > +/* bits 8-15: reserved for a second value field; must be zero */ > +#define DMA_BUF_PHYS_ATTR_RSVD_MASK GENMASK(15, 8) > +/* bits 16-31: flags; undefined bits must be zero */ > +#define DMA_BUF_PHYS_ATTR_READONLY BIT(16) > +/* BIT(17): reserved (hole, for importers that walk across gaps) */ > +/* BIT(18): reserved (private, for confidential computing) */ > +#define DMA_BUF_PHYS_ATTR_FLAGS_MASK (DMA_BUF_PHYS_ATTR_READONLY) > + > +static inline u32 dma_buf_phys_attr_type(u32 attrs) > +{ > + return FIELD_GET(DMA_BUF_PHYS_ATTR_TYPE_MASK, attrs); > +} > + > +static inline bool dma_buf_phys_attr_known(u32 attrs) > +{ > + return dma_buf_phys_attr_type(attrs) <= DMA_BUF_PHYS_ATTR_MMIO && > + !(attrs & DMA_BUF_PHYS_ATTR_RSVD_MASK) && > + !(attrs & ~(DMA_BUF_PHYS_ATTR_TYPE_MASK | > + DMA_BUF_PHYS_ATTR_RSVD_MASK | > + DMA_BUF_PHYS_ATTR_FLAGS_MASK)); > +} > + > +int dma_buf_get_phys(struct dma_buf_attachment *attach, u64 offset, u64 len, > + struct phys_vec *phys, u32 *attr); > + > int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, > enum dma_data_direction dir); > int dma_buf_end_cpu_access(struct dma_buf *dma_buf, > diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h > index 9a1674c152aa..2a1d13abdb0c 100644 > --- a/include/linux/vfio_pci_core.h > +++ b/include/linux/vfio_pci_core.h > @@ -257,7 +257,4 @@ vfio_pci_core_get_iomap(struct vfio_pci_core_device > *vdev, unsigned int bar) > return vdev->barmap[bar]; > } > > -int vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment, > - struct phys_vec *phys); > - > #endif /* VFIO_PCI_CORE_H */ > diff --git a/samples/kvm/gmem_provider.c b/samples/kvm/gmem_provider.c > index 75197c088762..b6824fe5d228 100644 > --- a/samples/kvm/gmem_provider.c > +++ b/samples/kvm/gmem_provider.c > @@ -487,35 +487,30 @@ static void gmem_dma_buf_release(struct dma_buf *dmabuf) > kfree(priv); > } > > -static const struct dma_buf_ops gmem_dma_buf_ops = { > - .attach = gmem_dma_buf_attach, > - .map_dma_buf = gmem_dma_buf_map, > - .unmap_dma_buf = gmem_dma_buf_unmap, > - .release = gmem_dma_buf_release, > -}; > - > -/* > - * Private interconnect for iommufd (mirrors vfio_pci_dma_buf_iommufd_map). > - * Returns the single contiguous phys range for the exported region so > iommufd > - * can program the IOMMU directly, bypassing the DMA API. > - */ > -int gmem_provider_dma_buf_iommufd_map(struct dma_buf_attachment *attach, > - struct phys_vec *phys); > -int gmem_provider_dma_buf_iommufd_map(struct dma_buf_attachment *attach, > - struct phys_vec *phys) > +/* Report this flat sample region through the generic dma-buf operation. */ > +static int gmem_dma_buf_get_phys(struct dma_buf_attachment *attach, > + u64 offset, u64 len, > + struct phys_vec *phys, u32 *attr) > { > - struct gmem_dmabuf *priv; > + struct gmem_dmabuf *priv = attach->dmabuf->priv; > > dma_resv_assert_held(attach->dmabuf->resv); > - if (attach->dmabuf->ops != &gmem_dma_buf_ops) > - return -EOPNOTSUPP; > - priv = attach->dmabuf->priv; > if (priv->revoked) > return -ENODEV; > - *phys = priv->phys; > + > + phys->paddr = priv->phys.paddr + offset; > + phys->len = len; > + *attr = DMA_BUF_PHYS_ATTR_RAM; > return 0; > } > -EXPORT_SYMBOL_FOR_MODULES(gmem_provider_dma_buf_iommufd_map, "iommufd"); > + > +static const struct dma_buf_ops gmem_dma_buf_ops = { > + .attach = gmem_dma_buf_attach, > + .map_dma_buf = gmem_dma_buf_map, > + .unmap_dma_buf = gmem_dma_buf_unmap, > + .release = gmem_dma_buf_release, > + .get_phys = gmem_dma_buf_get_phys, > +}; > > /* Called with info->dmabufs_lock held on the revoke path. */ > static void gmem_dma_buf_revoke_all(struct gmem_info *info) > -- > 2.47.3 >
