From: Mike Snitzer <snitzer@kernel.org>
To: Matthew Wilcox <willy@infradead.org>,
linux-mm@kvack.org, linux-fsdevel@vger.kernel.org
Cc: Chuck Lever <cel@kernel.org>, Jeff Layton <jlayton@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: [PATCH v10 4/7] mm: add folio_mark_dropbehind() to mark a folio dropbehind and account it
Date: Tue, 3 Nov 2026 16:17:51 -0500 [thread overview]
Message-ID: <20261103211754.35352-5-snitzer@kernel.org> (raw)
In-Reply-To: <20261103211754.35352-1-snitzer@kernel.org>
WB_DONTCACHE_DIRTY counts the dirty folios that are marked dropbehind.
When a dropbehind folio is dirtied, folio_account_dirtied() adds it to
the counter. When the folio is cleaned, folio_clear_dirty_for_io() or
folio_account_cleaned() subtracts it again. This balances only if the
folio is marked before it is dirtied, as it is for the folios that an
RWF_DONTCACHE write creates.
To prepare for NFSD to mark a folio dropbehind once both writes that
share it have written their parts, handle a folio that is already dirty
when it is marked. folio_set_dropbehind() only sets the flag. With it,
the clean would subtract the folio from WB_DONTCACHE_DIRTY although it
was never added, and the counter would go negative.
Add folio_mark_dropbehind(), the inverse of filemap_clear_dropbehind().
With the folio locked, it sets PG_dropbehind. Under the i_pages lock,
it adds the folio to WB_DONTCACHE_DIRTY if both PG_dirty and the dirty
tag are set. A dirtier that has set PG_dirty but not yet counted the
folio finds the flag set and counts the folio itself.
The name follows folio_set_dirty() and folio_mark_dirty(): the set
variant only sets the flag, the mark variant also accounts for it.
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
---
Notes:
Notes on questions from earlier reviews, with the code that answers each:
- Counting rule. The same rule as filemap_clear_dropbehind() in
2/7: folio_mark_dropbehind() counts the folio only when
folio_test_dirty() and PAGECACHE_TAG_DIRTY are both true. The
test runs under the folio lock (VM_WARN_ON_ONCE_FOLIO checks it)
and the i_pages lock. A stale tag on a clean folio adds no count.
- Double count. A folio that has PG_dropbehind returns at the first
test, before it changes the count.
- No writeback. A mapping without writeback gets only the flag.
folio_account_dirtied() does not count such a folio either
(mapping_can_writeback()).
- Known window. As in 2/7: a stale tag together with an unlocked
dirtier that has set PG_dirty but not yet taken the i_pages lock
can make this count a folio that the dirtier then counts again.
Only the counter is affected.
include/linux/pagemap.h | 1 +
mm/filemap.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 73af18a373670..3f5295d6fd73b 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -1306,6 +1306,7 @@ void end_page_writeback(struct page *page);
void folio_end_writeback(struct folio *folio);
void folio_end_writeback_no_dropbehind(struct folio *folio);
void folio_end_dropbehind(struct folio *folio);
+void folio_mark_dropbehind(struct folio *folio);
void folio_wait_stable(struct folio *folio);
void __folio_mark_dirty(struct folio *folio, struct address_space *, int warn);
void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb);
diff --git a/mm/filemap.c b/mm/filemap.c
index 3a13289c07dc4..5134227ba3a23 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1643,6 +1643,38 @@ void folio_end_dropbehind(struct folio *folio)
}
EXPORT_SYMBOL_GPL(folio_end_dropbehind);
+/**
+ * folio_mark_dropbehind - mark an existing folio dropbehind
+ * @folio: the folio, locked by the caller
+ *
+ * Mark @folio so that the writeback that cleans it drops it. If the folio
+ * is already counted as dirty, which with the i_pages lock held means both
+ * PG_dirty and the dirty tag are set, add it to WB_DONTCACHE_DIRTY so that
+ * the clean that subtracts it leaves the counter balanced.
+ */
+void folio_mark_dropbehind(struct folio *folio)
+{
+ struct address_space *mapping = folio->mapping;
+ unsigned long flags;
+
+ VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio);
+
+ if (folio_test_dropbehind(folio))
+ return;
+ if (!mapping || !mapping_can_writeback(mapping)) {
+ folio_set_dropbehind(folio);
+ return;
+ }
+ xa_lock_irqsave(&mapping->i_pages, flags);
+ folio_set_dropbehind(folio);
+ if (folio_test_dirty(folio) &&
+ xa_get_mark(&mapping->i_pages, folio->index, PAGECACHE_TAG_DIRTY))
+ wb_stat_mod(inode_to_wb(mapping->host), WB_DONTCACHE_DIRTY,
+ folio_nr_pages(folio));
+ xa_unlock_irqrestore(&mapping->i_pages, flags);
+}
+EXPORT_SYMBOL_GPL(folio_mark_dropbehind);
+
/**
* folio_end_writeback_no_dropbehind - End writeback against a folio.
* @folio: The folio.
--
2.52.0
next prev parent reply other threads:[~2026-11-03 21:18 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 21:17 [PATCH v10 0/7] mm, iomap, NFSD: stop uncached writes reading back shared pages Mike Snitzer
2026-11-03 21:17 ` [PATCH v10 1/7] mm: move clearing the uncached flag of a found folio into a helper Mike Snitzer
2026-11-04 9:17 ` Christoph Hellwig
2026-11-03 21:17 ` [PATCH v10 2/7] mm: take a folio off WB_DONTCACHE_DIRTY only if it was counted there Mike Snitzer
2026-11-03 21:17 ` [PATCH v10 3/7] mm: expose WB_DONTCACHE_DIRTY in bdi debugfs stats Mike Snitzer
2026-11-03 21:17 ` Mike Snitzer [this message]
2026-11-03 21:17 ` [PATCH v10 5/7] mm, iomap: keep a partly covered page until an uncached write completes it Mike Snitzer
2026-11-03 21:17 ` [PATCH v10 6/7] mm, iomap: let an uncached writer complete its shared pages itself Mike Snitzer
2026-11-03 21:17 ` [PATCH v10 7/7] NFSD: drop a shared boundary page only once both WRITEs have written it Mike Snitzer
2026-11-04 9:15 ` Christoph Hellwig
2026-11-04 9:17 ` [PATCH v10 0/7] mm, iomap, NFSD: stop uncached writes reading back shared pages Christoph Hellwig
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=20261103211754.35352-5-snitzer@kernel.org \
--to=snitzer@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=axboe@kernel.dk \
--cc=cel@kernel.org \
--cc=corbet@lwn.net \
--cc=hch@lst.de \
--cc=jlayton@kernel.org \
--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=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