nfsd_write_dio_iters_init() cuts a misaligned end of a direct-mode WRITE at a multiple of the larger of offset_align and PAGE_SIZE, so that the direct middle, which invalidates the page cache over its range, never shares a page with a buffered end. But where the mapping's minimum folio order makes the smallest folio a block larger than a page, the page cache holds that block as one folio: an end cut on a page boundary inside a block leaves the middle and the buffered end in the same folio. The middle's invalidation then drops the folio the end wrote, and whichever of the two neighbouring WRITEs comes second reads the block back. Cut a misaligned end at a multiple of the smallest folio the mapping allows as well. Where that is a page, nothing changes. Fixes: 80728157d1bd ("NFSD: cut a misaligned direct-mode WRITE at page boundaries") Signed-off-by: Mike Snitzer --- fs/nfsd/vfs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 9219f8eb386d..ade00dabef18 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1452,13 +1452,15 @@ nfsd_write_dio_iters_init(struct svc_rqst *rqstp, struct svc_fh *fhp, /* * The direct middle invalidates the page cache over its range, so it - * must not share a page with a buffered end. An aligned end needs no - * buffered segment; a misaligned one is cut on a page boundary even - * where the offset alignment is finer than a page. A WRITE may end - * at OFFSET_MAX, so the prefix is sized as a distance rather than - * by rounding @offset up, which could wrap. + * must not share a folio with a buffered end. An aligned end needs no + * buffered segment; a misaligned one is cut on a boundary of the + * smallest folio the mapping allows, a page or, where the block is + * larger, a block, even where the offset alignment is finer. A WRITE + * may end at OFFSET_MAX, so the prefix is sized as a distance rather + * than by rounding @offset up, which could wrap. */ - cut = max_t(u32, offset_align, PAGE_SIZE); + cut = max3(offset_align, PAGE_SIZE, + mapping_min_folio_nrbytes(nf->nf_file->f_mapping)); prefix_end = offset; if (!IS_ALIGNED(offset, offset_align)) prefix_end += min_t(loff_t, cut - (offset & (cut - 1)), total); -- 2.52.0