* [PATCH] nvme/io_uring: enable dma-buf backed passthrough I/O
@ 2026-10-16 10:34 Anuj Gupta
2026-10-16 10:41 ` Anuj gupta
2026-10-16 12:28 ` Christoph Hellwig
0 siblings, 2 replies; 3+ messages in thread
From: Anuj Gupta @ 2026-10-16 10:34 UTC (permalink / raw)
To: kbusch, hch, sagi, axboe
Cc: asml.silence, joshi.k, linux-nvme, linux-block, io-uring,
Anuj Gupta
From: Anuj Gupta <anuj20.g@samsung.com>
Allow registering a dma-buf against an NVMe namespace character device
and using it as the data buffer of fixed uring_cmd passthrough I/O.
io_uring_cmd_import_fixed() now accepts dma-buf buffers and attaches
the current map. blk_rq_map_user_iov() maps dma-buf iterators directly,
since they cannot fall back to a bounce copy.
Signed-off-by: Anuj Gupta <anuj20.g@samsung.com>
---
block/blk-map.c | 9 ++++++++-
drivers/nvme/host/core.c | 13 +++++++++++++
drivers/nvme/host/ioctl.c | 1 +
include/linux/io_uring/cmd.h | 6 ++++++
io_uring/uring_cmd.c | 16 +++++++++++++++-
5 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/block/blk-map.c b/block/blk-map.c
index 9cb9605d1f62..8f03e21fd5fe 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -459,7 +459,7 @@ int blk_rq_append_bio(struct request *rq, struct bio *bio)
}
EXPORT_SYMBOL(blk_rq_append_bio);
-/* Prepare bio for passthrough IO given ITER_BVEC iter */
+/* Prepare a bio for passthrough I/O from a directly mapped iterator. */
static int blk_rq_map_user_bvec(struct request *rq, const struct iov_iter *iter)
{
unsigned int max_bytes = rq->q->limits.max_hw_sectors << SECTOR_SHIFT;
@@ -506,6 +506,13 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
struct iov_iter i;
int ret = -EINVAL;
+ if (iov_iter_is_dmabuf_map(iter)) {
+ if (map_data || (iov_iter_alignment(iter) & align))
+ return -EINVAL;
+ ret = blk_rq_map_user_bvec(rq, iter);
+ return ret == -EREMOTEIO ? -EINVAL : ret;
+ }
+
if (map_data)
copy = true;
else if (iov_iter_alignment(iter) & align)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index d81462e864a4..29c29dad06b8 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3982,6 +3982,18 @@ static int nvme_ns_chr_release(struct inode *inode, struct file *file)
return 0;
}
+static int nvme_ns_chr_init_dma_buf_io_ctx(struct file *file,
+ struct dma_buf_io_ctx *ctx)
+{
+ struct nvme_ns *ns = container_of(file_inode(file)->i_cdev,
+ struct nvme_ns, cdev);
+ struct nvme_ctrl *ctrl = ns->ctrl;
+
+ if (!ctrl->ops->init_dma_buf_io_ctx)
+ return -EINVAL;
+ return ctrl->ops->init_dma_buf_io_ctx(ctrl, ctx);
+}
+
static const struct file_operations nvme_ns_chr_fops = {
.owner = THIS_MODULE,
.open = nvme_ns_chr_open,
@@ -3990,6 +4002,7 @@ static const struct file_operations nvme_ns_chr_fops = {
.compat_ioctl = compat_ptr_ioctl,
.uring_cmd = nvme_ns_chr_uring_cmd,
.uring_cmd_iopoll = nvme_ns_chr_uring_cmd_iopoll,
+ .init_dma_buf_io_ctx = nvme_ns_chr_init_dma_buf_io_ctx,
};
static void nvme_add_ns_cdev(struct nvme_ns *ns)
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index 3aa5d2f2dfbb..6343da1f6c05 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -458,6 +458,7 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
status = blk_status_to_errno(err);
}
io_uring_cmd_set_res32(ioucmd, status, result);
+ io_uring_cmd_detach_dmabuf(ioucmd);
/*
* For IOPOLL, check if this completion is happening in the context
diff --git a/include/linux/io_uring/cmd.h b/include/linux/io_uring/cmd.h
index e18d4af62e1a..33e0ebeea5a0 100644
--- a/include/linux/io_uring/cmd.h
+++ b/include/linux/io_uring/cmd.h
@@ -70,6 +70,7 @@ int io_uring_cmd_import_fixed_vec(struct io_uring_cmd *ioucmd,
size_t uvec_segs,
int ddir, struct iov_iter *iter,
unsigned issue_flags);
+void io_uring_cmd_detach_dmabuf(struct io_uring_cmd *ioucmd);
/*
* Completes the request, i.e. posts an io_uring CQE and deallocates @ioucmd
@@ -136,6 +137,11 @@ static inline int io_uring_cmd_import_fixed_vec(struct io_uring_cmd *ioucmd,
{
return -EOPNOTSUPP;
}
+
+static inline void io_uring_cmd_detach_dmabuf(struct io_uring_cmd *ioucmd)
+{
+}
+
static inline void __io_uring_cmd_done(struct io_uring_cmd *cmd,
unsigned issue_flags)
{
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
index 73b606899833..0e0509edec6f 100644
--- a/io_uring/uring_cmd.c
+++ b/io_uring/uring_cmd.c
@@ -10,6 +10,7 @@
#include "io_uring.h"
#include "alloc_cache.h"
+#include "dma-buf.h"
#include "rsrc.h"
#include "kbuf.h"
#include "uring_cmd.h"
@@ -28,6 +29,7 @@ static void io_req_uring_cleanup(struct io_kiocb *req, unsigned int issue_flags)
struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
struct io_async_cmd *ac = req->async_data;
+ io_detach_dmabuf_map(req);
if (issue_flags & IO_URING_F_UNLOCKED)
return;
@@ -48,6 +50,12 @@ void io_uring_cmd_cleanup(struct io_kiocb *req)
io_req_uring_cleanup(req, 0);
}
+void io_uring_cmd_detach_dmabuf(struct io_uring_cmd *ioucmd)
+{
+ io_detach_dmabuf_map(cmd_to_io_kiocb(ioucmd));
+}
+EXPORT_SYMBOL_GPL(io_uring_cmd_detach_dmabuf);
+
bool io_uring_try_cancel_uring_cmd(struct io_ring_ctx *ctx,
struct io_uring_task *tctx)
{
@@ -257,6 +265,7 @@ int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
ret = file->f_op->uring_cmd(ioucmd, issue_flags);
if (ret == -EAGAIN) {
+ io_detach_dmabuf_map(req);
ioucmd->flags |= IORING_URING_CMD_REISSUE;
return ret;
}
@@ -275,11 +284,16 @@ int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
unsigned int issue_flags)
{
struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
+ int ret;
if (WARN_ON_ONCE(!(ioucmd->flags & IORING_URING_CMD_FIXED)))
return -EINVAL;
- return io_import_reg_buf(req, iter, ubuf, len, rw, issue_flags);
+ ret = __io_import_reg_buf(req, iter, ubuf, len, rw, issue_flags,
+ IO_REGBUF_IMPORT_ALLOW_DMABUF);
+ if (ret)
+ return ret;
+ return io_attach_dmabuf_map(req, iter, issue_flags);
}
EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] nvme/io_uring: enable dma-buf backed passthrough I/O
2026-10-16 10:34 [PATCH] nvme/io_uring: enable dma-buf backed passthrough I/O Anuj Gupta
@ 2026-10-16 10:41 ` Anuj gupta
2026-10-16 12:28 ` Christoph Hellwig
1 sibling, 0 replies; 3+ messages in thread
From: Anuj gupta @ 2026-10-16 10:41 UTC (permalink / raw)
To: kbusch, hch, sagi, axboe
Cc: asml.silence, joshi.k, linux-nvme, linux-block, io-uring,
Anuj Gupta
I tested the dma-buf backed NVMe passthrough path with a liburing test,
available here:
https://github.com/anuj7781/liburing/tree/rw-dmabuf-pt
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] nvme/io_uring: enable dma-buf backed passthrough I/O
2026-10-16 10:34 [PATCH] nvme/io_uring: enable dma-buf backed passthrough I/O Anuj Gupta
2026-10-16 10:41 ` Anuj gupta
@ 2026-10-16 12:28 ` Christoph Hellwig
1 sibling, 0 replies; 3+ messages in thread
From: Christoph Hellwig @ 2026-10-16 12:28 UTC (permalink / raw)
To: Anuj Gupta
Cc: kbusch, hch, sagi, axboe, asml.silence, joshi.k, linux-nvme,
linux-block, io-uring, Anuj Gupta
On Fri, Oct 16, 2026 at 04:04:20PM +0530, Anuj Gupta wrote:
> From: Anuj Gupta <anuj20.g@samsung.com>
>
> Allow registering a dma-buf against an NVMe namespace character device
> and using it as the data buffer of fixed uring_cmd passthrough I/O.
>
> io_uring_cmd_import_fixed() now accepts dma-buf buffers and attaches
> the current map. blk_rq_map_user_iov() maps dma-buf iterators directly,
> since they cannot fall back to a bounce copy.
This really needs to be split into blk, io_uring and nvme parts, with
a good commit log for each part.
> +/* Prepare a bio for passthrough I/O from a directly mapped iterator. */
> static int blk_rq_map_user_bvec(struct request *rq, const struct iov_iter *iter)
And adding a comment to an otherwise unrelated function probably also
wants a comment..
> + if (iov_iter_is_dmabuf_map(iter)) {
> + if (map_data || (iov_iter_alignment(iter) & align))
> + return -EINVAL;
> + ret = blk_rq_map_user_bvec(rq, iter);
> + return ret == -EREMOTEIO ? -EINVAL : ret;
The error value remapping could probably also use a comment (and be
turned into an if to stand out).
> +static int nvme_ns_chr_init_dma_buf_io_ctx(struct file *file,
> + struct dma_buf_io_ctx *ctx)
> +{
> + struct nvme_ns *ns = container_of(file_inode(file)->i_cdev,
> + struct nvme_ns, cdev);
struct nvme_ns *ns =
> }
>
> +void io_uring_cmd_detach_dmabuf(struct io_uring_cmd *ioucmd)
> +{
> + io_detach_dmabuf_map(cmd_to_io_kiocb(ioucmd));
> +}
> +EXPORT_SYMBOL_GPL(io_uring_cmd_detach_dmabuf);
Add a comment on when this should be used?
> return -EINVAL;
>
> - return io_import_reg_buf(req, iter, ubuf, len, rw, issue_flags);
> + ret = __io_import_reg_buf(req, iter, ubuf, len, rw, issue_flags,
> + IO_REGBUF_IMPORT_ALLOW_DMABUF);
> + if (ret)
> + return ret;
> + return io_attach_dmabuf_map(req, iter, issue_flags);
No new here, but maybe io_import_reg_buf should take the flags argument
instead of the spurious __variant given how few users there are?
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-16 12:28 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-16 10:34 [PATCH] nvme/io_uring: enable dma-buf backed passthrough I/O Anuj Gupta
2026-10-16 10:41 ` Anuj gupta
2026-10-16 12:28 ` Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox