Re: [PATCH v4 00/11] mm: PMD-level swap entries for anonymous THPs
From: Yosry Ahmed
Date: Mon Jul 13 2026 - 11:59:26 EST
On Mon, Jul 13, 2026 at 6:36 AM Usama Arif <usama.arif@xxxxxxxxx> wrote:
>
> This is the PMD swap entry core series. The preparatory PMD softleaf [1]
> cleanup series has been merged in akpm/mm-new, so this series is now
> based directly on akpm/mm-new.
>
> When reclaim swaps out a PMD-mapped anonymous THP today, the PMD is
> split into HPAGE_PMD_NR PTE-level swap entries via TTU_SPLIT_HUGE_PMD
> before unmap. This series introduces a PMD-level swap entry so the
> huge mapping can survive the swap round-trip and do_huge_pmd_swap_page()
> can restore the PMD mapping directly on swap-in, without waiting for
> khugepaged to collapse the range later.
>
> The PMD swap entry is a compact page-table encoding for HPAGE_PMD_NR
> consecutive swap slots. swap_map accounting remains per-slot and is
> unchanged. Importantly, a PMD swap entry does not promise that the swap
> cache always contains one PMD-sized folio. While the cache is empty or
> contains one PMD-sized folio, PMD-level handling can proceed. Once the
> cache has split/per-slot state, users either inspect the individual
> slots directly (mincore) or split the PMD swap entry and retry through
> the PTE path (fault, swapoff, MADV_WILLNEED, UFFDIO_MOVE). Likewise,
> if any slot is still backed by zswap's per-page store, PMD-order
> swap-in consumers split and let the PTE path load the range page by page;
> an all-on-disk range can still be read back as one PMD-sized folio.
>
> The series is ordered so every consumer can handle PMD swap entries
> before the swap-out producer starts installing them. The swap-out patch
> is the last functional change.
>
> Patch breakdown:
>
> 1. mm: add PMD swap entry detection support
> Add pmd_is_swap_entry(), teach the softleaf layer that PMD swap
> entries are valid PMD softleaf entries, and add per-arch
> pmd_swp_*exclusive helpers.
>
> 2. mm: add PMD swap entry splitting support
> Teach __split_huge_pmd_locked() to split a PMD swap entry into
> HPAGE_PMD_NR PTE swap entries. This is the common fallback path
> whenever PMD-level handling is unsafe or unavailable.
>
> 3. mm: handle PMD swap entries in fork path
> Copy a PMD swap entry in fork via one
> swap_dup_entries_direct(HPAGE_PMD_NR) operation, with the same
> swapoff/mmlist preparation rules used by PTE entries.
>
> 4. mm: zswap: add range lookup for large-folio swapin
> Teach zswap_load() to let all-on-disk large folio reads proceed to
> the backing swap device, and add zswap_range_has_entry() so PMD
> swap-entry consumers can split only when a specific range has
> per-page zswap state.
>
> 5. mm: swap in PMD swap entries as whole THPs during swapoff
> Add swap_pmd_cache_lookup() and use it from swapoff. Empty cache
> and PMD-sized cache state can be handled at PMD order; split cache
> state, zswap-backed slots, allocation/read failure, or non-uptodate
> folios split the PMD and fall back to unuse_pte_range().
>
> 6. mm: handle PMD swap entries in non-present PMD walkers
> Teach zap, mprotect, soft-dirty, uffd-wp, smaps, mincore,
> mempolicy, khugepaged, HMM, and madvise walkers about PMD swap
> entries. mincore reports PMD-sized cache state directly and checks
> per-page slots after the cache has split.
>
> 7. mm: handle PMD swap entries in MADV_WILLNEED
> Let MADV_WILLNEED prefetch a PMD swap entry at PMD order when safe,
> treat an already cached PMD-sized folio as complete, and split/retry
> through PTEs for split cache state, zswap-backed slots, or races
> with per-slot cache population.
>
> 8. mm: handle PMD swap entries in UFFDIO_MOVE
> Move PMD swap entries whole when the covered range is empty or
> backed by one PMD-sized folio. Split/per-slot cache state returns
> -EAGAIN after splitting so retry can use the PTE move path and
> update per-page rmap metadata.
>
> 9. mm: handle PMD swap entry faults on swap-in
> Add do_huge_pmd_swap_page(). It maps a PMD-sized cached folio
> directly, or allocates/reads at PMD order when the cache is empty
> and the range has no zswap entries. Split cache state, zswap-backed
> slots, and PMD-order resource failures fall back to the PTE path.
>
> 10. mm: install PMD swap entries on swap-out
> Stop forcing TTU_SPLIT_HUGE_PMD for PMD-mappable swapcache folios
> and install one PMD swap entry instead. Zswap still stores the THP
> as per-page compressed entries; PMD-order swap-in consumers preserve
> a PMD-sized cached folio or read an all-on-disk range as a whole THP,
> and split before reading per-page zswap state.
>
> 11. selftests/mm: add PMD swap entry tests
> Add pmd_swap selftests covering swap-out/in, fork, fork+COW,
> repeated cycles, write fault, munmap, mprotect, mremap, pagemap,
> mincore, MADV_FREE, MADV_WILLNEED, UFFDIO_MOVE, and swapoff.
>
> Notes on zswap:
>
> Native PMD-order zswap load/store is intentionally left for a follow-up.
> Alexandre Ghiti is currently working this.
> This series can still preserve PMD swap entries while zswap is enabled:
> zswap stores the THP as order-0 entries, and PMD-order swap-in
> consumers split any range that has zswap entries before reading it. If
> zswap has written the whole range back to disk, or the swap cache still
> contains one PMD-sized folio, PMD-level handling can proceed.
So in the swapout path, a single PMD swap entry is created, but
order-0 pages are compressed and stored independently in zswap? Just
checking I understood this correctly.