diff options
| author | Dylan Yudaken <dyudaken@gmail.com> | 2026-06-07 10:31:54 +0300 |
|---|---|---|
| committer | Anna Schumaker <anna.schumaker@hammerspace.com> | 2026-06-08 19:07:16 +0300 |
| commit | e3a78029444777b7bb75693cfa8090b189e47cdc (patch) | |
| tree | 3f79e681289d3f72ed4722e83e95757f40a60bcc | |
| parent | 1d62e659c0bf11649cf48e002c2a55d148f2610a (diff) | |
| download | linux-e3a78029444777b7bb75693cfa8090b189e47cdc.tar.xz | |
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 <dyudaken@gmail.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
| -rw-r--r-- | fs/nfs/internal.h | 1 | ||||
| -rw-r--r-- | fs/nfs/io.c | 41 |
2 files changed, 42 insertions, 0 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 18d46b0e71dd..0c9aca624353 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 8337f0ae852d..2faf2003faf6 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 @@ -150,6 +160,37 @@ nfs_start_io_direct(struct inode *inode) } /** + * 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 * |
