summaryrefslogtreecommitdiff
path: root/io_uring
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-27 07:46:05 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-27 07:46:05 -1000
commited02f4f7ad9b5dabae2118e642cbbafe7dc9bb62 (patch)
tree297a798f9c58025b40247523470f5050faf08b2c /io_uring
parentd135ab453a7400a34930bdda1ef4bdc8acfac80e (diff)
parent45b716456dd99488a0cef58482120dc0474aa696 (diff)
Merge tag 'for-7.4/io_uring-dmabuf-20261023' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux
Pull io_uring dma-buf support from Jens Axboe: "This adds native dma-buf support to the I/O path, exposed through io_uring. It's been in development for a while and should be ready to go now. - dma-buf file I/O infrastructure: a dma_buf_io_ctx created through a new ->init_dma_buf_io_ctx file operation, and a dma_buf_io_map holding the device DMA mapping. The two are split so a mapping can be invalidated and re-established underneath a live context, with the map counting in-flight requests so it can be torn down safely. - A new iov_iter type for dmabuf maps, and a dma map backed bio type for the block layer, with raw block device support on top. - nvme-pci backend implementing dma-buf backed requests, including SGL support. - io_uring dmabuf backed registered buffers, built on a reworked buffer registration structure with an extended update path, regbuf import flags, an uncloneable flag for buffer types that can't be cloned, and cloning support for registered dma-bufs" * tag 'for-7.4/io_uring-dmabuf-20261023' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: io_uring/dma-buf: don't fail fixed buffers without dma-buf support nvme-pci: detach dma-bufs only on removal block: reject dma-bufs larger than 4GiB io_uring/dma-buf: allow cloning registered dma-bufs dma-buf-io: document dma_buf_io_init_map dma-buf-io: fix typos in kernel docs block: fix indention for dma-buf checks io_uring/rsrc: add dmabuf backed registered buffers io_uring/rsrc: add regbuf import flags io_uring/rsrc: add uncloneable regbuf flag io_uring/rsrc: extend buffer update io_uring/rsrc: introduce buf registration structure nvme-pci: add SGL support for the dmabuf path nvme-pci: implement dma-buf backed requests nvme-pci: rename nvme_pci_sgl_set_data to nvme_pci_dma_iter_set_sgl block: add dma-buf support for raw bdev block: introduce dma map backed bio type block: always adjust bi_offset on bio_advance_iter iov_iter: add iterator type for dmabuf maps dma-buf: introduce initial file I/O infrastructure
Diffstat (limited to 'io_uring')
-rw-r--r--io_uring/Makefile1
-rw-r--r--io_uring/dma-buf.c71
-rw-r--r--io_uring/dma-buf.h76
-rw-r--r--io_uring/rsrc.c176
-rw-r--r--io_uring/rsrc.h31
-rw-r--r--io_uring/rw.c33
6 files changed, 333 insertions, 55 deletions
diff --git a/io_uring/Makefile b/io_uring/Makefile
index c54e328d1410..965bb60e9f7b 100644
--- a/io_uring/Makefile
+++ b/io_uring/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_PROC_FS) += fdinfo.o
obj-$(CONFIG_IO_URING_MOCK_FILE) += mock_file.o
obj-$(CONFIG_IO_URING_BPF) += bpf_filter.o
obj-$(CONFIG_IO_URING_BPF_OPS) += bpf-ops.o
+obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o
diff --git a/io_uring/dma-buf.c b/io_uring/dma-buf.c
new file mode 100644
index 000000000000..132e3d0d7023
--- /dev/null
+++ b/io_uring/dma-buf.c
@@ -0,0 +1,71 @@
+#include "dma-buf.h"
+
+static inline void io_release_dmabuf(void *priv)
+{
+ struct io_buf_dma *bd = priv;
+
+ fput(bd->target_file);
+ dma_buf_io_ctx_release(bd->ctx);
+ kfree(bd);
+}
+
+int __io_register_dmabuf(struct io_ring_ctx *ctx,
+ struct io_uring_regbuf_desc *desc,
+ struct io_mapped_ubuf *imu)
+{
+ struct io_buf_dma *bd = NULL;
+ struct file *target_file = NULL;
+ 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)
+ return -EINVAL;
+
+ bd = kzalloc(sizeof(*bd), GFP_KERNEL);
+ if (!bd)
+ return -ENOMEM;
+
+ target_file = fget(desc->target_fd);
+ if (!target_file) {
+ ret = -EBADF;
+ goto err;
+ }
+ dmabuf = dma_buf_get(desc->dmabuf_fd);
+ if (IS_ERR(dmabuf)) {
+ ret = PTR_ERR(dmabuf);
+ dmabuf = NULL;
+ goto err;
+ }
+ ret = io_validate_user_buf_range(0, dmabuf->size);
+ if (ret)
+ goto err;
+
+ ret = dma_buf_io_ctx_create(target_file, dmabuf, DMA_BIDIRECTIONAL,
+ &bd->ctx);
+ if (ret)
+ goto err;
+
+ bd->target_file = target_file;
+ imu->len = dmabuf->size;
+ imu->release = io_release_dmabuf;
+ imu->priv = bd;
+ imu->flags = IO_REGBUF_F_DMABUF;
+ imu->dir = IO_BUF_DEST | IO_BUF_SOURCE;
+ dma_buf_put(dmabuf);
+ return 0;
+err:
+ kfree(bd);
+ if (target_file)
+ fput(target_file);
+ if (dmabuf)
+ dma_buf_put(dmabuf);
+ return ret;
+}
+
diff --git a/io_uring/dma-buf.h b/io_uring/dma-buf.h
new file mode 100644
index 000000000000..534c06b6879f
--- /dev/null
+++ b/io_uring/dma-buf.h
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef IOU_DMA_BUF_H
+#define IOU_DMA_BUF_H
+
+#include <linux/dma-buf-io.h>
+#include <linux/io_uring_types.h>
+
+#include "rsrc.h"
+
+struct io_buf_dma {
+ struct dma_buf_io_ctx *ctx;
+ struct file *target_file;
+};
+
+int __io_register_dmabuf(struct io_ring_ctx *ctx,
+ struct io_uring_regbuf_desc *desc,
+ struct io_mapped_ubuf *imu);
+
+static inline void io_detach_dmabuf_map(struct io_kiocb *req)
+{
+ if (!IS_ENABLED(CONFIG_DMA_SHARED_BUFFER))
+ return;
+ if (!(req->flags & REQ_F_DMABUF) || !req->dmabuf_map)
+ return;
+ dma_buf_io_map_drop(req->dmabuf_map);
+ req->dmabuf_map = NULL;
+}
+
+static inline int io_attach_dmabuf_map(struct io_kiocb *req,
+ struct iov_iter *iter,
+ unsigned issue_flags)
+{
+ bool nowait = issue_flags & IO_URING_F_NONBLOCK;
+ struct dma_buf_io_map *map;
+ struct io_buf_dma *bd;
+
+ if (!(req->flags & REQ_F_DMABUF))
+ return 0;
+ if (!IS_ENABLED(CONFIG_DMA_SHARED_BUFFER))
+ return -EOPNOTSUPP;
+
+ bd = req->buf_node->buf->priv;
+ map = dma_buf_io_get_map(bd->ctx, nowait);
+ if (unlikely(IS_ERR(map)))
+ return PTR_ERR(map);
+ req->dmabuf_map = map;
+ iter->dmabuf_map = map;
+ return 0;
+}
+
+static inline int io_import_dmabuf_map(struct io_kiocb *req,
+ int ddir, struct iov_iter *iter,
+ struct io_mapped_ubuf *imu,
+ size_t len, size_t offset)
+{
+ struct io_buf_dma *bd = imu->priv;
+
+ if (!IS_ENABLED(CONFIG_DMA_SHARED_BUFFER))
+ return -EOPNOTSUPP;
+ if (req->file != bd->target_file)
+ return -EBADF;
+ req->flags |= REQ_F_DMABUF;
+ iov_iter_dmabuf_map(iter, ddir, NULL, offset, len);
+ return 0;
+}
+
+static inline int io_register_dmabuf(struct io_ring_ctx *ctx,
+ struct io_uring_regbuf_desc *desc,
+ struct io_mapped_ubuf *imu)
+{
+ if (!IS_ENABLED(CONFIG_DMA_SHARED_BUFFER))
+ return -EOPNOTSUPP;
+ return __io_register_dmabuf(ctx, desc, imu);
+}
+
+#endif /* IOU_DMA_BUF_H */
diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
index 1efaf29514e8..d64228b0e19e 100644
--- a/io_uring/rsrc.c
+++ b/io_uring/rsrc.c
@@ -10,6 +10,7 @@
#include <linux/compat.h>
#include <linux/io_uring.h>
#include <linux/io_uring/cmd.h>
+#include <linux/dma-buf-io.h>
#include <uapi/linux/io_uring.h>
@@ -19,6 +20,7 @@
#include "rsrc.h"
#include "memmap.h"
#include "register.h"
+#include "dma-buf.h"
struct io_rsrc_update {
struct file *file;
@@ -28,7 +30,7 @@ struct io_rsrc_update {
};
static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx,
- struct iovec *iov);
+ struct io_uring_regbuf_desc *desc);
static int hpage_acct_ref(struct io_ring_ctx *ctx, struct page *hpage,
bool *acct_new)
@@ -81,6 +83,18 @@ static bool hpage_acct_unref(struct io_ring_ctx *ctx, struct page *hpage)
#define IO_CACHED_BVECS_SEGS 32
+static void io_iov_to_regbuf_desc(const struct iovec *iov,
+ struct io_uring_regbuf_desc *desc)
+{
+ *desc = (struct io_uring_regbuf_desc) {
+ .type = IO_REGBUF_TYPE_UADDR,
+ .uaddr = (u64)(uintptr_t)iov->iov_base,
+ .size = iov->iov_len,
+ };
+ if (!desc->uaddr)
+ desc->type = IO_REGBUF_TYPE_EMPTY;
+}
+
int __io_account_mem(struct user_struct *user, unsigned long nr_pages)
{
unsigned long page_limit, cur_pages, new_pages;
@@ -326,6 +340,8 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
return -ENXIO;
if (up->offset + nr_args > ctx->file_table.data.nr)
return -EINVAL;
+ if (up->flags)
+ return -EINVAL;
for (done = 0; done < nr_args; done++) {
u64 tag = 0;
@@ -385,9 +401,8 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
struct io_uring_rsrc_update2 *up,
unsigned int nr_args)
{
+ bool extended = up->flags & IORING_RSRC_UPDATE_EXTENDED;
u64 __user *tags = u64_to_user_ptr(up->tags);
- struct iovec fast_iov, *iov;
- struct iovec __user *uvec;
u64 user_data = up->data;
__u32 done;
int i, err;
@@ -396,26 +411,49 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
return -ENXIO;
if (up->offset + nr_args > ctx->buf_table.nr)
return -EINVAL;
+ if (up->flags & ~IORING_RSRC_UPDATE_EXTENDED)
+ return -EINVAL;
for (done = 0; done < nr_args; done++) {
+ struct io_uring_regbuf_desc desc;
struct io_rsrc_node *node;
u64 tag = 0;
- uvec = u64_to_user_ptr(user_data);
- iov = iovec_from_user(uvec, 1, 1, &fast_iov, io_is_compat(ctx));
- if (IS_ERR(iov)) {
- err = PTR_ERR(iov);
- break;
- }
if (tags && copy_from_user(&tag, &tags[done], sizeof(tag))) {
err = -EFAULT;
break;
}
- node = io_sqe_buffer_register(ctx, iov);
+
+ if (extended) {
+ if (copy_from_user(&desc, u64_to_user_ptr(user_data),
+ sizeof(desc))) {
+ err = -EFAULT;
+ break;
+ }
+ user_data += sizeof(desc);
+ } else {
+ struct iovec __user *uvec = u64_to_user_ptr(user_data);
+ struct iovec fast_iov, *iov;
+
+ if (io_is_compat(ctx))
+ user_data += sizeof(struct compat_iovec);
+ else
+ user_data += sizeof(struct iovec);
+
+ iov = iovec_from_user(uvec, 1, 1, &fast_iov, io_is_compat(ctx));
+ if (IS_ERR(iov)) {
+ err = PTR_ERR(iov);
+ break;
+ }
+ io_iov_to_regbuf_desc(iov, &desc);
+ }
+
+ node = io_sqe_buffer_register(ctx, &desc);
if (IS_ERR(node)) {
err = PTR_ERR(node);
break;
}
+
if (tag) {
if (!node) {
err = -EINVAL;
@@ -426,10 +464,6 @@ static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
i = array_index_nospec(up->offset + done, ctx->buf_table.nr);
io_reset_rsrc_node(ctx, &ctx->buf_table, i);
ctx->buf_table.nodes[i] = node;
- if (io_is_compat(ctx))
- user_data += sizeof(struct compat_iovec);
- else
- user_data += sizeof(struct iovec);
}
return done ? done : err;
}
@@ -464,7 +498,7 @@ int io_register_files_update(struct io_ring_ctx *ctx, void __user *arg,
memset(&up, 0, sizeof(up));
if (copy_from_user(&up, arg, sizeof(struct io_uring_rsrc_update)))
return -EFAULT;
- if (up.resv || up.resv2)
+ if (up.resv2)
return -EINVAL;
return __io_register_rsrc_update(ctx, IORING_RSRC_FILE, &up, nr_args);
}
@@ -478,7 +512,7 @@ int io_register_rsrc_update(struct io_ring_ctx *ctx, void __user *arg,
return -EINVAL;
if (copy_from_user(&up, arg, sizeof(up)))
return -EFAULT;
- if (!up.nr || up.resv || up.resv2)
+ if (!up.nr || up.resv2)
return -EINVAL;
return __io_register_rsrc_update(ctx, type, &up, up.nr);
}
@@ -578,12 +612,9 @@ int io_files_update(struct io_kiocb *req, unsigned int issue_flags)
struct io_uring_rsrc_update2 up2;
int ret;
+ memset(&up2, 0, sizeof(up2));
up2.offset = up->offset;
up2.data = up->arg;
- up2.nr = 0;
- up2.tags = 0;
- up2.resv = 0;
- up2.resv2 = 0;
if (up->offset == IORING_FILE_INDEX_ALLOC) {
ret = io_files_update_with_index_alloc(req, issue_flags);
@@ -869,27 +900,72 @@ bool io_check_coalesce_buffer(struct page **page_array, int nr_pages,
return true;
}
+static struct io_rsrc_node *io_register_dmabuf_desc(struct io_ring_ctx *ctx,
+ struct io_uring_regbuf_desc *desc)
+{
+ struct io_rsrc_node *node = NULL;
+ struct io_mapped_ubuf *imu = NULL;
+ int ret;
+
+ node = io_rsrc_node_alloc(ctx, IORING_RSRC_BUFFER);
+ if (!node)
+ return ERR_PTR(-ENOMEM);
+
+ imu = io_alloc_imu(ctx, 0);
+ if (!imu) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ memset(imu, 0, sizeof(*imu));
+ refcount_set(&imu->refs, 1);
+
+ ret = io_register_dmabuf(ctx, desc, imu);
+ if (ret)
+ goto err;
+ node->buf = imu;
+ return node;
+err:
+ if (imu)
+ io_free_imu(ctx, imu);
+ if (node)
+ io_cache_free(&ctx->node_cache, node);
+ return ERR_PTR(ret);
+}
+
static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx,
- struct iovec *iov)
+ struct io_uring_regbuf_desc *desc)
{
+ unsigned long uaddr = (unsigned long)desc->uaddr;
+ size_t size = desc->size;
struct io_mapped_ubuf *imu = NULL;
struct page **pages = NULL;
struct io_rsrc_node *node;
unsigned long off;
- size_t size;
int ret, nr_pages, i;
struct io_imu_folio_data data;
bool coalesced = false;
- if (!iov->iov_base) {
- if (iov->iov_len)
+ if (uaddr != desc->uaddr || size != desc->size)
+ return ERR_PTR(-EOVERFLOW);
+ if (desc->type >= __IO_REGBUF_TYPE_MAX)
+ return ERR_PTR(-EINVAL);
+ if (!mem_is_zero(&desc->__resv, sizeof(desc->__resv)) || desc->flags)
+ return ERR_PTR(-EINVAL);
+
+ if (desc->type == IO_REGBUF_TYPE_DMABUF)
+ return io_register_dmabuf_desc(ctx, desc);
+
+ if (desc->dmabuf_fd || desc->target_fd)
+ return ERR_PTR(-EINVAL);
+
+ if (desc->type == IO_REGBUF_TYPE_EMPTY) {
+ if (uaddr || size)
return ERR_PTR(-EFAULT);
/* remove the buffer without installing a new one */
return NULL;
}
- ret = io_validate_user_buf_range((unsigned long)iov->iov_base,
- iov->iov_len);
+ ret = io_validate_user_buf_range(uaddr, size);
if (ret)
return ERR_PTR(ret);
@@ -898,8 +974,7 @@ static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx,
return ERR_PTR(-ENOMEM);
ret = -ENOMEM;
- pages = io_pin_pages((unsigned long) iov->iov_base, iov->iov_len,
- &nr_pages);
+ pages = io_pin_pages(uaddr, size, &nr_pages);
if (IS_ERR(pages)) {
ret = PTR_ERR(pages);
pages = NULL;
@@ -921,10 +996,9 @@ static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx,
if (ret)
goto done;
- size = iov->iov_len;
/* store original address for later verification */
- imu->ubuf = (unsigned long) iov->iov_base;
- imu->len = iov->iov_len;
+ imu->ubuf = uaddr;
+ imu->len = size;
imu->folio_shift = PAGE_SHIFT;
imu->release = io_release_ubuf;
imu->priv = imu;
@@ -934,7 +1008,7 @@ static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx,
imu->folio_shift = data.folio_shift;
refcount_set(&imu->refs, 1);
- off = (unsigned long)iov->iov_base & ~PAGE_MASK;
+ off = uaddr & ~PAGE_MASK;
if (coalesced)
off += data.first_folio_page_idx << PAGE_SHIFT;
@@ -986,6 +1060,7 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
memset(iov, 0, sizeof(*iov));
for (i = 0; i < nr_args; i++) {
+ struct io_uring_regbuf_desc desc;
struct io_rsrc_node *node;
u64 tag = 0;
@@ -1009,7 +1084,8 @@ int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
}
}
- node = io_sqe_buffer_register(ctx, iov);
+ io_iov_to_regbuf_desc(iov, &desc);
+ node = io_sqe_buffer_register(ctx, &desc);
if (IS_ERR(node)) {
ret = PTR_ERR(node);
break;
@@ -1206,9 +1282,12 @@ static int io_import_kbuf(int ddir, struct iov_iter *iter,
return 0;
}
-static int io_import_fixed(int ddir, struct iov_iter *iter,
+static int io_import_fixed(struct io_kiocb *req,
+ int ddir, struct iov_iter *iter,
struct io_mapped_ubuf *imu,
- u64 buf_addr, size_t len)
+ u64 buf_addr, size_t len,
+ unsigned issue_flags,
+ unsigned import_flags)
{
const struct bio_vec *bvec;
size_t folio_mask;
@@ -1228,6 +1307,11 @@ static int io_import_fixed(int ddir, struct iov_iter *iter,
offset = buf_addr - imu->ubuf;
+ if (imu->flags & IO_REGBUF_F_DMABUF) {
+ if (!(import_flags & IO_REGBUF_IMPORT_ALLOW_DMABUF))
+ return -EFAULT;
+ return io_import_dmabuf_map(req, ddir, iter, imu, len, offset);
+ }
if (imu->flags & IO_REGBUF_F_KBUF)
return io_import_kbuf(ddir, iter, imu, len, offset);
@@ -1281,16 +1365,17 @@ inline struct io_rsrc_node *io_find_buf_node(struct io_kiocb *req,
return NULL;
}
-int io_import_reg_buf(struct io_kiocb *req, struct iov_iter *iter,
+int __io_import_reg_buf(struct io_kiocb *req, struct iov_iter *iter,
u64 buf_addr, size_t len, int ddir,
- unsigned issue_flags)
+ unsigned issue_flags, unsigned import_flags)
{
struct io_rsrc_node *node;
node = io_find_buf_node(req, issue_flags);
if (!node)
return -EFAULT;
- return io_import_fixed(ddir, iter, node->buf, buf_addr, len);
+ return io_import_fixed(req, ddir, iter, node->buf, buf_addr, len,
+ issue_flags, import_flags);
}
static int io_buffer_acct_cloned_hpages(struct io_ring_ctx *ctx,
@@ -1422,6 +1507,13 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx
if (!src_node) {
dst_node = NULL;
} else {
+ /* 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;
+ }
+
dst_node = io_rsrc_node_alloc(ctx, IORING_RSRC_BUFFER);
if (!dst_node) {
io_rsrc_data_free(ctx, &data);
@@ -1692,9 +1784,9 @@ static int io_kern_bvec_size(struct iovec *iov, unsigned nr_iovs,
return 0;
}
-int io_import_reg_vec(int ddir, struct iov_iter *iter,
+int __io_import_reg_vec(int ddir, struct iov_iter *iter,
struct io_kiocb *req, struct iou_vec *vec,
- unsigned nr_iovs, unsigned issue_flags)
+ unsigned nr_iovs, unsigned issue_flags, unsigned import_flags)
{
struct io_rsrc_node *node;
struct io_mapped_ubuf *imu;
@@ -1712,7 +1804,9 @@ int io_import_reg_vec(int ddir, struct iov_iter *iter,
iovec_off = vec->nr - nr_iovs;
iov = vec->iovec + iovec_off;
- if (imu->flags & IO_REGBUF_F_KBUF) {
+ if (imu->flags & IO_REGBUF_F_DMABUF) {
+ return -EOPNOTSUPP;
+ } else if (imu->flags & IO_REGBUF_F_KBUF) {
int ret = io_kern_bvec_size(iov, nr_iovs, imu, &nr_segs);
if (unlikely(ret))
diff --git a/io_uring/rsrc.h b/io_uring/rsrc.h
index 9ef88383b363..418d236152ff 100644
--- a/io_uring/rsrc.h
+++ b/io_uring/rsrc.h
@@ -26,7 +26,12 @@ struct io_rsrc_node {
};
enum {
- IO_REGBUF_F_KBUF = 1,
+ IO_REGBUF_F_KBUF = 1 << 0,
+ IO_REGBUF_F_DMABUF = 1 << 1,
+};
+
+enum {
+ IO_REGBUF_IMPORT_ALLOW_DMABUF = 1 << 1,
};
struct io_mapped_ubuf {
@@ -61,12 +66,28 @@ int io_rsrc_data_alloc(struct io_rsrc_data *data, unsigned nr);
struct io_rsrc_node *io_find_buf_node(struct io_kiocb *req,
unsigned issue_flags);
-int io_import_reg_buf(struct io_kiocb *req, struct iov_iter *iter,
+int __io_import_reg_buf(struct io_kiocb *req, struct iov_iter *iter,
u64 buf_addr, size_t len, int ddir,
- unsigned issue_flags);
-int io_import_reg_vec(int ddir, struct iov_iter *iter,
+ unsigned issue_flags, unsigned import_flags);
+int __io_import_reg_vec(int ddir, struct iov_iter *iter,
struct io_kiocb *req, struct iou_vec *vec,
- unsigned nr_iovs, unsigned issue_flags);
+ unsigned nr_iovs, unsigned issue_flags,
+ unsigned import_flags);
+
+static inline int io_import_reg_buf(struct io_kiocb *req, struct iov_iter *iter,
+ u64 buf_addr, size_t len, int ddir,
+ unsigned issue_flags)
+{
+ return __io_import_reg_buf(req, iter, buf_addr, len, ddir, issue_flags, 0);
+}
+
+static inline int io_import_reg_vec(int ddir, struct iov_iter *iter,
+ struct io_kiocb *req, struct iou_vec *vec,
+ unsigned nr_iovs, unsigned issue_flags)
+{
+ return __io_import_reg_vec(ddir, iter, req, vec, nr_iovs, issue_flags, 0);
+}
+
int io_prep_reg_iovec(struct io_kiocb *req, struct iou_vec *iv,
const struct iovec __user *uvec, size_t uvec_segs);
diff --git a/io_uring/rw.c b/io_uring/rw.c
index 61bd0641dd77..3a8559ff4dc6 100644
--- a/io_uring/rw.c
+++ b/io_uring/rw.c
@@ -23,6 +23,7 @@
#include "rsrc.h"
#include "poll.h"
#include "rw.h"
+#include "dma-buf.h"
static void io_complete_rw(struct kiocb *kiocb, long res);
static void io_complete_rw_iopoll(struct kiocb *kiocb, long res);
@@ -358,13 +359,18 @@ static int io_init_rw_fixed(struct io_kiocb *req, unsigned int issue_flags,
struct io_async_rw *io = req->async_data;
int ret;
- if (io->bytes_done)
- return 0;
+ if (!io->bytes_done) {
+ ret = __io_import_reg_buf(req, &io->iter, rw->addr, rw->len, ddir,
+ issue_flags, IO_REGBUF_IMPORT_ALLOW_DMABUF);
+ if (ret)
+ return ret;
+ iov_iter_save_state(&io->iter, &io->iter_state);
+ }
- ret = io_import_reg_buf(req, &io->iter, rw->addr, rw->len, ddir,
- issue_flags);
- iov_iter_save_state(&io->iter, &io->iter_state);
- return ret;
+ ret = io_attach_dmabuf_map(req, &io->iter, issue_flags);
+ if (ret)
+ return ret;
+ return 0;
}
int io_prep_read_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe)
@@ -577,6 +583,8 @@ static void io_complete_rw(struct kiocb *kiocb, long res)
struct io_rw *rw = container_of(kiocb, struct io_rw, kiocb);
struct io_kiocb *req = cmd_to_io_kiocb(rw);
+ io_detach_dmabuf_map(req);
+
/* ring owner may block in freeze_super() before task_work runs */
if (kiocb->ki_flags & IOCB_WRITE)
io_req_end_write(req);
@@ -680,7 +688,7 @@ static ssize_t loop_rw_iter(int ddir, struct io_rw *rw, struct iov_iter *iter)
!(kiocb->ki_filp->f_flags & O_NONBLOCK))
return -EAGAIN;
if ((req->flags & REQ_F_BUF_NODE) &&
- (req->buf_node->buf->flags & IO_REGBUF_F_KBUF))
+ (req->buf_node->buf->flags & (IO_REGBUF_F_KBUF|IO_REGBUF_F_DMABUF)))
return -EFAULT;
ppos = io_kiocb_ppos(kiocb);
@@ -1208,7 +1216,10 @@ int io_read_fixed(struct io_kiocb *req, unsigned int issue_flags)
if (unlikely(ret))
return ret;
- return io_read(req, issue_flags);
+ ret = io_read(req, issue_flags);
+ if (ret != -EIOCBQUEUED)
+ io_detach_dmabuf_map(req);
+ return ret;
}
int io_write_fixed(struct io_kiocb *req, unsigned int issue_flags)
@@ -1219,7 +1230,11 @@ int io_write_fixed(struct io_kiocb *req, unsigned int issue_flags)
if (unlikely(ret))
return ret;
- return io_write(req, issue_flags);
+ ret = io_write(req, issue_flags);
+ if (ret != -EIOCBQUEUED)
+ io_detach_dmabuf_map(req);
+ return ret;
+
}
void io_rw_fail(struct io_kiocb *req)