nfsd_write_dio_iters_init() marks the DIO-aligned middle of a misaligned WRITE IOCB_DIRECT, and nfsd_direct_write() issues it that way. A file system may service that request with buffered I/O instead: xfs_file_write_iter() retries through xfs_file_buffered_write() with the same kiocb when xfs_file_dio_write() returns -ENOTBLK, which iomap_dio_rw() does when it cannot invalidate page cache overlapping the range. Since the previous commit, the middle of a split WRITE shares no page with the buffered ends of its neighbours, so a streaming misaligned WRITE workload no longer causes this by itself. It still happens whenever something dirties a page in the middle's range between its writeback and its invalidation without taking the lock the file system holds across a direct write: a local process writing the exported file through mmap, which XFS's IOLOCK does not keep out, or, on a file system that does not hold such a lock for the length of a direct write, an overlapping WRITE that is issued buffered as a whole (too small to split, or its payload misaligned in memory) or a local buffered writer. All of the middle, nearly the whole WRITE, is then re-issued as a cached buffered write that nothing ever drops. Set IOCB_DONTCACHE on the middle segment alongside IOCB_DIRECT when the file system supports FOP_DONTCACHE. The direct path ignores the flag; a buffered fallback now drops its pages once written back. Say so in nfsd-io-modes.rst. Fixes: 06c5c97293e3 ("NFSD: Implement NFSD_IO_DIRECT for NFS WRITE") Assisted-by: LLM Signed-off-by: Mike Snitzer --- Documentation/filesystems/nfs/nfsd-io-modes.rst | 4 ++++ fs/nfsd/vfs.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Documentation/filesystems/nfs/nfsd-io-modes.rst b/Documentation/filesystems/nfs/nfsd-io-modes.rst index 1916b2eee58ad..f9b63f1a33990 100644 --- a/Documentation/filesystems/nfs/nfsd-io-modes.rst +++ b/Documentation/filesystems/nfs/nfsd-io-modes.rst @@ -132,6 +132,10 @@ Misaligned WRITE: one; a start or end that is already DIO-aligned gets no buffered segment at all. If the filesystem supports FOP_DONTCACHE, the misaligned segments are marked DONTCACHE. + So is the O_DIRECT segment, where the flag has no effect unless the + filesystem services it with buffered IO instead, as XFS does when it + cannot invalidate page cache that overlaps the segment. The + iomap_dio_invalidate_fail trace event reports such a fallback. Tracing: The nfsd_read_direct trace event shows how NFSD expands any diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index ed5903c3becac..bd3dab36e2962 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1375,6 +1375,9 @@ nfsd_write_dio_iters_init(struct nfsd_file *nf, struct bio_vec *bvec, if (iov_iter_bvec_offset(&segments[nsegs].iter) & (mem_align - 1)) goto no_dio; segments[nsegs].flags |= IOCB_DIRECT; + /* In case the file system falls back to buffered I/O (-ENOTBLK). */ + if (nf->nf_file->f_op->fop_flags & FOP_DONTCACHE) + segments[nsegs].flags |= IOCB_DONTCACHE; nsegs++; if (suffix) -- 2.52.0