[PATCH v3 0/7] selftests/mm: add MADV_COLD and MADV_PAGEOUT contract tests
From: Gregory Price (Meta)
Date: Mon Oct 19 2026 - 14:18:15 EST
MADV_COLD and MADV_PAGEOUT share a page-table walker in mm/madvise.c
that handles ordinary PTEs, PTE-mapped large folios and huge PMDs.
Existing selftests cover little of its range, folio and permission
handling.
The walker has needed several fixes recently, and it's clear we need
to refactor this walker to make it maintainable. Ahead of that, let's
add some selftests to at least cover contractual behaviors.
This series adds tools/testing/selftests/mm/madv_cold_pageout.c to test
only behaviors userspace can rely on, so that it stays valid across
changes to the walker's implementation.
Each patch adds one group of tests, simplest first:
1. neither hint populates a hole, faults a swapped page back in, or
accepts a locked VMA
2. a zero-length range succeeds, an unaligned start fails, and a gap
fails with ENOMEM after both sides are advised
3. neither hint accepts a hugetlb VMA
4. both hints preserve shared memory, and MADV_PAGEOUT leaves a
SHM_LOCK'd page mapped
5. paging out all or half of a THP reclaims only the advised pages,
and MADV_COLD on half a THP leaves it intact
6. only a caller that owns or can write a file may page out its pages;
anyone else only gets their private COW pages paged out
7. nor may anyone else split a large file folio, whether a PMD or PTEs
map it
We check whether MADV_PAGEOUT can swap/evict pages at all and skip
relevant tests that would fail if it can't. We do expect that the
swap/eviction will happen within 1 second with retries, but this has
been reliable on a reasonably unloaded system. We may need to increase
that timeout if it becomes an issue.
Tests that need root, THP, or hugetlbs skip accordingly as well.
All 24 tests pass over three consecutive runs, with no skips and no
warnings in dmesg, as root in a virtme-ng guest with 4 CPUs, two NUMA
nodes, a 2G swap disk, THP set to always, CONFIG_DEBUG_VM and
CONFIG_PROVE_LOCKING.
In the same guest:
- unprivileged: 18 pass, 6 skip (5 need root, 1 needs hugetlb pages)
- root without CAP_SYS_ADMIN: 22 pass, 2 skip (need page flags)
- no swap: 16 pass, 8 skip (need swap)
Changes since v2:
- renamed to madv_cold_pageout.c (Sarthak)
- pin to one CPU for the whole run (Sarthak)
- check swap and file unmapping once in main() instead of per-test.
- COW test retries, and fails if the COW page isn't swapped (Sarthak)
- gap test checks ENOMEM before it needs swap (Sarthak)
- reserve a hugetlb page as root, since run_vmtests.sh doesn't
- ignore /proc/kpageflags when pagemap hides PFNs (no CAP_SYS_ADMIN)
- shmem tests no longer require swap
- owned file test no longer needs /tmp writable by nobody
- folded patch 2 into patch 1 since it's really the same thing.
- comment and changelog fixes
v2: https://lore.kernel.org/linux-mm/20261014175756.2035176-1-gourry@xxxxxxxxxx/
original set: https://lore.kernel.org/linux-mm/20260922235830.2350770-2-gourry@xxxxxxxxxx/
Gregory Price (Meta) (7):
selftests/mm: add MADV_COLD and MADV_PAGEOUT contract tests
selftests/mm: check MADV_COLD and MADV_PAGEOUT range handling
selftests/mm: check that MADV_COLD and MADV_PAGEOUT reject hugetlb
selftests/mm: check that MADV_COLD and MADV_PAGEOUT preserve shared
memory
selftests/mm: check MADV_COLD and MADV_PAGEOUT on partly advised THPs
selftests/mm: check MADV_PAGEOUT file permissions
selftests/mm: check that unauthorized MADV_PAGEOUT skips large file
folios
tools/testing/selftests/mm/Makefile | 2 +
.../selftests/mm/ksft_madv_cold_pageout.sh | 4 +
.../testing/selftests/mm/madv_cold_pageout.c | 971 ++++++++++++++++++
tools/testing/selftests/mm/run_vmtests.sh | 5 +
tools/testing/selftests/mm/vm_util.h | 1 +
5 files changed, 983 insertions(+)
create mode 100755 tools/testing/selftests/mm/ksft_madv_cold_pageout.sh
create mode 100644 tools/testing/selftests/mm/madv_cold_pageout.c
--
2.56.0