From: Jeff Layton <jlayton@kernel.org>
To: Mike Snitzer <snitzer@kernel.org>,
Matthew Wilcox <willy@infradead.org>,
linux-mm@kvack.org, linux-fsdevel@vger.kernel.org
Cc: Chuck Lever <cel@kernel.org>,
linux-nfs@vger.kernel.org, NeilBrown <neil@brown.name>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>,
Christoph Hellwig <hch@lst.de>, Jens Axboe <axboe@kernel.dk>,
Jonathan Corbet <corbet@lwn.net>
Subject: Re: [PATCH v9 0/6] mm, iomap, NFSD: stop uncached writes reading back shared pages
Date: Tue, 27 Oct 2026 10:31:58 -0400 [thread overview]
Message-ID: <fc2ea8d6f2cd9ae83d38941f90386aac6638a497.camel@kernel.org> (raw)
In-Reply-To: <20261024221152.6965-1-snitzer@kernel.org>
On Sat, 2026-10-24 at 18:11 -0400, Mike Snitzer wrote:
> Hi,
>
> Please consider this v9 for the v7.5 development cycle, so that it can
> go upstream in the v7.5 merge window.
>
> An uncached (RWF_DONTCACHE) buffered write drops each page it writes
> once that page is written back. A page the write covers only partly is
> shared with the neighbouring write. Once the first of the two is
> written back, the second reads the page back from disk before it writes
> its part. 32 threads wrote interleaved records to one file on
> XFS (emulated 4Kn NVMe, 4 KiB pages). Before and after 4/6:
>
> record pwritev2() flags 4 KiB device MiB/s
> bytes reads per write
> before after before after
> 47008 RWF_DONTCACHE 0.97 0.0005 831 2281
> 47008 RWF_DONTCACHE|RWF_DSYNC 0.99 0.0005 601 1227
> 6000 RWF_DONTCACHE 0.97 0.0001 121 488
> 6000 RWF_DONTCACHE|RWF_DSYNC 0.99 0.0002 90 206
>
> What is left after is metadata. 49152-byte records cover only whole
> pages, and they read 0.0005 per write either way. The test program and
> script that produced this table, and how to run them, are in:
> https://lore.kernel.org/linux-nfs/atqJBS8MlYfeUU-t@kernel.org/
>
> 4/6 has the page cache keep such a page for the write that completes
> it. 5/6 lets a writer that syncs its own write complete those pages
> itself once the sync is done. NFSD does that for a stable WRITE. 6/6
> is the NFSD change that uses it. 2/6 reports the DONTCACHE dirty count
> in the bdi debugfs stats. 3/6 adds folio_mark_dropbehind(), which 4/6
> and 5/6 use.
>
> 1/6 fixes 88d6f128d06d ("mm: track DONTCACHE dirty pages per
> bdi_writeback"), in v7.3. A cached lookup that clears the dropbehind
> flag could uncount a folio that was never counted. It could also leave
> a folio counted with nothing to uncount it. The patch applies to v7.3
> as it is, if the mm side would rather take it alone.
>
> v8 1/7 is not in this series. As Chuck asked, I post it on its own. It
> is a revised version of 80728157d1bd ("NFSD: cut a misaligned
> direct-mode WRITE at page boundaries") in cel/nfsd-testing. This series
> applies on cel/nfsd-testing at 6d13b7f74eec ("NFSD: Map every
> NFS_ACLv2 reply status into aclstat2"), with or without that revision.
> Each patch builds with W=1 with no warnings.
>
> 1/6 to 5/6 are mm, with small iomap changes in 4/6 and 5/6. They are
> Cc'd to linux-mm and linux-fsdevel. If the mm and iomap maintainers
> are agreeable, their acks would let Chuck take the series through the
> nfsd tree. But whatever approach the maintainers prefer for this kind
> of cross-subsystem merge is obviously fine.
>
> Changes since v8, from two independent sashiko reviews of v8: the one
> Jeff Layton relayed, and the one that sashiko-bot posted to linux-mm.
> Some findings were in both.
> - 1/6 and 3/6 (both reviews): a folio is counted in WB_DONTCACHE_DIRTY
> only when both PG_dirty and its dirty tag are set. v8 tested the tag
> alone. __folio_cancel_dirty() clears PG_dirty but leaves the tag, and
> so does writeback that stops at EOF after folio_clear_dirty_for_io().
> A folio that stays cached then keeps a stale tag. 1/6 uncounted such
> a folio twice, and 3/6 counted it and never uncounted it.
> - 4/6, 5/6 and 6/6 (second review): with blocks smaller than the folio,
> iomap tracks uptodate per block. The edge that a write completes is
> then not uptodate when the write finds it, so it was never marked and
> stayed cached until reclaim. This happens with 4 KiB blocks on 16 or
> 64 KiB pages. The new folio_dontcache_edge_written() also accepts a
> folio whose blocks outside this write are uptodate.
> filemap_dontcache_edge_completes() takes the range that the write
> covers, and 6/6 passes it.
> - 5/6 (second review): filemap_dontcache_edge_complete() now waits for
> writeback in flight, which could not drop the folio. It also kicks
> DONTCACHE writeback when it marks a dirty folio. The earlier kick
> came before the mark. It drops a clean folio that is not mapped
> without a mark. A mark that filemap_end_dropbehind() then cleared
> outside the i_pages lock could leave WB_DONTCACHE_DIRTY counted.
> - 6/6 (both reviews): NFSD finds the edges that a buffered segment
> shares by the mapping's smallest folio, as iomap does, not by page.
> On 16 KiB blocks, a WRITE written as one buffered segment can have
> page-aligned ends inside a block. Nothing completed those edges.
> NFSD also completes a segment's first edge only when the write
> reached the end of the segment's bytes in that unit (first review).
> - 4/6 (first review): a paragraph on a limit. 4/6 marks the folio
> before iomap validates the iomap. A stale iomap stopped by a fatal
> signal then leaves a mark on a folio that this write did not complete.
> This costs one read-back and no data.
> - 2/6: unchanged.
>
> Patches 1, 3, 4, 5 and 6 carry notes below the --- line. The notes
> give each question from the v8 reviews, and the code, lock or check
> that answers it. This includes the limits that the series keeps on
> purpose.
>
> Before posting, I ran a third review of v9 locally, with Sashiko's
> review stages and the review prompts it uses. It found no new
> problems.
>
> Measured for 6/6 on 16 KiB-block XFS over the loop device. Its
> dma_alignment is 511, so every TCP payload is memory-misaligned and
> NFSD writes each WRITE as one buffered segment. 32 writers of 12288-byte
> records, 1 GiB: v8 left all 32,736 pages of a 128 MiB file resident.
> v9 leaves 948 of 262,080 pages (0.4%) and reads 0.0003 blocks per
> record. The v8 results hold. In every run BdiDontcacheDirty was 0
> after the final sync. That includes runs that mix uncached writes,
> cached writes and mmap stores on one file. Every record verified.
>
> I measured all of v9 again on 4 KiB pages, with XFS blocks of 1 KiB
> and 2 KiB over the loop device. These blocks are smaller than the page.
> 32 writers wrote 47008-byte records, 1 GiB. Uncached application writes
> left 0 of 261,850 pages resident. NFSD left 497 (1 KiB blocks) and 349
> (2 KiB blocks). LOCALIO left 854 and 949. Every path read 0.0001
> blocks per record. A kernel without these fixes, on a 128 MiB run with
> 1 KiB blocks, left about one page for every two records. Uncached
> writes through NFSD, cached writes and mmap stores ran together on one
> file, with 4 KiB and 1 KiB blocks. BdiDontcacheDirty was 0 after every
> round, and every record verified. I did not test kernels with 16 KiB
> or 64 KiB pages.
>
> v8: https://lore.kernel.org/linux-nfs/20261023024548.71123-1-snitzer@kernel.org/
> v7: https://lore.kernel.org/linux-nfs/20261020220346.28020-1-snitzer@kernel.org/
> v6: https://lore.kernel.org/linux-nfs/atbfEbgMU6UGkn2X@kernel.org/
> v5: https://lore.kernel.org/linux-nfs/20261019150725.1507-1-snitzer@kernel.org/
> v4: https://lore.kernel.org/linux-nfs/20261015233309.42999-1-snitzer@kernel.org/
> v3: https://lore.kernel.org/linux-nfs/20261001045502.48381-1-snitzer@kernel.org/
> v2: https://lore.kernel.org/linux-nfs/20260929231329.22018-1-snitzer@kernel.org/
> v1: https://lore.kernel.org/linux-nfs/20260929173423.16149-1-snitzer@kernel.org/
>
> Thanks,
> Mike
>
> Mike Snitzer (6):
> mm: take a folio off WB_DONTCACHE_DIRTY only if it was counted there
> mm: expose WB_DONTCACHE_DIRTY in bdi debugfs stats
> mm: add folio_mark_dropbehind() to mark a folio dropbehind and account it
> mm, iomap: keep a partly covered page until an uncached write completes it
> mm, iomap: let an uncached writer complete its shared pages itself
> NFSD: drop a shared boundary page only once both WRITEs have written it
>
>
> .../filesystems/nfs/nfsd-io-modes.rst | 17 ++
> fs/iomap/buffered-io.c | 36 ++-
> fs/iomap/trace.h | 3 +-
> fs/nfsd/vfs.c | 116 +++++++-
> include/linux/fs.h | 8 +-
> include/linux/iomap.h | 1 +
> include/linux/pagemap.h | 14 +
> mm/backing-dev.c | 6 +
> mm/filemap.c | 265 +++++++++++++++++-
> 9 files changed, 435 insertions(+), 31 deletions(-)
>
>
> base-commit: 6d13b7f74eec16e08d5e7f772ee119432a14ef2c
This all looks good to me at this point. This is a mixed mm and nfsd
set though. How do you envision this being merged?
Reviewed-by: Jeff Layton <jlayton@kernel.org>
next prev parent reply other threads:[~2026-10-27 14:32 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-24 22:11 [PATCH v9 0/6] mm, iomap, NFSD: stop uncached writes reading back shared pages Mike Snitzer
2026-10-24 22:11 ` [PATCH v9 1/6] mm: take a folio off WB_DONTCACHE_DIRTY only if it was counted there Mike Snitzer
2026-10-24 22:11 ` [PATCH v9 2/6] mm: expose WB_DONTCACHE_DIRTY in bdi debugfs stats Mike Snitzer
2026-10-24 22:11 ` [PATCH v9 3/6] mm: add folio_mark_dropbehind() to mark a folio dropbehind and account it Mike Snitzer
2026-10-24 22:11 ` [PATCH v9 4/6] mm, iomap: keep a partly covered page until an uncached write completes it Mike Snitzer
2026-10-24 22:11 ` [PATCH v9 5/6] mm, iomap: let an uncached writer complete its shared pages itself Mike Snitzer
2026-10-24 22:11 ` [PATCH v9 6/6] NFSD: drop a shared boundary page only once both WRITEs have written it Mike Snitzer
2026-10-27 14:31 ` Jeff Layton [this message]
2026-10-27 15:36 ` [PATCH v9 0/6] mm, iomap, NFSD: stop uncached writes reading back shared pages Chuck Lever
2026-10-28 5:12 ` Mike Snitzer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fc2ea8d6f2cd9ae83d38941f90386aac6638a497.camel@kernel.org \
--to=jlayton@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=axboe@kernel.dk \
--cc=cel@kernel.org \
--cc=corbet@lwn.net \
--cc=hch@lst.de \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=snitzer@kernel.org \
--cc=tom@talpey.com \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox