Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
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


  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