From: Dylan Yudaken Date: Sun, 7 Jun 2026 07:31:54 +0000 (+0100) Subject: nfs: add nowait version of nfs_start_io_direct X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e3a78029444777b7bb75693cfa8090b189e47cdc;p=thirdparty%2Flinux.git nfs: add nowait version of nfs_start_io_direct nfs_start_io_direct might block on existing operations to the same inode. In order to support NOWAIT O_DIRECT reads, add a non-blocking version of this nfs_start_io_direct that just returns -EAGAIN if locks could not be taken. Signed-off-by: Dylan Yudaken Signed-off-by: Anna Schumaker --- diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 18d46b0e71ddc..0c9aca624353a 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -532,6 +532,7 @@ extern void nfs_end_io_read(struct inode *inode); extern __must_check int nfs_start_io_write(struct inode *inode); extern void nfs_end_io_write(struct inode *inode); extern __must_check int nfs_start_io_direct(struct inode *inode); +extern __must_check int nfs_start_io_direct_nowait(struct inode *inode); extern void nfs_end_io_direct(struct inode *inode); static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi) diff --git a/fs/nfs/io.c b/fs/nfs/io.c index 8337f0ae852d4..2faf2003faf67 100644 --- a/fs/nfs/io.c +++ b/fs/nfs/io.c @@ -109,6 +109,16 @@ static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode) } } +static int nfs_block_buffered_nowait(struct nfs_inode *nfsi, struct inode *inode) +{ + if (!test_bit(NFS_INO_ODIRECT, &nfsi->flags)) { + if (inode->i_mapping->nrpages != 0) + return 1; + set_bit(NFS_INO_ODIRECT, &nfsi->flags); + } + return 0; +} + /** * nfs_start_io_direct - declare the file is being used for direct i/o * @inode: file inode @@ -149,6 +159,37 @@ nfs_start_io_direct(struct inode *inode) return 0; } +/** + * nfs_start_io_direct_nowait - non-blocking variant of nfs_start_io_direct() + * @inode: file inode + * + * Try to declare that a direct I/O operation is about to start without + * blocking. + * Ensure all buffered I/O is blocked. + * If this could not be done without blocking then returns -EAGAIN. + */ +int +nfs_start_io_direct_nowait(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + if (!down_read_trylock(&inode->i_rwsem)) + return -EAGAIN; + if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) + return 0; + up_read(&inode->i_rwsem); + + /* Slow path: try to flip NFS_INO_ODIRECT without blocking. */ + if (!down_write_trylock(&inode->i_rwsem)) + return -EAGAIN; + if (nfs_block_buffered_nowait(nfsi, inode)) { + up_write(&inode->i_rwsem); + return -EAGAIN; + } + downgrade_write(&inode->i_rwsem); + return 0; +} + /** * nfs_end_io_direct - declare that the direct i/o operation is done * @inode: file inode