One problem that was brought up is that the file table size is often a limiting factor when working with dma-bufs, which is quite an old problem. With a single io_uring people can work it around by closing the dma-buf fd after registration, but for more complex cases we need a way to dynamically register it into another ring. We also need to deduplicate internal registrations as each creates a new attachment and related structures, which could involve large allocations and iommu mappings. Solve it by enabling io_uring buffer cloning. I made dma-bufs registered for io_uring not cloneable between rings because the implementation could modify parts of struct io_buf_dma without any locking and sharing it would've created races. That was an optimisation that got dropped at some point for simplicity, so we can safely enable cloning back as long as IORING_SETUP_IOPOLL rejection is honoured. Kill the uncloneable flag as unused as well. Reported-by: William Power Reported-by: Tushar Gohad Signed-off-by: Pavel Begunkov --- Some tests using it: https://github.com/isilence/liburing/commits/rw-dmabuf-tests io_uring/dma-buf.c | 7 ++++++- io_uring/rsrc.c | 4 +++- io_uring/rsrc.h | 3 +-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/io_uring/dma-buf.c b/io_uring/dma-buf.c index 1a1a88640823..132e3d0d7023 100644 --- a/io_uring/dma-buf.c +++ b/io_uring/dma-buf.c @@ -18,6 +18,11 @@ int __io_register_dmabuf(struct io_ring_ctx *ctx, struct dma_buf *dmabuf = NULL; int ret; + /* + * We have to drop the dma-buf map early when IO is finished. Disable + * IOPOLL for now as we can't wait potentially infintely for a task + * to do that. + */ if (ctx->flags & IORING_SETUP_IOPOLL) return -EOPNOTSUPP; if (desc->uaddr || desc->size) @@ -51,7 +56,7 @@ int __io_register_dmabuf(struct io_ring_ctx *ctx, imu->len = dmabuf->size; imu->release = io_release_dmabuf; imu->priv = bd; - imu->flags = IO_REGBUF_F_DMABUF | IO_REGBUF_F_UNCLONEABLE; + imu->flags = IO_REGBUF_F_DMABUF; imu->dir = IO_BUF_DEST | IO_BUF_SOURCE; dma_buf_put(dmabuf); return 0; diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c index 2e89e091afbb..d64228b0e19e 100644 --- a/io_uring/rsrc.c +++ b/io_uring/rsrc.c @@ -1507,7 +1507,9 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx if (!src_node) { dst_node = NULL; } else { - if (src_node->buf->flags & IO_REGBUF_F_UNCLONEABLE) { + /* we don't allow IOPOLL rw with dma-buf for now */ + if ((src_node->buf->flags & IO_REGBUF_F_DMABUF) && + (ctx->flags & IORING_SETUP_IOPOLL)) { io_rsrc_data_free(ctx, &data); return -EOPNOTSUPP; } diff --git a/io_uring/rsrc.h b/io_uring/rsrc.h index d893cc5e580a..418d236152ff 100644 --- a/io_uring/rsrc.h +++ b/io_uring/rsrc.h @@ -27,8 +27,7 @@ struct io_rsrc_node { enum { IO_REGBUF_F_KBUF = 1 << 0, - IO_REGBUF_F_UNCLONEABLE = 1 << 1, - IO_REGBUF_F_DMABUF = 1 << 3, + IO_REGBUF_F_DMABUF = 1 << 1, }; enum { -- 2.54.0