From: Matt Evans <matt@ozlabs.org>
To: "Alex Williamson" <alex@shazbot.org>,
"Leon Romanovsky" <leon@kernel.org>,
"Jason Gunthorpe" <jgg@nvidia.com>,
"Alex Mastro" <amastro@fb.com>,
"Christian König" <christian.koenig@amd.com>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Logan Gunthorpe" <logang@deltatee.com>,
"Kevin Tian" <kevin.tian@intel.com>,
"Pranjal Shrivastava" <praan@google.com>,
"Longfang Liu" <liulongfang@huawei.com>
Cc: "Mahmoud Adam" <mngyadam@amazon.de>,
"David Matlack" <dmatlack@google.com>,
"Björn Töpel" <bjorn@kernel.org>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Ankit Agrawal" <ankita@nvidia.com>,
"Alistair Popple" <apopple@nvidia.com>,
"Vivek Kasireddy" <vivek.kasireddy@intel.com>,
linux-kernel@vger.kernel.org, linux-media@vger.kernel.org,
dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org,
kvm@vger.kernel.org, linux-pci@vger.kernel.org
Subject: [PATCH v6 5/9] vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA
Date: Fri, 11 Sep 2026 22:41:53 +0100 [thread overview]
Message-ID: <20260911214200.33793-6-matt@ozlabs.org> (raw)
In-Reply-To: <20260911214200.33793-1-matt@ozlabs.org>
This helper, vfio_pci_core_mmap_prep_dmabuf(), creates a single-range
DMABUF for the purpose of mapping a PCI BAR. This is used in a future
commit by VFIO's ordinary mmap() path.
This function transfers ownership of the VFIO device fd to the
DMABUF, which fput()s when it's released.
Refactor the existing vfio_pci_core_feature_dma_buf() to split out
export code common to the two paths, VFIO_DEVICE_FEATURE_DMA_BUF and
this new VFIO_BAR mmap().
By exchanging the VMA file, we lose the original device path in
/proc/<pid>/maps, lsof, etc. Generate a debug-oriented synthetic
'filename' for BAR mappings based on the cdev, plus BDF, plus resource
index. (This does not apply to explicitly-exported DMABUFs which are
named by DMA_BUF_SET_NAME.)
Signed-off-by: Matt Evans <matt@ozlabs.org>
---
drivers/vfio/pci/vfio_pci_dmabuf.c | 211 +++++++++++++++++++++++------
drivers/vfio/pci/vfio_pci_priv.h | 5 +
2 files changed, 171 insertions(+), 45 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c
index 9f10b10fc436..faa9239e66f8 100644
--- a/drivers/vfio/pci/vfio_pci_dmabuf.c
+++ b/drivers/vfio/pci/vfio_pci_dmabuf.c
@@ -3,6 +3,7 @@
*/
#include <linux/dma-buf-mapping.h>
#include <linux/pci-p2pdma.h>
+#include <linux/dma-buf.h>
#include <linux/dma-resv.h>
#include "vfio_pci_priv.h"
@@ -82,6 +83,8 @@ static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf)
up_write(&priv->vdev->dmabuf_lock);
vfio_device_put_registration(&priv->vdev->vdev);
}
+ if (priv->vfile)
+ fput(priv->vfile);
kfree(priv->phys_vec);
kfree(priv);
}
@@ -246,6 +249,167 @@ int vfio_pci_dma_buf_find_pfn(struct vfio_pci_core_device *vdev,
return ret;
}
+/*
+ * Create a DMABUF corresponding to priv, add it to vdev->dmabufs list
+ * for tracking (meaning cleanup or revocation will zap it), and take
+ * a vfio_device registration.
+ */
+static int vfio_pci_dmabuf_export(struct vfio_pci_core_device *vdev,
+ struct vfio_pci_dma_buf *priv, u32 flags)
+{
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+ if (!vfio_device_try_get_registration(&vdev->vdev))
+ return -ENODEV;
+
+ exp_info.ops = &vfio_pci_dmabuf_ops;
+ exp_info.size = priv->size;
+ exp_info.flags = flags;
+ exp_info.priv = priv;
+
+ priv->dmabuf = dma_buf_export(&exp_info);
+ if (IS_ERR(priv->dmabuf)) {
+ vfio_device_put_registration(&vdev->vdev);
+ return PTR_ERR(priv->dmabuf);
+ }
+
+ kref_init(&priv->kref);
+ init_completion(&priv->comp);
+
+ /* dma_buf_put() now frees priv */
+ INIT_LIST_HEAD(&priv->dmabufs_elm);
+
+ /*
+ * dmabuf_lock synchronises access (R) or updates (W) to the
+ * vdev->dmabufs list and to bars_revoked (see below). The
+ * revocation state of DMABUF elements in the list is written
+ * holding both dmabuf_lock(W) and resv, and tested with
+ * either.
+ *
+ * (memory_lock, if held ->) dmabuf_lock -> resv
+ *
+ * NOTE: memory_lock is strictly avoided here, to avoid a
+ * dependency on memory_lock when mmap_lock is held, when
+ * mmap() leads to export. vfio-pci variant drivers are
+ * permitted to hold memory_lock across actions that might
+ * fault (such as user access); a deadlock could result when
+ * that fault path attempts to take mmap_lock (if held by an
+ * export waiting for memory_lock).
+ *
+ * vdev->bars_revoked tracks the BAR revocation status updated
+ * via vfio_pci_dma_buf_move(), so the initial DMABUF state
+ * follows the same criteria that later update the DMABUF
+ * state (BAR zap, etc.).
+ */
+ lockdep_assert_not_held(&vdev->memory_lock);
+
+ down_write(&vdev->dmabuf_lock);
+ dma_resv_lock(priv->dmabuf->resv, NULL);
+ priv->revoked = vdev->bars_revoked;
+ list_add_tail(&priv->dmabufs_elm, &vdev->dmabufs);
+ dma_resv_unlock(priv->dmabuf->resv);
+ up_write(&vdev->dmabuf_lock);
+
+ return 0;
+}
+
+int vfio_pci_core_mmap_prep_dmabuf(struct vfio_pci_core_device *vdev,
+ struct vm_area_struct *vma,
+ u64 phys_start, u64 req_len,
+ unsigned int res_index)
+{
+ struct vfio_pci_dma_buf *priv;
+ unsigned long vma_pgoff = vma->vm_pgoff & (VFIO_PCI_OFFSET_MASK >> PAGE_SHIFT);
+ char *bufname;
+ int ret;
+
+ priv = kzalloc_obj(*priv);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->phys_vec = kzalloc_obj(*priv->phys_vec);
+ if (!priv->phys_vec) {
+ ret = -ENOMEM;
+ goto err_free_priv;
+ }
+
+ /*
+ * Maximum size of the friendly debug name is
+ * vfio1048575:ffff:ff:1f.7/5 = 26. This fits within
+ * DMA_BUF_NAME_LEN, so dma_buf_set_name() below won't fail.
+ */
+ bufname = kasprintf(GFP_KERNEL, "%s:%s/%x",
+ dev_name(&vdev->vdev.device), pci_name(vdev->pdev),
+ res_index);
+
+ if (!bufname) {
+ ret = -ENOMEM;
+ goto err_free_phys;
+ }
+
+ /*
+ * The DMABUF begins from the mmap()'s BAR offset, i.e. the
+ * start of the VMA corresponds to byte 0 of the DMABUF and
+ * byte (vma_pgoff << PAGE_SHIFT) of the BAR.
+ *
+ * vfio_pci_dma_buf_find_pfn() reverses this offset using
+ * vma_pgoff_adjust, so that ultimately a fault's offset from
+ * the start of the _VMA_ has a consistent usage whether the
+ * VMA originates from an mmap() of the VFIO device here or a
+ * direct DMABUF mmap(). Note vma_pgoff_adjust also includes
+ * the encoded VFIO region index, which cancels out the index
+ * encoded in vm_pgoff.
+ */
+ priv->vdev = vdev;
+ priv->size = req_len;
+ priv->nr_ranges = 1;
+ priv->vma_pgoff_adjust = vma->vm_pgoff;
+
+ priv->provider = pcim_p2pdma_provider(vdev->pdev, res_index);
+ if (!priv->provider) {
+ ret = -EINVAL;
+ goto err_free_name;
+ }
+
+ priv->phys_vec[0].paddr = phys_start + ((u64)vma_pgoff << PAGE_SHIFT);
+ priv->phys_vec[0].len = priv->size;
+
+ ret = vfio_pci_dmabuf_export(vdev, priv, O_RDWR);
+ if (ret)
+ goto err_free_name;
+
+ if (dma_buf_set_name(priv->dmabuf, bufname)) {
+ /* Shouldn't happen, but don't leak if it does: */
+ dev_dbg_ratelimited(&vdev->pdev->dev,
+ "Failed to set map name '%s'\n",
+ bufname);
+ kfree(bufname);
+ }
+
+ /*
+ * Ownership of the DMABUF file transfers to the VMA so that
+ * other users can locate the DMABUF via a VA. Ownership of
+ * the original VFIO device file being mmap()ed transfers to
+ * priv, and is put when the DMABUF is released. This
+ * intentionally does not use get_file()/vma_set_file()
+ * because the references are already held, and ownership
+ * moves.
+ */
+ priv->vfile = vma->vm_file;
+ vma->vm_file = priv->dmabuf->file;
+ vma->vm_private_data = priv;
+
+ return 0;
+
+err_free_name:
+ kfree(bufname);
+err_free_phys:
+ kfree(priv->phys_vec);
+err_free_priv:
+ kfree(priv);
+ return ret;
+}
+
/*
* This is a temporary "private interconnect" between VFIO DMABUF and iommufd.
* It allows the two co-operating drivers to exchange the physical address of
@@ -364,7 +528,6 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
{
struct vfio_device_feature_dma_buf get_dma_buf = {};
struct vfio_region_dma_range *dma_ranges;
- DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct vfio_pci_dma_buf *priv;
size_t length;
int ret;
@@ -424,49 +587,9 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
kfree(dma_ranges);
dma_ranges = NULL;
- if (!vfio_device_try_get_registration(&vdev->vdev)) {
- ret = -ENODEV;
+ ret = vfio_pci_dmabuf_export(vdev, priv, get_dma_buf.open_flags);
+ if (ret)
goto err_free_phys;
- }
-
- exp_info.ops = &vfio_pci_dmabuf_ops;
- exp_info.size = priv->size;
- exp_info.flags = get_dma_buf.open_flags;
- exp_info.priv = priv;
-
- priv->dmabuf = dma_buf_export(&exp_info);
- if (IS_ERR(priv->dmabuf)) {
- ret = PTR_ERR(priv->dmabuf);
- goto err_dev_put;
- }
-
- kref_init(&priv->kref);
- init_completion(&priv->comp);
-
- /* dma_buf_put() now frees priv */
- INIT_LIST_HEAD(&priv->dmabufs_elm);
-
- /*
- * dmabuf_lock synchronises access (R) or updates (W) to the
- * vdev->dmabufs list and to bars_revoked (see below). The
- * revocation state of DMABUF elements in the list is written
- * holding both dmabuf_lock(W) and resv, and tested with
- * either.
- *
- * dmabuf_lock -> resv
- *
- * vdev->bars_revoked tracks the BAR revocation status updated
- * via vfio_pci_dma_buf_move(), so the initial DMABUF state
- * follows the same criteria that later update the DMABUF
- * state (BAR zap, etc.).
- */
- down_write(&vdev->dmabuf_lock);
- dma_resv_lock(priv->dmabuf->resv, NULL);
- priv->revoked = vdev->bars_revoked;
- list_add_tail(&priv->dmabufs_elm, &vdev->dmabufs);
- dma_resv_unlock(priv->dmabuf->resv);
- up_write(&vdev->dmabuf_lock);
-
/*
* dma_buf_fd() consumes the reference, when the file closes the dmabuf
* will be released.
@@ -477,8 +600,6 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
return ret;
-err_dev_put:
- vfio_device_put_registration(&vdev->vdev);
err_free_phys:
kfree(priv->phys_vec);
err_free_priv:
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index 48d9f574a3df..3ec676e12e21 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -30,6 +30,7 @@ struct vfio_pci_dma_buf {
size_t size;
struct phys_vec *phys_vec;
struct p2pdma_provider *provider;
+ struct file *vfile;
u32 nr_ranges;
struct kref kref;
struct completion comp;
@@ -134,6 +135,10 @@ int vfio_pci_dma_buf_find_pfn(struct vfio_pci_core_device *vdev,
unsigned long address,
unsigned int order,
unsigned long *out_pfn);
+int vfio_pci_core_mmap_prep_dmabuf(struct vfio_pci_core_device *vdev,
+ struct vm_area_struct *vma,
+ u64 phys_start, u64 req_len,
+ unsigned int res_index);
#ifdef CONFIG_VFIO_PCI_DMABUF
int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
--
2.50.1 (Apple Git-155)
next prev parent reply other threads:[~2026-09-11 21:42 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 21:41 [PATCH v6 0/9] vfio/pci: Add mmap() for DMABUFs Matt Evans
2026-09-11 21:41 ` [PATCH v6 1/9] vfio/pci: Remove DMABUF export dependency on vdev->memory_lock Matt Evans
2026-09-11 21:41 ` [PATCH v6 2/9] vfio/pci: Un-revoke DMABUFs in LOW_POWER_ENTRY_WITH_WAKEUP resume Matt Evans
2026-09-11 21:41 ` [PATCH v6 3/9] dma-buf: Export dma_buf_set_name() Matt Evans
2026-09-14 11:06 ` Christian König
2026-09-15 13:35 ` Matt Evans
2026-09-11 21:41 ` [PATCH v6 4/9] vfio/pci: Add a helper to look up PFNs for DMABUFs Matt Evans
2026-09-11 21:41 ` Matt Evans [this message]
2026-09-15 12:16 ` [PATCH v6 5/9] vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA liulongfang
2026-09-21 13:24 ` Matt Evans
2026-09-22 9:16 ` liulongfang
2026-09-24 12:43 ` Matt Evans
2026-09-11 21:41 ` [PATCH v6 6/9] vfio/pci: Convert BAR mmap() to use a DMABUF Matt Evans
2026-09-11 21:41 ` [PATCH v6 7/9] vfio/pci: Clean up BAR zap and revocation Matt Evans
2026-09-11 21:41 ` [PATCH v6 8/9] vfio/pci: Support mmap() of a VFIO DMABUF Matt Evans
2026-09-11 21:41 ` [PATCH v6 9/9] vfio/pci: Permanently revoke a DMABUF on request Matt Evans
2026-09-13 16:52 ` Leon Romanovsky
2026-09-14 11:36 ` Jason Gunthorpe
2026-09-14 11:54 ` Leon Romanovsky
2026-09-14 11:58 ` Jason Gunthorpe
2026-09-14 12:06 ` Leon Romanovsky
2026-09-14 12:08 ` Jason Gunthorpe
2026-09-14 12:13 ` Matt Evans
2026-09-15 7:20 ` Leon Romanovsky
2026-09-15 11:13 ` Christian König
2026-09-15 14:22 ` Matt Evans
2026-09-16 14:19 ` Christian König
2026-09-21 13:08 ` Matt Evans
2026-09-21 13:22 ` Jason Gunthorpe
2026-09-21 13:45 ` Christian König
2026-09-21 13:49 ` Jason Gunthorpe
2026-09-21 14:09 ` Christian König
2026-09-22 12:41 ` Jason Gunthorpe
2026-09-22 12:46 ` Leon Romanovsky
2026-09-22 12:54 ` Jason Gunthorpe
2026-09-22 22:31 ` Alex Mastro
2026-09-22 22:57 ` Jason Gunthorpe
2026-09-23 15:40 ` Matt Evans
2026-09-23 16:13 ` Jason Gunthorpe
2026-09-23 16:52 ` Leon Romanovsky
2026-09-23 17:06 ` Matt Evans
2026-09-24 17:36 ` Alex Mastro
2026-09-22 11:40 ` Leon Romanovsky
2026-09-15 12:35 ` Jason Gunthorpe
2026-09-15 14:30 ` Matt Evans
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260911214200.33793-6-matt@ozlabs.org \
--to=matt@ozlabs.org \
--cc=alex@shazbot.org \
--cc=amastro@fb.com \
--cc=ankita@nvidia.com \
--cc=apopple@nvidia.com \
--cc=bhelgaas@google.com \
--cc=bjorn@kernel.org \
--cc=christian.koenig@amd.com \
--cc=dmatlack@google.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=jgg@nvidia.com \
--cc=kevin.tian@intel.com \
--cc=kvm@vger.kernel.org \
--cc=leon@kernel.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=liulongfang@huawei.com \
--cc=logang@deltatee.com \
--cc=mngyadam@amazon.de \
--cc=praan@google.com \
--cc=sumit.semwal@linaro.org \
--cc=vivek.kasireddy@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.