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 17/32] mm: swap in PMD swap entries as whole THPs during swapoff
Date: Fri, 06 Nov 2026 18:43:05 +0000 [thread overview]
Message-ID: <sashiko-outbox-202072@kernel.org> (raw)
In-Reply-To: <20261105183940.2236717-18-usama.arif@linux.dev>
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Critical] mm/swapfile: race between unuse_pmd_entry() and
do_swap_page() corrupts rmap
--
commit 2a3a8bc71439dccac7a6dee3671d26f7c3dba876
Author: Usama Arif <usama.arif@linux.dev>
mm: swap in PMD swap entries as whole THPs during swapoff
This commit adds swap_pmd_cache_lookup(), unuse_pmd(), and unuse_pmd_entry()
to swap in PMD swap entries as whole THPs during swapoff when possible,
falling back to splitting the PMD into PTEs otherwise.
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index 6b5149b88fa43..7e91dc50a5131 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
[ ... ]
> @@ -2695,6 +2696,182 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
[ ... ]
> +static int unuse_pmd_entry(struct vm_area_struct *vma, pmd_t *pmd,
> + unsigned long addr, softleaf_t entry)
> +{
> + enum swap_pmd_cache cache_state;
> + struct folio *folio;
> + pmd_t pmdval;
> + int ret;
> +
> + cache_state = swap_pmd_cache_lookup(entry, &folio);
> + if (cache_state == SWAP_PMD_CACHE_SPLIT) {
> + ret = -EAGAIN;
> + goto split_fallback;
> + }
> + if (!folio) {
> + struct vm_fault vmf = {
> + .vma = vma,
> + .address = addr,
> + .real_address = addr,
> + .pmd = pmd,
> + };
> +
> + if (zswap_is_present(entry, HPAGE_PMD_NR)) {
> + ret = -EAGAIN;
> + goto split_fallback;
> + }
> +
> + folio = swapin_sync(entry, GFP_HIGHUSER_MOVABLE,
> + BIT(HPAGE_PMD_ORDER), &vmf, NULL, 0);
> + if (IS_ERR_OR_NULL(folio)) {
> + ret = folio ? PTR_ERR(folio) : -ENOMEM;
> + goto split_fallback;
> + }
> + }
> +
> + folio_lock(folio);
> + folio_wait_writeback(folio);
> + /*
> + * If the cached folio is no longer PMD-sized (e.g. split in the
> + * swap cache by deferred_split_scan() or memory_failure() while
> + * the PMD swap entry was installed), the PMD swap entry no longer
> + * maps a single contiguous folio. Split the PMD swap entry so
> + * unuse_pte_range() can swap the per-slot folios in individually.
> + */
> + if (folio_nr_pages(folio) != HPAGE_PMD_NR) {
> + folio_unlock(folio);
> + folio_put(folio);
> + ret = -EAGAIN;
> + goto split_fallback;
> + }
> + ret = unuse_pmd(vma, pmd, addr, entry, folio);
> + /*
> + * PTE fallback cannot add a single-page rmap to a newly allocated,
> + * PMD-sized !anon folio, and it cannot do anything useful with a folio
> + * that failed to read. Remove either from the swap cache so each slot
> + * is read back into an order-0 folio. An uptodate anon swap-cache folio
> + * can be mapped one PTE at a time and must stay cached so poisoned
> + * subpages remain visible.
> + */
> + if (ret && folio_matches_swap_entry(folio, entry) &&
> + (!folio_test_uptodate(folio) || !folio_test_anon(folio)))
> + swap_cache_del_folio(folio);
[Severity: Critical]
Can a concurrent page fault in do_swap_page() race with unuse_pmd_entry() and
map this newly allocated PMD-sized !anon folio via PTEs before
swap_cache_del_folio() runs, corrupting the folio's rmap state?
In mm/swapfile.c, try_to_unuse() -> unuse_mm() -> unuse_pmd_range() ->
unuse_pmd_entry() calls swapin_sync() with BIT(HPAGE_PMD_ORDER) without
holding pmd_lock (and with only mmap_read_lock(mm) held). swapin_sync()
allocates an order HPAGE_PMD_ORDER folio with !folio_test_anon(folio) and
folio_test_pmd_mappable(folio) == true, inserts it into the swap cache
covering [entry, entry + HPAGE_PMD_NR), and initiates swap_read_folio().
When the swap read completes, the folio is unlocked before unuse_pmd_entry()
acquires folio_lock(folio). During that window, a concurrent page fault on
split PTEs covering the same swap range (either in the same mm after a
concurrent PMD split such as madvise or mprotect, or in a forked mm whose PMD
swap entry was split into HPAGE_PMD_NR contiguous PTE swap entries) can enter
do_swap_page(), find the folio via swap_cache_get_folio(entry), and lock it
first.
In mm/memory.c:do_swap_page(), when all HPAGE_PMD_NR PTEs in the split page
table are still contiguous swap entries, folio_pte_range() and
swap_pte_batch() compute nr_pages == HPAGE_PMD_NR == folio_nr_pages(folio), so
the size mismatch check does not trigger:
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;
}
do_swap_page() then calls folio_add_new_anon_rmap(folio, vma, address,
rmap_flags) and maps the folio across HPAGE_PMD_NR PTEs with set_ptes().
However, mm/rmap.c:folio_add_new_anon_rmap() assumes any
folio_test_pmd_mappable(folio) folio is being mapped at the PMD level:
} 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 initializes PMD-mapped rmap accounting (_entire_mapcount = 0,
_large_mapcount = 1, per-page _mapcount left at -1, and PageAnonExclusive set
only on page 0) on a folio that is actually mapped by HPAGE_PMD_NR PTEs, which
will corrupt mapcounts and trigger BUG checks when those PTEs are later
unmapped via folio_remove_rmap_ptes().
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261105183940.2236717-1-usama.arif@linux.dev?part=17
next prev parent 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 [this message]
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
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-202072@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.