[PATCH 2/2] NFSD: Update the atime for iterator READs

From: Ameer Hamza

Date: Tue Aug 18 2026 - 18:57:42 EST


A READ served by nfsd_iter_read() or nfsd_direct_read() leaves the
atime update to the filesystem's ->read_iter, and not every
implementation does it: fuse_dax_read_iter() carries a TODO for
it, and kernfs_fop_read_iter() does not touch the atime at all. On
a fuse DAX export, READs never advance the atime, no matter how
often clients read the file. Spliced READs are not affected, since
splice_direct_to_actor() ends with file_accessed(). nfsd serves
whatever filesystem is exported, so it cannot rely on every
->read_iter keeping the convention.

Call file_accessed() after each successful vfs_iocb_iter_read().

Reported-by: Chuck Lever <cel@xxxxxxxxxx>
Closes: https://lore.kernel.org/linux-nfs/2ed0ee16-c20e-44bd-9e7a-f5b71764f14f@xxxxxxxxxxxxxxxx/
Fixes: 507df40ebf316 ("NFSD: Hoist rq_vec preparation into nfsd_read()")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ameer Hamza <ameer.hamza@xxxxxxxxxxx>
---
fs/nfsd/vfs.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index f45d4ad70b964..f017729cc1be0 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1144,6 +1144,9 @@ nfsd_direct_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (host_err >= 0) {
unsigned int pad = offset - dio_start;

+ /* Not every ->read_iter implementation updates the atime */
+ file_accessed(nf->nf_file);
+
/* The returned payload starts after the pad */
rqstp->rq_res.page_base = pad;

@@ -1229,6 +1232,9 @@ __be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
trace_nfsd_read_vector(rqstp, fhp, offset, *count - total);
iov_iter_bvec(&iter, ITER_DEST, rqstp->rq_bvec, v, *count - total);
host_err = vfs_iocb_iter_read(file, &kiocb, &iter);
+ /* Not every ->read_iter implementation updates the atime */
+ if (host_err >= 0)
+ file_accessed(file);
return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
}

--
2.53.0