All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Usama Arif" <usama.arif@linux.dev>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	david@kernel.org, chrisl@kernel.org, kasong@tencent.com,
	ljs@kernel.org, ziy@nvidia.com, linux-mm@kvack.org
Cc: chenhuacai@kernel.org, ying.huang@linux.alibaba.com,
	"Baoquan He" <baoquan.he@linux.dev>,
	willy@infradead.org, youngjun.park@lge.com, hannes@cmpxchg.org,
	riel@surriel.com, shakeel.butt@linux.dev, alex@ghiti.fr,
	kas@kernel.org, baohua@kernel.org, dev.jain@arm.com,
	baolin.wang@linux.alibaba.com,
	"Nico Pache" <nico.pache@linux.dev>,
	"Liam R. Howlett" <liam@infradead.org>,
	ryan.roberts@arm.com, "Vlastimil Babka" <vbabka@kernel.org>,
	lance.yang@linux.dev, nphamcs@gmail.com,
	shikemeng@huaweicloud.com, yosry@kernel.org, qi.zheng@linux.dev,
	luizcap@redhat.com, kernel-team@meta.com
Subject: Re: [PATCH v9 27/32] mm: handle PMD swap entries in MADV_WILLNEED
Date: Fri, 06 Nov 2026 18:43:07 +0000	[thread overview]
Message-ID: <sashiko-outbox-202082@kernel.org> (raw)
In-Reply-To: <20261105183940.2236717-28-usama.arif@linux.dev>

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Critical] mm: rmap corruption from unmapped PMD folio cached by
  swapin_pmd_swap_entry()
--

commit 14ed08337de0c0909e93ae1d8b999993fb793692
Author: Usama Arif <usama.arif@linux.dev>

mm: handle PMD swap entries in MADV_WILLNEED

This commit teaches MADV_WILLNEED to prefetch PMD swap entries as a single
PMD-order folio when THP policy allows it, falling back to splitting the
PMD into PTEs when PMD-order swapin is disallowed or fails.

> diff --git a/mm/madvise.c b/mm/madvise.c
> index f7f17efdd926d..576be4b8744c2 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
[ ... ]
> @@ -193,6 +194,108 @@ static int madvise_update_vma(vm_flags_t new_flags,
>  }
>  
>  #ifdef CONFIG_SWAP
> +/*
> + * Prefetch a whole PMD swap entry as one PMD-order folio.
> + *
> + * Called with the PMD lock held; always drops it. Returns true when the
> + * caller should ask the walker to retry so the PTE path can handle the
> + * covered slots individually.
> + */
> +static bool swapin_pmd_swap_entry(struct vm_area_struct *vma, pmd_t *pmd,
> +				  unsigned long addr, softleaf_t entry,
> +				  spinlock_t *ptl)
> +{
[ ... ]
> +	/*
> +	 * The range was PMD-mapped when it was swapped out, but the policy may
> +	 * have changed since: MADV_NOHUGEPAGE, or the sysfs knob. Reading it
> +	 * back at PMD order would then hand do_swap_page() a PMD-sized folio to
> +	 * map with PTEs, which is exactly what the policy forbids. Split now
> +	 * and let the PTE path prefetch at order 0 - the next fault would split
> +	 * the entry anyway, so nothing is lost that the VMA still permits.
> +	 */
> +	if (!thp_vma_allowable_order(vma, vma->vm_flags, TVA_PAGEFAULT,
> +				     HPAGE_PMD_ORDER)) {
> +		spin_unlock(ptl);
> +		return true;
> +	}
> +
> +	cache_state = swap_pmd_cache_lookup(entry, &folio);
> +	if (cache_state == SWAP_PMD_CACHE_HUGE) {
> +		/* Already cached as one PMD-sized folio, nothing to do. */
> +		folio_put(folio);
> +		spin_unlock(ptl);
> +		return false;
> +	}
> +	if (cache_state == SWAP_PMD_CACHE_SPLIT ||
> +	    zswap_is_present(entry, HPAGE_PMD_NR)) {
> +		spin_unlock(ptl);
> +		return true;
> +	}
> +
> +	/*
> +	 * Pin the swap device under the PMD lock so the PMD-swap-entry
> +	 * observation keeps the entry valid for swapin_sync().
> +	 */
> +	si = get_swap_device(entry);
> +	spin_unlock(ptl);
> +	if (IS_ERR_OR_NULL(si))
> +		return false;
> +
> +	folio = swapin_sync(entry, GFP_HIGHUSER_MOVABLE, BIT(HPAGE_PMD_ORDER),
> +			    &vmf, NULL, 0);

[Severity: Critical]
Can leaving a newly allocated PMD-order folio unmapped in the swap cache
corrupt rmap and mapcount state if the PMD swap entry is split before a
PMD fault maps it?

When madvise_willneed() -> swapin_walk_pmd_entry() ->
swapin_pmd_swap_entry() calls swapin_sync() with BIT(HPAGE_PMD_ORDER), it
inserts a fresh HPAGE_PMD_ORDER folio into the swap cache and leaves it
unmapped (!folio_test_anon(folio)).

Before a PMD page fault maps that folio via do_huge_pmd_swap_page(), the
PMD swap entry can be split into 512 contiguous PTE swap entries without
removing the cached folio. For example, if userspace applies
MADV_NOHUGEPAGE (or the sysfs THP policy changes) and then either calls
MADV_WILLNEED again (hitting the !thp_vma_allowable_order() check above
and splitting via __split_huge_pmd()) or faults on the range (causing
do_huge_pmd_swap_page() to split the PMD for PTE fallback), or performs a
partial munmap(), mprotect(), MADV_DONTNEED, or MADV_FREE, the unmapped
PMD-order folio remains in the swap cache while the page table now holds
PTE swap entries.

When do_swap_page() then faults on one of those 512 contiguous PTE swap
entries, swap_cache_get_folio() returns the HPAGE_PMD_ORDER folio and
swap_pte_batch() batches all 512 PTEs so nr_pages == folio_nr_pages(folio),
bypassing the partial mapping check:

mm/memory.c:do_swap_page() {
	...
	if (!folio_test_anon(folio) && folio_test_large(folio) &&
	    nr_pages != folio_nr_pages(folio)) {
		if (!WARN_ON_ONCE(folio_test_dirty(folio)))
			swap_cache_del_folio(folio);
		goto out_nomap;
	}
	...
	} else if (!folio_test_anon(folio)) {
		VM_WARN_ON_ONCE_FOLIO(folio_nr_pages(folio) != nr_pages, folio);
		VM_WARN_ON_ONCE_FOLIO(folio_mapped(folio), folio);
		folio_add_new_anon_rmap(folio, vma, address, rmap_flags);
		folio_put_swap(folio, NULL);
	}
	...
	set_ptes(vma->vm_mm, addr, ptep, pte, nr_pages);
}

Because folio_test_pmd_mappable(folio) is true for an HPAGE_PMD_ORDER
folio, folio_add_new_anon_rmap() initializes the folio as PMD-mapped
rather than PTE-mapped:

mm/rmap.c:folio_add_new_anon_rmap() {
	...
	} else if (!folio_test_pmd_mappable(folio)) {
		...
	} else {
		nr = folio_large_nr_pages(folio);
		/* increment count (starts at -1) */
		atomic_set(&folio->_entire_mapcount, 0);
		folio_set_large_mapcount(folio, 1, vma);
		if (IS_ENABLED(CONFIG_PAGE_MAPCOUNT))
			atomic_set(&folio->_nr_pages_mapped, ENTIRELY_MAPPED);
		if (exclusive)
			SetPageAnonExclusive(&folio->page);
		nr_pmdmapped = nr;
	}
}

This maps the folio with 512 PTEs while setting _entire_mapcount = 0,
_large_mapcount = 1, nr_pmdmapped = 512, leaving per-page _mapcount at -1,
and only setting PageAnonExclusive on the head page even when tail pages
are mapped by writable PTEs.

Similarly, if swapoff runs on the split PTE swap entries, unuse_pte() will
find the unmapped HPAGE_PMD_ORDER folio in the swap cache:

mm/swapfile.c:unuse_pte() {
	...
	if (!folio_test_anon(folio)) {
		VM_WARN_ON_ONCE(folio_test_large(folio));
		VM_WARN_ON_FOLIO(!folio_test_locked(folio), folio);
		folio_add_new_anon_rmap(folio, vma, addr, rmap_flags);
	}
}

Would it make sense to ensure that unmapped PMD-order folios in the swap
cache are either removed when a PMD swap entry is split or rejected by PTE
swapin paths such as do_swap_page() and unuse_pte()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261105183940.2236717-1-usama.arif@linux.dev?part=27


  reply	other threads:[~2026-11-06 18:43 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05 18:38 [PATCH v9 00/32] mm: PMD-level swap entries for anonymous THPs Usama Arif
2026-11-05 18:38 ` [PATCH v9 01/32] mm: rename pmd_to_softleaf_folio() to pmd_softleaf_to_folio() Usama Arif
2026-11-05 18:38 ` [PATCH v9 02/32] arm64: mm: add PMD swap-exclusive helpers Usama Arif
2026-11-05 18:38 ` [PATCH v9 03/32] loongarch: " Usama Arif
2026-11-05 18:38 ` [PATCH v9 04/32] powerpc: " Usama Arif
2026-11-05 18:38 ` [PATCH v9 05/32] riscv: " Usama Arif
2026-11-05 18:38   ` Usama Arif
2026-11-05 18:38 ` [PATCH v9 06/32] s390: " Usama Arif
2026-11-06 18:43   ` sashiko-bot
2026-11-10 17:17   ` Gerald Schaefer
2026-11-05 18:38 ` [PATCH v9 07/32] x86: " Usama Arif
2026-11-05 18:38 ` [PATCH v9 08/32] mm: recognize PMD swap entries in the softleaf layer Usama Arif
2026-11-05 18:38 ` [PATCH v9 09/32] mm/debug_vm_pgtable: test PMD swap-exclusive helpers Usama Arif
2026-11-05 18:38 ` [PATCH v9 10/32] mm/migrate_device: avoid leaking folio references during THP splitting Usama Arif
2026-11-05 18:38 ` [PATCH v9 11/32] mm: make PMD migration-entry splitting explicit Usama Arif
2026-11-05 18:38 ` [PATCH v9 12/32] mm: split PMD swap entries into PTE swap entries Usama Arif
2026-11-05 18:38 ` [PATCH v9 13/32] mm/swap: allow duplicating a range of " Usama Arif
2026-11-05 18:38 ` [PATCH v9 14/32] mm: handle PMD swap entries in fork path Usama Arif
2026-11-05 18:38 ` [PATCH v9 15/32] mm: swap: share swap-cache allocation error cleanup Usama Arif
2026-11-06 21:10   ` Yosry Ahmed
2026-11-06 21:39   ` Nhat Pham
2026-11-05 18:39 ` [PATCH v9 16/32] mm: zswap: reject high-order swap cache allocations backed by zswap Usama Arif
2026-11-06 16:26   ` Nhat Pham
2026-11-06 21:16   ` Yosry Ahmed
2026-11-05 18:39 ` [PATCH v9 17/32] mm: swap in PMD swap entries as whole THPs during swapoff Usama Arif
2026-11-06 18:43   ` sashiko-bot
2026-11-05 18:39 ` [PATCH v9 18/32] fs/proc: account PMD swap entries in smaps Usama Arif
2026-11-05 18:39 ` [PATCH v9 19/32] mm: handle soft-dirty and uffd-wp on PMD swap entries Usama Arif
2026-11-05 18:39 ` [PATCH v9 20/32] mm/hmm: fault PMD swap entries on demand Usama Arif
2026-11-05 18:39 ` [PATCH v9 21/32] mm: free PMD swap entries in zap_huge_pmd() Usama Arif
2026-11-05 18:39 ` [PATCH v9 22/32] mm/madvise: free PMD swap entries with MADV_FREE Usama Arif
2026-11-05 18:39 ` [PATCH v9 23/32] mm/madvise: skip PMD swap entries for MADV_COLD and MADV_PAGEOUT Usama Arif
2026-11-05 18:39 ` [PATCH v9 24/32] mm/madvise: keep PMD swap entries whole for MADV_GUARD_INSTALL/REMOVE Usama Arif
2026-11-05 18:39 ` [PATCH v9 25/32] mm/mincore: report PMD swap-cache residency Usama Arif
2026-11-05 18:39 ` [PATCH v9 26/32] mm/khugepaged: treat PMD swap entries as mapped THPs Usama Arif
2026-11-05 18:39 ` [PATCH v9 27/32] mm: handle PMD swap entries in MADV_WILLNEED Usama Arif
2026-11-06 18:43   ` sashiko-bot [this message]
2026-11-05 18:39 ` [PATCH v9 28/32] mm: handle PMD swap entries in UFFDIO_MOVE Usama Arif
2026-11-06 18:43   ` sashiko-bot
2026-11-05 18:39 ` [PATCH v9 29/32] mm: don't PTE-batch a swap-in over a hardware-poisoned subpage Usama Arif
2026-11-05 18:39 ` [PATCH v9 30/32] mm: handle PMD swap entry faults on swap-in Usama Arif
2026-11-06 18:43   ` sashiko-bot
2026-11-05 18:39 ` [PATCH v9 31/32] mm: install PMD swap entries on swap-out Usama Arif
2026-11-06 18:43   ` sashiko-bot
2026-11-05 18:39 ` [PATCH v9 32/32] selftests/mm: add PMD swap entry tests Usama Arif
2026-11-06 18:43   ` sashiko-bot

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-202082@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=alex@ghiti.fr \
    --cc=baohua@kernel.org \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=baoquan.he@linux.dev \
    --cc=chenhuacai@kernel.org \
    --cc=chrisl@kernel.org \
    --cc=david@kernel.org \
    --cc=dev.jain@arm.com \
    --cc=hannes@cmpxchg.org \
    --cc=kas@kernel.org \
    --cc=kasong@tencent.com \
    --cc=kernel-team@meta.com \
    --cc=lance.yang@linux.dev \
    --cc=liam@infradead.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=luizcap@redhat.com \
    --cc=nico.pache@linux.dev \
    --cc=nphamcs@gmail.com \
    --cc=qi.zheng@linux.dev \
    --cc=riel@surriel.com \
    --cc=ryan.roberts@arm.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=shakeel.butt@linux.dev \
    --cc=shikemeng@huaweicloud.com \
    --cc=usama.arif@linux.dev \
    --cc=vbabka@kernel.org \
    --cc=willy@infradead.org \
    --cc=ying.huang@linux.alibaba.com \
    --cc=yosry@kernel.org \
    --cc=youngjun.park@lge.com \
    --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 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.