From: sashiko-bot@kernel.org
To: "Pedro Falcato" <pfalcato@suse.de>,
"Andrew Morton" <akpm@linux-foundation.org>,
"David Hildenbrand" <david@kernel.org>, "Zi Yan" <ziy@nvidia.com>
Cc: "Baolin Wang" <baolin.wang@linux.alibaba.com>,
"Liam R. Howlett" <liam@infradead.org>,
"Nico Pache" <nico.pache@linux.dev>,
"Ryan Roberts" <ryan.roberts@arm.com>,
"Dev Jain" <dev.jain@arm.com>, "Barry Song" <baohua@kernel.org>,
"Lance Yang" <lance.yang@linux.dev>,
"Usama Arif" <usama.arif@linux.dev>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Kiryl Shutsemau" <kas@kernel.org>,
linux-mm@kvack.org
Subject: Re: [PATCH v2 7/8] mm/khugepaged: hoist more code into collapse_isolate_folio()
Date: Thu, 12 Nov 2026 17:51:47 +0000 [thread overview]
Message-ID: <sashiko-outbox-211635@kernel.org> (raw)
In-Reply-To: <20261111175121.1328383-8-pfalcato@suse.de>
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [High] mm/khugepaged: missing smp_rmb() in collapse_isolate_folio()
--
commit 1a6c61868f8e8d364cc5be77c89e1e39fd7f5a4a
Author: Pedro Falcato <pfalcato@suse.de>
mm/khugepaged: hoist more code into collapse_isolate_folio()
This commit moves the folio reference count and dirtiness checks from
collapse_file() into collapse_isolate_folio(), performing them outside the
i_pages xarray lock.
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 1e58ae5b3e74d..accd8b4895d30 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -2404,13 +2404,53 @@ static enum scan_result collapse_isolate_folio(struct collapse_file_state *state
>
> if (!filemap_release_folio(folio, GFP_KERNEL)) {
> result = SCAN_PAGE_HAS_PRIVATE;
> - folio_putback_lru(folio);
> - goto out_unlock;
> + goto out_putback;
> }
>
> if (folio_mapped(folio))
> try_to_unmap(folio, TTU_IGNORE_MLOCK | TTU_BATCH_FLUSH);
> + /*
> + * We control 2 + nr_pages references to the folio:
> + * - we hold a pin on it;
> + * - nr_pages reference from page cache;
> + * - one from lru_isolate_folio;
> + * If those are the only references, then any new usage
> + * of the folio will have to fetch it from the page
> + * cache. That requires locking the folio to handle
> + * truncate, so any new usage will be blocked until we
> + * unlock folio after collapse/during rollback.
> + */
> + if (folio_ref_count(folio) != 2 + folio_nr_pages(folio)) {
> + result = SCAN_PAGE_COUNT;
> + goto out_putback;
> + }
> +
> + /*
> + * At this point, the folio is locked and unmapped. If the PTE
> + * was dirty, try_to_unmap() has transferred the dirty bit to
> + * the folio and we must not collapse it into a clean
> + * file-backed folio.
> + *
> + * If the folio is clean here, no one can write it until we
> + * drop the folio lock. A write through a stale TLB entry came
> + * from a clean PTE and must fault because the PTE has been
> + * cleared; the fault path has to take the folio lock before
> + * installing a writable mapping. Buffered write paths also
> + * have to take the folio lock before modifying file contents
> + * without a mapping, typically via write_begin_get_folio().
> + */
> + if (!state->is_shmem && folio_test_dirty(folio)) {
> + result = SCAN_PAGE_DIRTY_OR_WRITEBACK;
> + goto out_putback;
> + }
> return SCAN_SUCCEED;
[Severity: High]
Without xas_lock_irq(&xas), can the folio_test_dirty(folio) load be
satisfied before folio_ref_count(folio) on weakly-ordered architectures?
A concurrent holder of a temporary reference or pin (such as direct I/O
read completion into a file-backed buffer) can mark the folio dirty and
drop its reference without holding the folio lock:
CPU0 CPU1
collapse_isolate_folio()
[speculatively loads folio->flags:
folio_test_dirty(folio) == false]
folio_mark_dirty(folio)
folio_put(folio)
folio_ref_count(folio) == 2 + nr
return SCAN_SUCCEED <-- dirty folio collapsed as clean
Previously, holding i_pages.xa_lock across both checks serialized against
__folio_mark_dirty(), as noted in __remove_mapping():
mm/vmscan.c:__remove_mapping() {
...
* Reversing the order of the tests ensures such a situation cannot
* escape unnoticed. The smp_rmb is needed to ensure the folio->flags
* load is not satisfied before that of folio->_refcount.
*
* Note that if the dirty flag is always set via folio_mark_dirty,
* and thus under the i_pages lock, then this ordering is not required.
...
}
Because folio_ref_count(folio) and folio_test_dirty(folio) are plain reads
of different struct folio members with no barrier between them, reordering
them allows a newly dirtied file-backed folio to be collapsed into a clean
PMD folio, losing the modified data on reclaim and leaving dirty page
accounting elevated. Adding smp_rmb() between folio_ref_count(folio) and
folio_test_dirty(folio) (matching ttu_anon_lazyfree_folio() and
__discard_anon_folio_pmd_locked()) would preserve the ordering.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261111175121.1328383-1-pfalcato@suse.de?part=7
next prev parent reply other threads:[~2026-11-12 17:51 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 17:51 [PATCH v2 0/8] mm/khugepaged: collapse_file() cleanups Pedro Falcato
2026-11-11 17:51 ` [PATCH v2 1/8] mm/khugepaged: separate out windy folio logic from collapse_file Pedro Falcato
2026-11-12 17:51 ` sashiko-bot
2026-11-11 17:51 ` [PATCH v2 2/8] mm/khugepaged: sanitize the folio passed to file folio collapse logic Pedro Falcato
2026-11-11 17:51 ` [PATCH v2 3/8] mm/khugepaged: factor out page cache folio reading Pedro Falcato
2026-11-11 17:51 ` [PATCH v2 4/8] mm/khugepaged: factor out and simplify dirty/writeback handling Pedro Falcato
2026-11-11 17:51 ` [PATCH v2 5/8] mm/khugepaged: simplify prepare folio locking and exit paths Pedro Falcato
2026-11-11 17:51 ` [PATCH v2 6/8] mm/khugepaged: hoist isolation into collapse_isolate_folio() Pedro Falcato
2026-11-11 17:51 ` [PATCH v2 7/8] mm/khugepaged: hoist more code " Pedro Falcato
2026-11-12 17:51 ` sashiko-bot [this message]
2026-11-11 17:51 ` [PATCH v2 8/8] mm/khugepaged: flesh out try_to_unmap_flush() comment Pedro Falcato
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-211635@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=kas@kernel.org \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=nico.pache@linux.dev \
--cc=pfalcato@suse.de \
--cc=ryan.roberts@arm.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=usama.arif@linux.dev \
--cc=ziy@nvidia.com \
/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