NFS O_DIRECT reads already (mostly) handle async requests, with the exception of locking the inode for direct. Handle async requests properly by using nfs_start_io_direct_nowait, and then expose FMODE_NOWAIT since it's now supported for direct reads. Signed-off-by: Dylan Yudaken --- fs/nfs/direct.c | 12 ++++++++++-- fs/nfs/file.c | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 48d89716193a..e626c72495e6 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -466,14 +466,22 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter, goto out_release; } dreq->l_ctx = l_ctx; - if (!is_sync_kiocb(iocb)) + if (!is_sync_kiocb(iocb)) { dreq->iocb = iocb; + } else if (iocb->ki_flags & IOCB_NOWAIT) { + result = -EAGAIN; + nfs_direct_req_release(dreq); + goto out_release; + } if (user_backed_iter(iter)) dreq->flags = NFS_ODIRECT_SHOULD_DIRTY; if (!swap) { - result = nfs_start_io_direct(inode); + if (iocb->ki_flags & IOCB_NOWAIT) + result = nfs_start_io_direct_nowait(inode); + else + result = nfs_start_io_direct(inode); if (result) { /* release the reference that would usually be * consumed by nfs_direct_read_schedule_iovec() diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 25048a3c2364..a0d8f1c1cf10 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -72,8 +72,12 @@ nfs_file_open(struct inode *inode, struct file *filp) return res; res = nfs_open(inode, filp); - if (res == 0) + if (res == 0) { filp->f_mode |= FMODE_CAN_ODIRECT; + /* flag NOWAIT on read-only files only */ + if (!(filp->f_mode & FMODE_WRITE)) + filp->f_mode |= FMODE_NOWAIT; + } return res; } @@ -166,6 +170,10 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) if (iocb->ki_flags & IOCB_DIRECT) return nfs_file_direct_read(iocb, to, false); + /* NOWAIT only supported on direct reads */ + if (iocb->ki_flags & IOCB_NOWAIT) + return -EAGAIN; + dprintk("NFS: read(%pD2, %zu@%lu)\n", iocb->ki_filp, iov_iter_count(to), (unsigned long) iocb->ki_pos); @@ -705,6 +713,12 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) trace_nfs_file_write(iocb, from); + /* + * FMODE_NOWAIT is not set for writable files + */ + if (WARN_ON_ONCE(iocb->ki_flags & IOCB_NOWAIT)) + return -EAGAIN; + result = nfs_key_timeout_notify(file, inode); if (result) return result; -- 2.50.1