On Sun, 2026-08-30 at 10:58 +0300, Leon Romanovsky wrote: > On Thu, Aug 27, 2026 at 09:18:29PM +0200, Thomas Hellström wrote: > > Hi, > > > > Some comments below: > > > > On Tue, 2026-08-25 at 09:28 +0300, Leon Romanovsky wrote: > > > From: Leon Romanovsky <[email protected]> > > > > > > Pinned, revoked and movable mappings are selected by which > > > optional > > > callbacks each side implements and by whether dma_buf_pin() > > > succeeds, > > > not by any flag or enum. Nothing in Documentation/ says so, and > > > the > > > rules are spread over the kdoc of dma_buf_ops.pin, > > > dma_buf_attach_ops.invalidate_mappings and > > > dma_buf_invalidate_mappings(), > > > so a driver author has to know the symbol names before finding > > > them. > > > > > > Name, per flow, the callbacks both sides have to implement to end > > > up > > > in > > > it, describe dma_buf_pin() as the runtime negotiation, and record > > > that > > > the pin is what tells a revoke from a move. > > > > > > Signed-off-by: Leon Romanovsky <[email protected]> > > > --- > > > Documentation/driver-api/dma-buf.rst | 6 +++ > > > drivers/dma-buf/dma-buf.c | 85 > > > +++++++++++++++++++++++++++++++++++- > > > 2 files changed, 90 insertions(+), 1 deletion(-) > > > > > > diff --git a/Documentation/driver-api/dma-buf.rst > > > b/Documentation/driver-api/dma-buf.rst > > > index 2f36c21d9948..39c201f38aa6 100644 > > > --- a/Documentation/driver-api/dma-buf.rst > > > +++ b/Documentation/driver-api/dma-buf.rst > > > @@ -113,6 +113,12 @@ Basic Operation and Device DMA Access > > > .. kernel-doc:: drivers/dma-buf/dma-buf.c > > > :doc: dma buf device access > > > > > > +Mapping Lifetime Negotiation > > > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > > > + > > > +.. kernel-doc:: drivers/dma-buf/dma-buf.c > > > + :doc: mapping lifetime negotiation > > > + > > > CPU Access to DMA Buffer Objects > > > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > > > > > > diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma- > > > buf.c > > > index d504c636dc29..30afec7365bc 100644 > > > --- a/drivers/dma-buf/dma-buf.c > > > +++ b/drivers/dma-buf/dma-buf.c > > > @@ -684,7 +684,90 @@ static struct file *dma_buf_getfile(size_t > > > size, > > > int flags) > > > * reference acquired with dma_buf_get() by calling > > > dma_buf_put(). > > > * > > > * For the detailed semantics exporters are expected to > > > implement > > > see > > > - * &dma_buf_ops. > > > + * &dma_buf_ops. Whether the exporter may still move or destroy > > > the > > > backing > > > + * storage after step 3 depends on what exporter and importer > > > implement, see > > > + * the mapping lifetime negotiation section below. > > > + */ > > > + > > > +/** > > > + * DOC: mapping lifetime negotiation > > > + * > > > + * No flag or enum says whether the exporter may move or take > > > away > > > the backing > > > + * storage while an importer holds a mapping. Each side > > > implements a > > > set of > > > + * optional callbacks, and dma_buf_pin() settles the result at > > > runtime. Three > > > + * flows come out of it: > > > + * > > > + * - Pinned: the storage never moves and is never taken away. > > > + * - Revoked: the storage never moves, but the exporter may take > > > it > > > away. > > > + * - Movable: the exporter may relocate the storage at any time. > > > > Perhaps add "even temporarily to locations that are not available > > for > > DMA". > > I don't know. "Not available for DMA" defeats the whole purpose of > dma-buf, > which is intended to expose DMA-capable memory to other peers. I > imagine > that "everything is optional dmabuf world" this is possible, but it > looks to me like a partial version of revoked flow.
Not permanently revoked. In practice this would be, for example, a GPU- exported dma-buf which is only available for p2p access which gets evicted, or a system memory exported dma-buf that gets hit by a shrinker and moved to swap. The exporter calls invalidate_mappings() to notify importers that storage is going away. Importers need to call map_attachment() to bring it back. > > > > > > + * > > > + * Every exporter implements &dma_buf_ops.map_dma_buf, > > > + * &dma_buf_ops.unmap_dma_buf and &dma_buf_ops.release. > > > dma_buf_export() > > > + * rejects an exporter missing any of them. > > > + * > > > + * An importer reaches its flow like this: > > > + * > > > + * 1. Attach with dma_buf_dynamic_attach(). Leaving > > > + * &dma_buf_attach_ops.invalidate_mappings NULL rules out > > > everything but the > > > + * pinned flow, because the importer can then never be told > > > anything. > > > + * 2. Call dma_buf_pin() under the reservation lock. > > > + * 3. On failure run the movable flow, or give up. > > > + * 4. On success the storage stays put. Whether the exporter may > > > still take it > > > + * away, which makes this the revoked flow instead of the > > > pinned > > > one, is the > > > + * exporter's choice and is not reported back. > > > + * > > > + * dma_buf_attach() is the shorthand for an importer which only > > > ever > > > wants the > > > + * pinned flow. It passes no &dma_buf_attach_ops, and DMA-buf > > > then > > > pins around > > > + * every dma_buf_map_attachment() and waits for the > > > DMA_RESV_USAGE_KERNEL > > > + * fences on the importer's behalf. Peer to peer needs > > > + * dma_buf_dynamic_attach(), because > > > &dma_buf_attach_ops.allow_peer2peer lives > > > + * in the attach ops. > > > + * > > > + * Pinned flow: > > > + * > > > + * - Exporter: implement &dma_buf_ops.pin and &dma_buf_ops.unpin > > > to > > > hold the > > > + * storage still on request. An exporter whose storage never > > > moves > > > implements > > > + * neither, and dma_buf_pin() then succeeds on its own. An > > > exporter which > > > + * refuses to be pinned implements &dma_buf_ops.pin and fails > > > it. > > > + * - Importer: nothing more. The mapping stays valid until it > > > unmaps. > > > + * > > > + * Revoked flow: > > > + * > > > + * - Exporter: answer dma_buf_pin() as above. Call > > > + * dma_buf_invalidate_mappings() when the storage goes away > > > and > > > fail > > > + * &dma_buf_ops.map_dma_buf while it is gone. The two waits > > > which > > > complete a > > > + * revocation are described in dma_buf_invalidate_mappings(). > > > + * - Importer: &dma_buf_attach_ops.invalidate_mappings has to > > > unmap > > > within > > > + * bounded time and drop the pin. > > > + * > > > + * Movable flow: > > > + * > > > + * - Exporter: call dma_buf_invalidate_mappings() before each > > > move, > > > then wait > > > + * for the &dma_buf.resv fences. &dma_buf_ops.pin and > > > &dma_buf_ops.unpin play > > > + * no part here. > > > + * - Importer: hold no pin. > > > &dma_buf_attach_ops.invalidate_mappings > > > drops the > > > + * cached mapping and has to lead to > > > dma_buf_unmap_attachment() > > > within > > > + * bounded time. > > > > Hear I would want to see the exporter being allowed to force unmap > > the > > dma mappings and reclaim thestorage when the fences mentioned above > > have signaled, but the importer has not yet called > > dma_buf_unmap_attachment(). That would allow importers to call > > dma_buf_unmap_attachment() lazily, just before the next > > map_attachment, > > which would allow simplifying importer implementations. > > How? It will move one piece of code as is to another place. In > addition, > both exporter and importer need to stop HW access to same region. A typical GPU example: A GPU importer receives invalidate_mappings() on an imported dma-buf. The dma-buf is still accessed by the GPU and thus has a couple of dma-fences attached. The importer can't immediately call dma_buf_unmap_attachment(). In fact, typically the easiest thing for the importer is to call dma_buf_unmap_attachment() on the next gpu command submission immediately followed by a dma_buf_map_attachment(), but it can't guarantee that would happen within bounded time. A well behaved importer would therefore currently have to schedule an async worker or similar to wait for its dma-fences to signal and then grab the resv lock from worker context and call dma_buf_unmap_attachment(). A well-behaved exporter on the other hand, would have to wait for all dma-fences to signal, then wait for all unmap_attachment() calls before reclaiming. TBH I'm not sure what the best solution is here, but the importer flow doesn't fit well in a typical gpu command submission model IMO. Thanks, Thomas > > > More of a related idea than something that needs fixing for this > > patch. > > > > > It need not stop the hardware, because access runs until the > > > + * importer's &dma_buf.resv fences retire. Map again before > > > the > > > next DMA. > > > > A successful map will mean the exporter has placed the data in > > storage > > compatible with what was agreed during attachment? > > Yes. > > > > > Thanks, > > Thomas > >
