[RFC 6/6] ext4: support dma-buf registered buffers for direct I/O
From: Mengmeng Zhao
Date: Thu Nov 05 2026 - 02:00:51 EST
From: Mengmeng Zhao <zhaomengmeng@xxxxxxxxxx>
Add the init_dma_buf_io_ctx fop for ext4 files. The data of every
regular file lives on the block device of the mount, so the buffer is
registered for that device and an ext4 file cannot move to another disk
after the registration.
A device mapping can only be read or written by a direct I/O bio.
Add a fast check at ext4_file_read_iter/ext4_file_write_iter entry.
Refuse the iterator for buffered I/O in the two dispatchers; the DAX
methods are covered by dax_iomap_rw() and direct I/O by the iomap and
block layer guards.
A direct I/O write whose tail still needs the page cache reports the
bytes the block layer already submitted instead of the error, as that
part cannot be undone and the remainder can never be copied.
Signed-off-by: Mengmeng Zhao <zhaomengmeng@xxxxxxxxxx>
Signed-off-by: Li Wang <liwang@xxxxxxxxxx>
---
fs/ext4/file.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 374b4bc25bd5..46629915fa84 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -139,6 +139,12 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
if (!iov_iter_count(to))
return 0; /* skip atime */
+ /* a device mapping can only be read by a direct I/O bio */
+ if (iov_iter_is_dmabuf_map(to) &&
+ (!(iocb->ki_flags & IOCB_DIRECT) ||
+ !ext4_should_use_dio(iocb, to)))
+ return -EOPNOTSUPP;
+
#ifdef CONFIG_FS_DAX
if (IS_DAX(inode))
return ext4_dax_read_iter(iocb, to);
@@ -670,6 +676,13 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
ssize_t err;
loff_t endbyte;
+ /*
+ * The page cache cannot copy from a device mapping. What
+ * direct I/O already submitted stands on its own.
+ */
+ if (iov_iter_is_dmabuf_map(from))
+ return ret > 0 ? ret : -EAGAIN;
+
/*
* There is no support for atomic writes on buffered-io yet,
* we should never fallback to buffered-io for DIO atomic
@@ -773,6 +786,12 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (unlikely(ret))
return ret;
+ /* a device mapping can only be written by a direct I/O bio */
+ if (iov_iter_is_dmabuf_map(from) &&
+ (!(iocb->ki_flags & IOCB_DIRECT) ||
+ !ext4_should_use_dio(iocb, from)))
+ return -EOPNOTSUPP;
+
#ifdef CONFIG_FS_DAX
if (IS_DAX(inode))
return ext4_dax_write_iter(iocb, from);
@@ -1032,10 +1051,24 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence)
return vfs_setpos(file, offset, maxbytes);
}
+/*
+ * The data of every regular file lives on the block device of the
+ * filesystem, so an ext4 file cannot move to another disk after the
+ * buffer has been registered.
+ */
+static int ext4_file_init_dma_buf_io_ctx(struct file *file,
+ struct dma_buf_io_ctx *ctx)
+{
+ return iomap_file_init_dma_buf_io_ctx(file,
+ file_inode(file)->i_sb->s_bdev,
+ ctx);
+}
+
const struct file_operations ext4_file_operations = {
.llseek = ext4_llseek,
.read_iter = ext4_file_read_iter,
.write_iter = ext4_file_write_iter,
+ .init_dma_buf_io_ctx = ext4_file_init_dma_buf_io_ctx,
.iopoll = iocb_bio_iopoll,
.unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
--
2.43.0