From: sashiko-bot@kernel.org
To: "Mike Snitzer" <snitzer@kernel.org>,
"Matthew Wilcox" <willy@infradead.org>,
linux-mm@kvack.org
Cc: "Chuck Lever" <cel@kernel.org>,
"Jeff Layton" <jlayton@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>,
"Anna Schumaker" <anna@kernel.org>
Subject: Re: [PATCH v10 4/7] mm: add folio_mark_dropbehind() to mark a folio dropbehind and account it
Date: Wed, 04 Nov 2026 21:18:15 +0000 [thread overview]
Message-ID: <sashiko-outbox-198087@kernel.org> (raw)
In-Reply-To: <20261103211754.35352-5-snitzer@kernel.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] mm: double WB_DONTCACHE_DIRTY accounting in folio_mark_dropbehind()
--
commit 22fee9ca43388b4bd59c934777df4d9990967b8e
Author: Mike Snitzer <snitzer@kernel.org>
mm: add folio_mark_dropbehind() to mark a folio dropbehind and account it
This commit introduces folio_mark_dropbehind() to mark a locked folio
with PG_dropbehind and increment WB_DONTCACHE_DIRTY under the i_pages
lock when both PG_dirty and PAGECACHE_TAG_DIRTY are set.
> 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);
> +}
[Severity: Medium]
As reported by Sashiko on v9 [1], can WB_DONTCACHE_DIRTY be double-counted
in folio_mark_dropbehind() when a stale PAGECACHE_TAG_DIRTY mark coincides
with an unlocked dirtier that has just set PG_dirty?
Specifically, PAGECACHE_TAG_DIRTY can remain set in mapping->i_pages on a
clean folio after __folio_cancel_dirty() clears PG_dirty and calls
folio_account_cleaned():
mm/page-writeback.c:__folio_cancel_dirty() {
...
if (folio_test_clear_dirty(folio))
folio_account_cleaned(folio, wb);
...
}
(or after folio_clear_dirty_for_io() clears PG_dirty and writeback exits
early before calling folio_start_writeback()).
If an unlocked dirtier that does not hold the folio lock (such as
zap_present_folio_ptes() -> folio_mark_dirty() -> filemap_dirty_folio()
under the PTE lock) then runs concurrently, it sets PG_dirty before
acquiring mapping->i_pages.xa_lock in __folio_mark_dirty():
mm/page-writeback.c:filemap_dirty_folio() {
folio_ clamp/test:
if (folio_test_set_dirty(folio))
return false;
__folio_mark_dirty(folio, mapping, !folio_has_attached_private(folio));
}
If folio_mark_dropbehind() acquires mapping->i_pages.xa_lock in that
window, it sets PG_dropbehind, observes both folio_test_dirty(folio) and
the stale PAGECACHE_TAG_DIRTY mark as true, and adds folio_nr_pages(folio)
to WB_DONTCACHE_DIRTY.
When __folio_mark_dirty() subsequently acquires mapping->i_pages.xa_lock,
folio_account_dirtied() sees PG_dropbehind set and adds
folio_nr_pages(folio) to WB_DONTCACHE_DIRTY a second time:
mm/page-writeback.c:folio_account_dirtied() {
...
lruvec_stat_mod_folio(folio, NR_FILE_DIRTY, nr);
if (folio_test_dropbehind(folio))
wb_stat_mod(wb, WB_DONTCACHE_DIRTY, nr);
}
When the folio is later cleaned, WB_DONTCACHE_DIRTY is only decremented
once, leaving a permanent positive drift in the counter.
[1] https://lore.kernel.org/r/sashiko-outbox-184464@kernel.org
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103211754.35352-1-snitzer@kernel.org?part=4
next prev parent reply other threads:[~2026-11-04 21:18 UTC|newest]
Thread overview: 14+ 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 ` [PATCH v10 4/7] mm: add folio_mark_dropbehind() to mark a folio dropbehind and account it Mike Snitzer
2026-11-04 21:18 ` sashiko-bot [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-04 21:18 ` sashiko-bot
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 17:01 ` Mike Snitzer
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=sashiko-outbox-198087@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=anna@kernel.org \
--cc=axboe@kernel.dk \
--cc=cel@kernel.org \
--cc=corbet@lwn.net \
--cc=hch@lst.de \
--cc=jlayton@kernel.org \
--cc=linux-mm@kvack.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=sashiko-reviews@lists.linux.dev \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.