On 10/21/26 11:08, Val Packett wrote:
Introduce a new ioctl that allows userspace to register an eventfd to get notified when a dma-buf is released.
The current use case comes from virtio-gpu device backends wishing to add support for guest-owned buffers with host handles (CREATE_GUEST_HANDLE):
- guest creates a guest-only blob resource on the virtgpu
- host creates a udmabuf from the iovecs sent by the guest
- guest attaches the resource to a cross-domain socket send operation
- guest immediately releases the resource (no longer needed by the guest)
- host sends the udmabuf to the compositor, but needs to delay responding to the resource release request until the resource is *actually* free on the host side, i.e. the compositor no longer uses it
Interesting use case you have here.
It doesn't sound to crazy, e.g. it can't deadlock the kernel or anything like that which we often see with dma-fence.
Signed-off-by: Val Packett val@invisiblethingslab.com
More background on the use case with extra links: https://lore.kernel.org/virtio-comment/20260903021442.423274-1-val@invisible...
Funnily enough, gntdev-dmabuf (which is used on Xen hosts instead of udmabuf for this) offers "a way" to "poll" for these release events on its dmabufs (IOCTL_GNTDEV_DMABUF_EXP_WAIT_RELEASED), but it's unusable:
- it's a blocking wait!!
- release does not happen while you still have the fd open, so:
- you can't just timeout and restart, you'd need the fd to restart;
- and the only way to even close the fd is from a different thread, after some arbitrary timeout when hopefully the wait has started.
Oh that made my day :D
The buffer lifecycle coordination we need this for applies to KVM as well and it generally doesn't make sense to have this as a provider-specific thing since it's not related to the provider in any way, it's just something we want from dmabufs in general.
I wouldn't put that on the DMA-buf file descriptor where basically anybody can mess with it. That is just an recipe for trouble.
The better approach seems to be putting it into the udmabuf_ioctl(), so that from the very beginning you add the eventfd which signals when the udmabuf is released.
If we need that for more implementations than just udmabuf, we can potentially add it to dma_buf_export_info so that exporters can provide the eventfd file descriptor directly on creation.
Regards, Christian.
Thanks, ~val
drivers/dma-buf/dma-buf.c | 24 ++++++++++++++++++++++++ include/linux/dma-buf.h | 3 +++ include/uapi/linux/dma-buf.h | 1 + 3 files changed, 28 insertions(+)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 36cdc342627e..1321fee73656 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -17,6 +17,7 @@ #include <linux/dma-fence.h> #include <linux/dma-fence-unwrap.h> #include <linux/anon_inodes.h> +#include <linux/eventfd.h> #include <linux/export.h> #include <linux/debugfs.h> #include <linux/list.h> @@ -185,6 +186,11 @@ static void dma_buf_release(struct dentry *dentry) if (dmabuf->resv == (struct dma_resv *)&dmabuf[1]) dma_resv_fini(dmabuf->resv);
- if (dmabuf->release_eventfd) {
eventfd_signal(dmabuf->release_eventfd);eventfd_ctx_put(dmabuf->release_eventfd);- }
- WARN_ON(!list_empty(&dmabuf->attachments)); module_put(dmabuf->owner); kfree(dmabuf->name);
@@ -537,6 +543,21 @@ static long dma_buf_import_sync_file(struct dma_buf *dmabuf, } #endif +static long dma_buf_set_release_eventfd(struct dma_buf *dmabuf,
u32 fd)+{
- struct eventfd_ctx *ev_fd_ctx = eventfd_ctx_fdget(fd);
- if (IS_ERR(ev_fd_ctx))
return PTR_ERR(ev_fd_ctx);- if (dmabuf->release_eventfd)
eventfd_ctx_put(dmabuf->release_eventfd);- dmabuf->release_eventfd = ev_fd_ctx;
- return 0;
+}
static long dma_buf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -587,6 +608,9 @@ static long dma_buf_ioctl(struct file *file, return dma_buf_import_sync_file(dmabuf, (const void __user *)arg); #endif
- case DMA_BUF_IOCTL_SET_RELEASE_EVENTFD:
return dma_buf_set_release_eventfd(dmabuf, (u32)arg);- default: return -ENOTTY; }
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index d15b2b31d3c9..07b4a589a793 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -429,6 +429,9 @@ struct dma_buf { __poll_t active; } cb_in, cb_out;
- /** @release_eventfd: for userspace release notification */
- struct eventfd_ctx *release_eventfd;
}; /** diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h index e827c9d20c5d..566dea778ad0 100644 --- a/include/uapi/linux/dma-buf.h +++ b/include/uapi/linux/dma-buf.h @@ -179,5 +179,6 @@ struct dma_buf_import_sync_file { #define DMA_BUF_SET_NAME_B _IOW(DMA_BUF_BASE, 1, __u64) #define DMA_BUF_IOCTL_EXPORT_SYNC_FILE _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file) #define DMA_BUF_IOCTL_IMPORT_SYNC_FILE _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file) +#define DMA_BUF_IOCTL_SET_RELEASE_EVENTFD _IOW(DMA_BUF_BASE, 4, __u32) #endif