On 10/5/26 15:20, Fred Griffoul wrote:
> On 10/5/26 Christian König wrote:
>> 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.
>
> Understood, thanks for the quick and clear answers on this patch and on
> patch 3.
>
>> The problem you are facing here is that dma_buf_mmap() doesn't work
>> because you don't have a VMA.
>
> Right: the memory has no struct page and is deliberately not mapped in
> the host, so there is no VMA to hand to KVM.
>
> I'll post a new version of this series. It drops get_phys(), the ranged
> invalidation and the guest_memfd dma-buf import (patches 2-5), and it
> does not touch drivers/dma-buf, as you suggested in the PAL discussion:
>
> https://lore.kernel.org/all/c413710b-4c28-4ed8-88ec-aeb8c4482011@amd.com/
>
> KVM gets its frames through the KVM-private guest_memfd provider
> interface from David's series. iommufd gets them through a private
> interface with the exporter, as it already does for vfio-pci. The new
> version adds a small registry in iommufd for that, which replaces the
> symbol_get() of the sample in David's series. The dma-buf is then only
> the handle and the existing revoke.
Yeah that approach sounds totally sane to me.
We have drivers which stuff all kind of resources, not just memory, into a DMA-buf. That ranges from MMIO BARs to trigger FW operations (doorbells) over full HW blocks (ordered appends, global wave sync etc...) where two or more applications need to share which one is used.
That you then have a exporter private interface is for accessing this is perfectly ok.
The problem you are facing here is more that this is not limited to one driver/module but multiple ones and you don't want module inter dependencies because of the symbols.
So symbol_get() is probably the right thing to do as long as we don't have something like weak symbols or similar.
Regards,
Christian.
>
> Thanks,
> Fred
On 10/5/26 11:55, Fred Griffoul wrote:
> From: Fred Griffoul <fgriffo(a)amazon.co.uk>
>
> dma_buf_invalidate_mappings() tells every importer that the whole
> buffer changed. An exporter that changes one part of its memory cannot
> say which bytes changed, so importers throw away mappings that are
> still valid.
>
> Add an exporter helper that invalidates a byte range, and an importer
> callback that receives it. The callback means that the address, the
> attributes or the backing of the range changed. If part of the range is
> no longer backed, get_phys() returns -ENOENT for it. Importers must stop
> using their old answer before the callback returns. Importers that do
> not implement the callback still receive a whole-buffer invalidation.
Yeah that is exactly one of the reasons why we don't allow that.
Clear NAK to the whole approach. See the reply to patch #2 for a detailed description.
Regards,
Christian.
>
> Signed-off-by: Fred Griffoul <fgriffo(a)amazon.co.uk>
> ---
> drivers/dma-buf/dma-buf.c | 30 ++++++++++++++++++++++++++++++
> include/linux/dma-buf.h | 16 ++++++++++++++++
> 2 files changed, 46 insertions(+)
>
> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> index 66b85d53ed22..e7010163eb2f 100644
> --- a/drivers/dma-buf/dma-buf.c
> +++ b/drivers/dma-buf/dma-buf.c
> @@ -1389,6 +1389,36 @@ void dma_buf_invalidate_mappings(struct dma_buf *dmabuf)
> }
> EXPORT_SYMBOL_NS_GPL(dma_buf_invalidate_mappings, "DMA_BUF");
>
> +/**
> + * dma_buf_invalidate_mappings_range - notify attachments that a range changed
> + * @dmabuf: buffer whose layout changed
> + * @offset: first changed byte
> + * @length: number of changed bytes
> + *
> + * Importers with a ranged callback stop using their old mappings of the range
> + * before returning. Other importers receive the existing whole-buffer
> + * callback, which is correct but coarser. The reservation lock must be held.
> + */
> +void dma_buf_invalidate_mappings_range(struct dma_buf *dmabuf,
> + unsigned long offset,
> + unsigned long length)
> +{
> + struct dma_buf_attachment *attach;
> +
> + dma_resv_assert_held(dmabuf->resv);
> + list_for_each_entry(attach, &dmabuf->attachments, node) {
> + const struct dma_buf_attach_ops *ops = attach->importer_ops;
> +
> + if (!ops)
> + continue;
> + if (ops->invalidate_mappings_range)
> + ops->invalidate_mappings_range(attach, offset, length);
> + else if (ops->invalidate_mappings)
> + ops->invalidate_mappings(attach);
> + }
> +}
> +EXPORT_SYMBOL_NS_GPL(dma_buf_invalidate_mappings_range, "DMA_BUF");
> +
> /**
> * dma_buf_get_phys - describe the run that starts at an offset
> * @attach: attachment to query
> diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
> index b223962e20c2..55c3fe60a0ba 100644
> --- a/include/linux/dma-buf.h
> +++ b/include/linux/dma-buf.h
> @@ -485,6 +485,19 @@ struct dma_buf_attach_ops {
> * required behavior.
> */
> void (*invalidate_mappings)(struct dma_buf_attachment *attach);
> +
> + /**
> + * @invalidate_mappings_range: [optional] a byte range changed
> + *
> + * The exporter changed the address, attributes or backing of
> + * [@offset, @offset + @length). The importer must stop using its old
> + * answer for that range before returning.
> + * Importers without this callback receive @invalidate_mappings for
> + * the whole buffer instead.
> + */
> + void (*invalidate_mappings_range)(struct dma_buf_attachment *attach,
> + unsigned long offset,
> + unsigned long length);
> };
>
> /**
> @@ -600,6 +613,9 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
> 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);
> +void dma_buf_invalidate_mappings_range(struct dma_buf *dma_buf,
> + unsigned long offset,
> + unsigned long length);
> 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)
> --
> 2.47.3
>
On Mon, Sep 28, 2026 at 02:32:22PM +0100, Pavel Begunkov wrote:
> +static void nvme_dmabuf_map_sync_for_cpu(struct nvme_dev *nvme_dev,
> + struct request *req)
> +{
> + struct device *dev = nvme_dev->dev;
> + enum dma_data_direction dma_dir;
> + struct bio *bio = req->bio;
> + struct nvme_dmabuf_map *map = to_nvme_dmabuf_map(bio->bi_dmabuf_map);
> +
> + dma_dir = rq_data_dir(req) == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> + dma_sync_sgtable_for_cpu(dev, map->sgt, dma_dir);
This can use rq_dma_dir in the argument. Same for the other DMA API
calls.
Btw, given how larger the dmabuf code is now, have you considered
splitting it into a new nvme-pci-dmabuf.c file?
On Mon, Sep 28, 2026 at 02:32:21PM +0100, Pavel Begunkov wrote:
> Add a simple proxy implementation of init_dma_buf_io_ctx() forwarding
> the call to a new struct block_device_operations operation. Also reject
> dma-buf backed iterators for buffered IO.
>
> Reviewed-by: Christoph Hellwig <hch(a)lst.de>
> [pavel: reject dma-buf without O_DIRECT]
> Signed-off-by: Pavel Begunkov <asml.silence(a)gmail.com>
The Sashiko report about the errno on fallback here looks real,
and is probably easily fixed by setting a proper errno.
On Mon, Sep 28, 2026 at 02:32:18PM +0100, Pavel Begunkov wrote:
> Introduce a new iterator type for dmabuf maps. The map in an opaque
> object with internals and format specific to the subsystem / driver, and
> only it can use that subsystem / driver for issuing IO. The task of the
> middle layers is to pass the map / iterator further down, maybe doing
> basic splitting and length checking. The iterator can only be used by
> operations of the file the associated map was created for.
>
> Suggested-by: Keith Busch <kbusch(a)kernel.org>
> Reviewed-by: Christoph Hellwig <hch(a)lst.de>
> Signed-off-by: Pavel Begunkov <asml.silence(a)gmail.com>
FYI, I think the Sashiko complaint about iterate_and_advance2
is correct here. We don't really hit that in the series, but leaving
iov_iter methods partially implemented and fall through to others
seems dangerous. At minimum that needs a WARN_ON to catch that case.
Hi all,
The goal of this series is to enable userspace driver designs that use
VFIO to export DMABUFs representing subsets of PCI device BARs, and
"vend" those buffers from a primary process to other subordinate
processes by fd. This is achieved by allowing the processes to mmap()
the DMABUFs; their access to the device is isolated to the exported
ranges. The primary userspace driver process can forcibly revoke
access to previously-shared buffers upon cleanup (without requiring
cooperation from the subordinate processes). This is an improvement
on sharing the VFIO device fd to subordinate processes, which would
allow global access. See the RFCs for background.
The existing VFIO PCI BAR mmap() becomes backed by a DMABUF too,
keeping common vm_ops and fault handler for VMAs from the VFIO device
and explicitly-exported DMABUFs. This will help future iommufd
emulation of VFIO Type1 peer-to-peer, making it easier to get a DMABUF
for a VFIO BAR as a DMA target.
Below are per-patch notes & background info, and at the bottom are
several related questions that reviewers may like to consider (worth
at least skipping to #1, a possible bug).
Notes on patches
================
mmap() conversion to use DMABUF underneath has been done for vfio-pci,
but not sub-drivers: nvgrace-gpu's mmap() override path is unchanged;
I kept this out of scope for now not least because I don't have a
thorough test setup for this system. I would prefer to help the
nvgrace-gpu maintainers enable BAR mmap() DMABUFs themselves.
vfio/pci: Remove DMABUF export dependency on vdev->memory_lock
In v5 of this series we discover that doing an export from the VFIO
mmap() path (fundamental!) adds a dependency between mmap_lock and
vdev->memory_lock(W) because export was using memory_lock(W) to
protect the vdev->dmabufs list and state within, and a deadlock
scenario leapt out to bite:
https://lore.kernel.org/kvm/9a615f22-c0d4-46ae-9654-db11e94e5fec@ozlabs.org/
The suggestion was to add a dedicated mutex/rwsem specifically for
the DMABUFs/list, which is cleaner than overloading memory_lock(W).
But whilst export could now downgrade to holding memory_lock(R) to
test __vfio_pci_memory_enabled(), a very similar deadlock can still
arise due to a memory_lock(W) elsewhere depending on a prior
memory_lock(R) to be released, and attempting to take
memory_lock(R) will queue behind the (W) for fairness (effectively
an R->R dependency). I'd overlooked that rwsem cannot guarantee
multiple readers.
To be able to export while holding mmap_lock, export cannot hold
memory_lock at all. Instead of testing __vfio_pci_memory_enabled()
(which tracks PCI_COMMAND.MSE and PM state), this patch tracks
device-global DMABUF revocation state in a new vdev->bars_revoked
flag updated by vfio_pci_dma_buf_move(). If an mmap() is somehow
performed during a period when DMABUFs are all revoked, then the
DMABUF is created revoked. Move() already bookends reset, PM
transitions etc., so subsequent revocation state changes work
as-is. This flag is also protected by the dmabuf_lock and thus
memory_lock is not required to export.
vfio/pci: Un-revoke DMABUFs in LOW_POWER_ENTRY_WITH_WAKEUP resume
On LOW_POWER entry, DMABUFs have a move(revoke=true), but the
runtime resume path didn't un-revoke. This adds a corresponding
move(revoke=false), which will later turn into
vfio_pci_unrevoke_bars().
NOTE: the unrevoke is reordered _before_ the eventfd_signal() in
vfio_pci_core_runtime_resume() to remove a window in which a waking
waiter could have observed the DMABUF state as still revoked (or
pm_runtime_engaged = true). (The UAPI docs state the event means
the resume's complete, so observing otherwise seemed unintended.)
Also, when DMABUFs are later mmap()ed, a waiter waking and taking a
fault could have seen the unrevoked state and SIGBUS just before
taking the memory_lock. (If the handler gets to acquire the lock,
though, the resume sequence is complete, and the handler observes
pm_runtime_engaged = false.)
This fix is in this series because the issue will impact CPU access
to the VMA as well (once they use DMABUFs), and so it's a strict
dependency of later commits.
dma-buf: Provide dma_buf_set_name()
Makes dma_buf_set_name() available for use (by helper patch),
taking a kernel-allocated string. The pre-existing local helper
becomes a wrapper copying a __user string for the set-name ioctl.
vfio/pci: Add a helper to look up PFNs for DMABUFs
Adds a DMABUF VMA fault handler helper to determine arbitrary-sized
PFNs from ranges in DMABUF.
vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA
Refactors DMABUF export for use by the existing export feature, and
adds a helper that creates a DMABUF corresponding to a VFIO BAR
mmap() request.
There was a request for decent debug naming in /proc/<pid>/maps
etc. comparable to the existing VFIO names: since the VMAs are
DMABUFs, they have a "dmabuf:" prefix and can't be 100% identical
to before. This is a user-visible change, but this patch at least
now gives us extra info on the BDF & BAR being mmap()ed. The name
is installed with the new dma_buf_set_name() above.
vfio/pci: Convert BAR mmap() to use a DMABUF
The vfio-pci core mmap() creates a DMABUF with the helper above,
and the vm_ops fault handler uses the other helper to resolve the
fault. Because this depends on DMABUF structs/code,
CONFIG_VFIO_PCI_CORE needs to depend on CONFIG_DMA_SHARED_BUFFER.
The CONFIG_VFIO_PCI_DMABUF still conditionally enables the export
support code.
NOTE: The user mmap()s a device fd, but the resulting VMA's vm_file
becomes that of the DMABUF. The DMABUF takes ownership of the
device file and put()s it on release, which maintains the existing
behaviour of a VMA keeping the VFIO device open.
BAR zapping then happens via the existing vfio_pci_dma_buf_move()
path, which now needs to unmap PTEs in the DMABUF's address_space.
NOTE: As local LLM reviews did, Sashiko might falsely worry about
the DMABUF fd being obtained through /proc/pid/map_files and
remapped, but the file is an anon inode and doesn't support the
open op (-ENXIO) so AFAICT this is currently impossible.
NOTE: A side-effect of this is that is_mergeable_vma() will be
false between adjacent mappings of VFIO BARs; merging would require
rebuilding a larger DMABUF representing the union, not just
plugging the VMAs together.
The DMABUF backing the BAR is an implicit/internal export, even
when the CONFIG_VFIO_PCI_DMABUF feature is not included because
CONFIG_PCI_P2PDMA is not available. Without P2PDMA, it's
acceptable for the DMABUF to not have a P2PDMA provider. In this
configuration, the VFIO DMABUF .attach prohibits any import, which
avoids getting as far as a WARN in dma_buf_map_attachment(), which
would fail without P2PDMA anyway.
vfio/pci: Clean up BAR zap and revocation
In general (see NOTE!) the vfio_pci_zap_bars() is now obsolete,
since it unmaps PTEs in the VFIO device address_space which is now
unused. This consolidates all calls (e.g. around reset) with the
neighbouring vfio_pci_dma_buf_move()s into new functions, to
revoke/unrevoke (making the steps clearer).
NOTE: Because drivers can use their own vm_ops and override .mmap,
the core must conservatively assume an overridden .mmap might still
add PTEs to the VFIO device address_space and therefore still does
the zap. A new flag, zap_bars_on_revoke, enables the zap when
.mmap is overridden. A driver that does not need the zap can clear
this to opt-out, e.g. if the driver calls down to the common mmap
(and so uses DMABUFs). hisi-acc-vfio-pci does just this, and thus
sets the opt-out flag.
vfio/pci: Support mmap() of a VFIO DMABUF
Adds mmap() for a DMABUF fd exported from vfio-pci.
It was a goal to keep the VFIO device fd lifetime behaviour
unchanged with respect to the DMABUFs. An application can close
all device fds, and this will revoke/clean up all DMABUFs; then, no
mappings or other access can be performed. When enabling mmap() of
the DMABUFs, this means access through the VMA is also revoked.
This complicates the fault handler because whilst the DMABUF
exists, it has no guarantee that the corresponding VFIO device is
still alive. Adds synchronisation ensuring the vdev is available
before the locks in vdev are touched; this holds the device
registration so that even if the buffer has been cleaned up, vdev
hasn't been freed and so the locks can be safely taken.
vfio/pci: Revoke a DMABUF on request from userspace
This is mostly a rename of `revoked` to an enum, `status`, and
adding a third state for a buffer: usable, revoked temporary,
revoked permanent. A new VFIO feature is added,
VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE, which takes a DMABUF (exported
from the same device) and permanently revokes it. Thus a userspace
driver can guarantee any downstream consumers of a shared fd are
prevented from accessing a BAR range, and that range can be reused.
NOTE: This might block userspace, waiting on importers to detach.
The code doing revocation in vfio_pci_dma_buf_move() is moved, to a
common function used by ..._move() and this new feature.
Testing
=======
(The [RFC ONLY] userspace test program, which drives a QEMU
bochs-display function, can be found in the GitHub branch below. It
at least illustrates how the export, map, revoke, and close semantics
interoperate. WIP on a follow-up with a proper vfio-selftests style
test based on this -- this won't be part of this series.)
This code has been tested in mapping DMABUFs of single/multiple ranges
from multiple BARs, aliasing mmap()s, aliasing ranges across DMABUFs,
vm_pgoff > 0, revocation, shutdown/cleanup scenarios, and hugepage
mappings. No regressions observed on the VFIO selftests, or on our
internal vfio-pci applications. VFIO on i386 has been build-tested.
Thanks to Alex Mastro for building a (WIP) testcase for the
prior mmap_lock->memory_lock issue.
Dear Reviewers,
===============
Along the way several related issues came up that warrant more
eyes, and I'd be grateful for your input:
1. If VFIO fd is opened O_RDONLY, it currently can't be mmap()ed
(because PROT_WRITE is rejected in do_mmap(), and PROT_READ alone
drops the VM_SHARED so VFIO's mmap rejects it). BUT it seems we
can export a DMABUF from it, and then pass the resulting fd around
for P2P writes.
I don't know if this is intentional/relied on/a known limitation,
or a bug?
a) We could reject export w/ -EPERM unless the device fd's f_mode
has O_RDWR, to reflect the RW abilities of P2P
If we agree it's a bug, I want to do this fix (a), as we can now
export a DMABUF RW from an O_RDONLY device fd and then succeed to
mmap() the DMABUF with RW. (That said, even with an O_RDONLY
device fd, the device state can still be changed/reset. But it
feels cleaner to prevent export for a O_RDONLY device fd, and match
the device fd mmap() behaviour.)
In future, we could consider finer-grained RD/WR if there's a
future goal to tie DMABUF permissions to, say, iommufd
IOMMU_READ/IOMMU_WRITE permissions:
b) Instead of just failing if !O_RDWR, we could limit the
get_dma_buf.open_flags to the VFIO device fd's f_mode, such as:
VFIO device fd perms: Export flags: Result:
O_RDWR O_RDWR, O_RDONLY OK
O_RDONLY O_RDONLY OK
O_RDONLY O_RDWR -EPERM
O_WRONLY * -EPERM
* O_WRONLY -EPERM
(Skipping WRONLY because a PROT_WRITE-only mmap() won't work,
though it probably should be included for P2P.)
2. The mmap fault handler takes a bunch of locks non-interruptibly,
and potentially depends on a lot of DMABUF-related activities
completing. I'd had a go at converting them to
interruptible/killable forms, but that revealed there seems to be a
wider issue if move/revoke doesn't complete in a timely fashion
(due to buggy importers). Where I got to was that just updating
the fault handler won't fix the user experience of an unkillable
task, and move()/revocation will need thought too. I don't intend
to fix this here but wanted to start discussion so we can address
it in a follow up. There's now a dependency between mmap_lock in
the fault handler and the DMABUF resv (which might take a while to
resolve), though revocation will be rare in practice.
3. vfio_basic_config_write() has an error path if
vfio_default_config_write() fails that releases memory_lock but
doesn't un-revoke BARs in the case of PCI_COMMAND.MSE being
cleared. When can the write fail, in practice, perhaps surprise
removal?
The effect on this series would be: a write of MSE=0 revokes BARs,
vconfig[PCI_COMMAND]'s MSE becomes 0, but if the physical write
fails then the physical MSE remains 1 and BAR VMAs stay revoked.
This seemed a mess; fixing isn't as simple as un-revoking on the
error path since vfio_default_config_write() has already trampled
vconfig so that'd need unwinding. It felt like a catastrophic
scenario where BARs staying revoked isn't a bad outcome, but want
to hear your experience of the likelihood of this issue.
4. The exchange of a VFIO fd mmap()'s vma->vm_file with an implicitly
created DMABUF's file has implications on LSM. For example, an
mmap will be checked against the policy for a VFIO fd, but a
subsequent mprotect() relates to the policy of the DMABUF file
(which is anon/unique to the mapping). This is pretty confusing.
END
===
This is based on v7.3-rc4
These commits are on GitHub for easier browsing, along with
"[RFC ONLY] selftests: vfio: Add standalone vfio_dmabuf_mmap_test":
https://github.com/metamev/linux/compare/v7.3-rc4...dev/mev/vfio-dmabuf-mma…
Thanks for reading,
Matt
================================================================================
Changelog:
v7:
- Rebased, v7.3-rc4
- "dma-buf: Export dma_buf_set_name()" is now "dma-buf: Provide
dma_buf_set_name()": reworded commit message with rationale, and
indicate it is only expected to be used by exporters. Remove static
helper for user ioctl & copy from user inline in the ioctl.
- "vfio/pci: Permanently revoke a DMABUF on request" is now
"vfio/pci: Revoke a DMABUF on request from userspace", with a
clarified commit message, and removal of "temporary/permanent"
language. This still replaces the priv->revoked flag with an
enum/third state, named OK/REVOKED for the existing two. The new
state, DEAD, is "sticky" from the VFIO-internal perspective, meaning
it prevents any of the move-style transitions from REVOKED back to
OK, guaranteeing that a DEAD buffer cannot ever be attached/mapped
by a new or existing importer. Clarified language around attach vs
map to not imply a racing import will be detached; it might attach,
but cannot map (and has no existing maps) after the ioctl returns.
- Reworded several commit messages for more clarity/brevity.
- "vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA":
As of the recent e8efdf02d3a97 ("vfio: Enable cdev noiommu mode
under iommufd") dev_name() can be much larger
(e.g. noiommu_vfio1048575) and the discovery that
drivers/pci/controller/vmd.c (others?) could create a domain up to
MAX_INT means there isn't a nice way to guarantee a debug name is
available across all cdev names and maximum sizes of all properties
(e.g. 1M cdevs, 4G domains). So, removed the cdev name from the
debug name construction, which now looks like 'vfio:0001:02:03.4/5'.
The cdev can be fished out of sysfs given the domain+BDF, and it's
still useful debug. Adjusted comments & commit message.
v6: https://lore.kernel.org/all/20260911214200.33793-1-matt@ozlabs.org/
v5: https://lore.kernel.org/all/20260715174737.15287-1-matt@ozlabs.org/
v4: https://lore.kernel.org/all/20260701171245.90111-1-matt@ozlabs.org/
v3: https://lore.kernel.org/all/20260610154327.37758-1-matt@ozlabs.org/
v2: https://lore.kernel.org/all/20260527102319.100128-1-mattev@meta.com/
v1: https://lore.kernel.org/kvm/20260416131815.2729131-1-mattev@meta.com/
RFCv2: https://lore.kernel.org/kvm/20260312184613.3710705-1-mattev@meta.com/
RFCv1: https://lore.kernel.org/all/20260226202211.929005-1-mattev@meta.com/
Tech topic: https://lore.kernel.org/linux-iommu/20250918214425.2677057-1-amastro@fb.com/
Matt Evans (9):
vfio/pci: Remove DMABUF export dependency on vdev->memory_lock
vfio/pci: Un-revoke DMABUFs in LOW_POWER_ENTRY_WITH_WAKEUP resume
dma-buf: Provide dma_buf_set_name()
vfio/pci: Add a helper to look up PFNs for DMABUFs
vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA
vfio/pci: Convert BAR mmap() to use a DMABUF
vfio/pci: Clean up BAR zap and revocation
vfio/pci: Support mmap() of a VFIO DMABUF
vfio/pci: Revoke a DMABUF on request from userspace
drivers/dma-buf/dma-buf.c | 78 ++-
drivers/vfio/pci/Kconfig | 4 +-
drivers/vfio/pci/Makefile | 3 +-
.../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 14 +-
drivers/vfio/pci/vfio_pci_config.c | 30 +-
drivers/vfio/pci/vfio_pci_core.c | 222 +++++--
drivers/vfio/pci/vfio_pci_dmabuf.c | 609 +++++++++++++++---
drivers/vfio/pci/vfio_pci_priv.h | 54 +-
include/linux/dma-buf.h | 2 +
include/linux/vfio_pci_core.h | 3 +
include/uapi/linux/vfio.h | 24 +
11 files changed, 856 insertions(+), 187 deletions(-)
--
2.50.1 (Apple Git-155)
PCI P2PDMA applies Request and Completion Redirect throughout both paths.
This misclassifies asymmetric and nested switches, and reports one answer
for every kind of TLP.
Three ACS controls act on TLP attributes the client chooses rather than
on the topology: Translation Blocking and Direct Translated P2P act on
a Request's Address Type, and Completion Redirect skips Completions carrying
Relaxed Ordering.
Evaluate each direction at the path divergence, decide every class from the
one walk, and treat a client with ATS enabled as translating unless its
driver declares per-mapping ATS.
This completes the P2PDMA side; dma-buf and mlx5 follow separately.
Signed-off-by: Leon Romanovsky <leonro(a)nvidia.com>
---
Changes in v9:
- Removed dmabuf patches for now.
- Removed mlx5 per-mapping ATS declaration for now; it comes back with
the dmabuf patches.
- Link to v8: https://patch.msgid.link/20260928-fix-p2p-acs-v4-0-v8-0-404453b9c435@nvidia…
Changes in v8:
- Added extra Reviewed-by from Logan.
- Added patches to take care of ATS per-device vs. per-mapping option
- Link to v7: https://patch.msgid.link/20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia…
Changes in v7:
- Removed "Document pdev->p2pdma lifetime rules" patch, it gives nothing
after p2pmem fix.
- Split dmabuf patch.
- Tushar retested the series, so added his Tested-by.
- Added Logan's ROB tags and fixed minor documentation issues pointed
by him.
- Link to v6: https://lore.kernel.org/all/20260914-fix-p2p-acs-v4-0-v6-0-5ef07ec9ef06@nvi…
Changes in v6:
- Changed DMABUF to use callbacks and not directly stored pointer.
- Link to v5: https://patch.msgid.link/20260910-fix-p2p-acs-v4-0-v5-0-856087f63c0d@nvidia…
Changes in v5:
- Rebase on the posted fixes.
- Dropped tags from changed patches.
- Remove Egress Control Vector interpretation and coverage.
- Keep enabled Egress Control conservative as a Request redirect.
- Use pci_dbg()/dev_dbg() for diagnostics and drop the "debug" prefix.
- Removed code comments from "Document the pdev->p2pdma lifetime and RCU
rules" patch and reduced description to actual lifetime explanation.
- Added note that Linux assumes that TLPs are in strict-ordering and
untranslated.
- Added code to calculate p2p paths per-TLP type.
- Converted mlx5 to use that new proposed API.
- Link to https://patch.msgid.link/20260821-fix-p2p-acs-v4-0-v4-0-94426b96de73@nvidia…
Changes in v4:
- Reject ACS Violations and unreadable routing state instead of treating
them as host-bridge redirects
- Added Tested-by tags from Tushar Dave
- Added support to asymmetric ACS routing
- Limited redirect checks to the two ports at the path divergence
- Added standalone ACS routing diagnostics for hardware retesting
- Dropped " PCI: Account for Direct Translated P2P in ACS isolation checks" patch
- Link to v3: https://patch.msgid.link/20260811-fix-p2p-acs-v3-0-efc488ee7c03@nvidia.com
Changes in v3:
- Fixed pci_p2pdma_add_resource() error unwinding
- Made pdev->p2pdma teardown wait unconditionally for RCU readers
- Restricted pci_p2pmem_find_many() to pool-backed providers
- Documented the pdev->p2pdma lifetime and RCU rules
- Fixed calc_map_type_and_dist() handling of the verbose argument
- Required the ACS port and target to share a bus before indexing the
Egress Control Vector
- Gave pci_acs_enabled() and pci_acs_path_enabled() a scope, so the ACS
Direct Translated P2P rule no longer stops pci_enable_pasid() from
enabling PASID
- Dropped "Report ACS ports when the paths share no upstream bridge":
the mapping type cannot change without a shared upstream bridge, so
the pci=disable_acs_redir= hint was not actionable there and the ACS
walk only cost config space reads
- Folded the Request Redirect rule into pci_acs_rr_ineffective(), so
pci_acs_flags_enabled() and the Intel SPT PCH quirk share one copy
- Renamed pci_acs_egress_ctrl_set() to pci_acs_egress_ctrl_is_set(), it
reads the bit rather than setting it
- Reworded the blocked-path warning: ACS may also leave the direct route
indeterminate rather than blocked
- Added KUnit coverage for the shared-bus guard, a device with no ACS
capability and an unreadable ACS Control register
- Added the missing Fixes: tags, a second one on the
pci_p2pdma_add_resource() unwinding fix (the dangling devres action
dates to f58ef9d1d135) and one on the Egress Control isolation change
- Link to v2: https://patch.msgid.link/20260806-fix-p2p-acs-v2-0-0cec14812965@nvidia.com
Changes in v2:
- Added Logan's ROB tags
- Added commas in Documentation patch
- Link to v1: https://patch.msgid.link/20260802-fix-p2p-acs-v1-0-a7c5eb64fff6@nvidia.com
---
Leon Romanovsky (18):
PCI/P2PDMA: Document the TLP attribute assumptions
PCI/P2PDMA: Derive routing from directional ACS controls
PCI: Reject unreadable ACS controls in isolation checks
PCI/P2PDMA: Evaluate ACS controls at the path divergence
PCI/P2PDMA: Document directional ACS routing
PCI/P2PDMA: Collect the path's ACS controls before deciding
PCI/P2PDMA: Answer routing per TLP class
PCI/P2PDMA: Route Relaxed Ordering Completions directly
PCI/P2PDMA: Reject Translated Requests blocked by Translation Blocking
PCI/P2PDMA: Route Translated Requests under Direct Translated P2P
PCI/P2PDMA: Log detailed ACS routing diagnostics
PCI/P2PDMA: Add KUnit tests for the ACS routing decisions
PCI/P2PDMA: Test the ACS P2P routing walk
PCI: Add KUnit coverage for ACS isolation checks
PCI/P2PDMA: Document TLP-class routing
PCI/P2PDMA: Let a client declare that it selects ATS per mapping
PCI/P2PDMA: Evaluate the ATS path for clients with ATS enabled
PCI/P2PDMA: Test the routing of clients with ATS enabled
Documentation/admin-guide/kernel-parameters.txt | 15 +-
Documentation/driver-api/pci/p2pdma.rst | 80 +++
drivers/pci/Kconfig | 15 +
drivers/pci/Makefile | 1 +
drivers/pci/p2pdma.c | 719 ++++++++++++++++++--
drivers/pci/pci.c | 7 +-
drivers/pci/pci.h | 58 ++
drivers/pci/pci_acs_test.c | 860 ++++++++++++++++++++++++
drivers/pci/quirks.c | 6 +-
include/linux/pci-p2pdma.h | 12 +-
10 files changed, 1687 insertions(+), 86 deletions(-)
---
base-commit: 08dbfad3f5040f5bdb6c529da20d6d4e81fefd72
change-id: 20260821-fix-p2p-acs-v4-0-e72455e3a261
prerequisite-message-id: <20260830-batch-p2p-fixes-v1-0-5044e8dfbe2e(a)nvidia.com>
prerequisite-patch-id: 6b25c7fcf164cdfc14e9fac5b908d97fcf6509d7
prerequisite-patch-id: 0d083c281001365aae4b35544cf28891a6ab9a96
prerequisite-patch-id: bfd9dabf271f3cc9a3a61f46387d20c20311363d
prerequisite-patch-id: fad0275efc722830fc591509506c0a5e4f581073
prerequisite-patch-id: 0c83bee688fec1f6d1564654df7c630fa6a4a978
Best regards,
--
Leon Romanovsky <leonro(a)nvidia.com>