From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=95.215.58.36 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794553744; b=UKHkfZi1Si3YaU+J8jri/xuT3UyyewYnEqLh+521orE6ORGxeuAjsUt2a8DySi28DL7X ShjostAlh34feOjPA6AW/QACRvTQf/CaJAvo5pUy/vbivm0WUaHFoi+rUF6EiPm4QU1Db 3x66sTq39MLYSuhB+aoti0DDpFj0TaMcJtDBTJDx5pCOewHsZaItc0o2XHYGLEtScE/Gl XLBVENv6rgUti8N1TJQJnMxzCR/GBG4fBa1W5Jlz2lLi/q7FKhBpViu0KTzva7Bb/SOW/ ll0KjmHyG6CHJ2cdosl4DrkzKyROblw3h7/NqwP5VJrm2qNFuPH/zTJ4ys/JcHQM63A== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794553744; h=DMARC-Filter:X-Envelope-To:DKIM-Signature:X-Envelope-To:Received: X-Mizu-Trace-ID:X-Migadu-Flow:From:To:Cc:Subject:Date:Message-ID: X-Mailer:In-Reply-To:References:MIME-Version: Content-Transfer-Encoding; bh=SYhdRBfbhOCrZODwMof2LJJutjMOsW3pk0k9wT+4x1s=; b=Sfl74LcznC0y2bM96/T5WVHm3xvWRa7ADUMiuqgMxQSdN6bUhPQ/AYncX0ubLSDoJz68 V8WWbnxL2VW6IWEVa0H8cr4Y+4WwZwCWhmrkXBl/C3lUYUjbXLwUeozbPN0c/EdnfrBnT BV4qgK9nIhx2odpceOvKatkVzM6i4dmYcM0WWXiaSdPUSx8a5caymwbi4nQM2y4wCAoT/ BqYvU6wbVzO4UUcNQnSJl8eeQMAW2JSAuz2jxeNALZ2FVigAsbbLuE1QT3nR1al9J36+t +uOw8TPP9nEQG1Koy0LyczE9IGeIpN9xVw0X9/5lmNYcnuY6ldgyK5MgBnhHRnetY/A== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass header.d=linux.dev header.i=@linux.dev header.a=rsa-sha256 header.s=key1 header.b=ih9I4ay6; arc=none smtp.remote-ip=95.215.58.36 Received: from mta1.migadu.com (out-36.mta1.migadu.com [95.215.58.36]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4D3C6606A888 for ; Fri, 13 Nov 2026 07:09:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 4D3C6606A888 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=linux.dev header.i=@linux.dev header.a=rsa-sha256 header.s=key1 header.b=ih9I4ay6 X-Envelope-To: linux-doc@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=ePA00gWH1MMaJNHfq4j4NnI+p0p7J/Mr89Hwy2EXwkk=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1794553741; v=1; x=1795158541; b=ih9I4ay6pugHf1ZtG7LXmd2hi+y1tBAXHtC2p5SLx0WqipipXVQ/e5zhWif0IHI/XAJOmv1R TmMC443IKltpaQIsebS52cfKO0QtKbK02x0Gta065tEJobXu8OWtbFGV485gLqqfnFQhMnBjO1h EnEdvlAw+4qKMmaYZVl8MG8w= X-Envelope-To: linux-doc@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id 60ee62a93959a5fb; Fri, 13 Nov 2026 07:08:57 +0000 X-Mizu-Trace-ID: 60ee62a93959a5fb X-Migadu-Flow: FLOW_OUT From: Mengmeng Zhao To: Christoph Hellwig , Anuj Gupta , Nitesh Shetty , Jens Axboe , Sumit Semwal , christian.koenig@amd.com, Philipp Stanner , Dan Williams , Matthew Wilcox , Jan Kara , Alexander Viro , Christian Brauner , tytso@mit.edu, Andreas Dilger , Baokun Li , Ojaswin Mujoo , "Ritesh Harjani (IBM)" , Zhang Yi , asml.silence@gmail.com, Jonathan Corbet , Shuah Khan , Randy Dunlap Cc: linux-block@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, nvdimm@lists.linux.dev, linux-ext4@vger.kernel.org, linux-xfs@vger.kernel.org, linux-doc@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, Li Wang , Mengmeng Zhao Subject: [RFC PATCH v2 8/8] ext4: support dma-buf registered buffers for direct I/O Date: Fri, 13 Nov 2026 15:06:21 +0800 Message-ID: <20261113070621.273953-9-mengmeng.zhao@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20261113070621.273953-1-mengmeng.zhao@linux.dev> References: <20261113070621.273953-1-mengmeng.zhao@linux.dev> X-Mailing-List: linux-doc@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Mengmeng Zhao Advertise FMODE_CAN_DMABUF_IO for inodes that can support dma-buf I/O and implement ->init_dma_buf_io_ctx() by registering the buffer against the filesystem's block device. The capability follows ext4_dio_alignment(), so an inode that can never do direct I/O - fs-verity, data=journal or inline data - is refused at open, and encrypted inodes are refused on the inode flag, which is set even without CONFIG_FS_ENCRYPTION. The inode is rechecked at registration because DAX can be enabled after the file was opened. A dma-buf iterator has no pages to copy from, so it must never reach the page cache. ext4_buffered_read_iter() and ext4_buffered_write_iter() are the single sinks of the buffered fallbacks and refuse it there; a short direct I/O write still reports its progress, and the DAX write path refuses at its entry instead of after starting a journal handle. Signed-off-by: Mengmeng Zhao Signed-off-by: Li Wang --- fs/ext4/ext4.h | 11 +++++++++++ fs/ext4/file.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index f38fec3167fb..028b2e5ddc8b 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -4135,6 +4135,17 @@ static inline bool ext4_inode_can_atomic_write(struct inode *inode) EXT4_SB(inode->i_sb)->s_awu_min > 0; } +/* + * dma-buf I/O needs an inode that supports direct I/O without the page cache. + * IS_ENCRYPTED() tests the inode flag, which is set even without + * CONFIG_FS_ENCRYPTION. + */ +static inline bool ext4_inode_can_dmabuf_io(struct inode *inode) +{ + return !IS_DAX(inode) && !IS_ENCRYPTED(inode) && + ext4_dio_alignment(inode) != 0; +} + extern int ext4_block_write_begin(handle_t *handle, struct folio *folio, loff_t pos, unsigned len, get_block_t *get_block); diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 50d3c92709c8..5a8481637da5 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "ext4.h" #include "ext4_jbd2.h" #include "xattr.h" @@ -66,6 +67,15 @@ static bool ext4_should_use_dio(struct kiocb *iocb, struct iov_iter *iter) return IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), dio_align); } +static ssize_t ext4_buffered_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + /* a dma-buf iterator has no pages for the page cache to copy into */ + if (iov_iter_is_dmabuf_map(to)) + return -EOPNOTSUPP; + + return generic_file_read_iter(iocb, to); +} + static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to) { ssize_t ret; @@ -88,7 +98,7 @@ static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to) * taken. */ iocb->ki_flags &= ~IOCB_DIRECT; - return generic_file_read_iter(iocb, to); + return ext4_buffered_read_iter(iocb, to); } ret = iomap_dio_read_simple(iocb, to, ext4_iomap_begin); @@ -119,7 +129,7 @@ static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to) if (!IS_DAX(inode)) { inode_unlock_shared(inode); /* Fallback to buffered IO in case we cannot support DAX */ - return generic_file_read_iter(iocb, to); + return ext4_buffered_read_iter(iocb, to); } ret = dax_iomap_rw(iocb, to, &ext4_iomap_ops); inode_unlock_shared(inode); @@ -146,7 +156,7 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to) if (iocb->ki_flags & IOCB_DIRECT) return ext4_dio_read_iter(iocb, to); - return generic_file_read_iter(iocb, to); + return ext4_buffered_read_iter(iocb, to); } static ssize_t ext4_file_splice_read(struct file *in, loff_t *ppos, @@ -354,6 +364,10 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb, if (iocb->ki_flags & IOCB_NOWAIT) return -EOPNOTSUPP; + /* a dma-buf iterator cannot be handled by buffered I/O */ + if (iov_iter_is_dmabuf_map(from)) + return -EOPNOTSUPP; + inode_lock(inode); /* @@ -688,6 +702,10 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) ssize_t err; loff_t endbyte; + /* a dma-buf iterator cannot fall back to buffered I/O */ + if (iov_iter_is_dmabuf_map(from)) + return ret; + /* * There is no support for atomic writes on buffered-io yet, * we should never fallback to buffered-io for DIO atomic @@ -731,6 +749,10 @@ ext4_dax_write_iter(struct kiocb *iocb, struct iov_iter *from) bool extend = false; struct inode *inode = file_inode(iocb->ki_filp); + /* a dma-buf iterator cannot be handled by DAX either */ + if (iov_iter_is_dmabuf_map(from)) + return -EOPNOTSUPP; + if (iocb->ki_flags & IOCB_NOWAIT) { if (!inode_trylock(inode)) return -EAGAIN; @@ -1014,6 +1036,8 @@ static int ext4_file_open(struct inode *inode, struct file *filp) filp->f_mode |= FMODE_CAN_ATOMIC_WRITE; filp->f_mode |= FMODE_NOWAIT | FMODE_CAN_ODIRECT; + if (ext4_inode_can_dmabuf_io(inode)) + filp->f_mode |= FMODE_CAN_DMABUF_IO; return dquot_file_open(inode, filp); } @@ -1050,10 +1074,24 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence) return vfs_setpos(file, offset, maxbytes); } +static int ext4_file_init_dma_buf_io_ctx(struct file *file, + struct dma_buf_io_ctx *ctx) +{ + struct inode *inode = file_inode(file); + + /* DAX can be enabled after the file was opened */ + if (!ext4_inode_can_dmabuf_io(inode)) + return -EOPNOTSUPP; + + /* all file data lives on s_bdev, which never changes for ext4 */ + return bdev_init_dma_buf_io_ctx(inode->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