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>
This commit is contained in:
Dylan Yudaken 2026-06-07 08:31:54 +01:00 committed by Anna Schumaker
parent 1d62e659c0
commit e3a7802944
2 changed files with 42 additions and 0 deletions

View File

@ -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)

View File

@ -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