[PATCH v2 0/2] mm/huge_memory: take a reference on a device DAX PUD copied by fork

From: Konstantin Khorenko

Date: Thu Nov 05 2026 - 13:48:56 EST


copy_huge_pud() copies a device DAX PUD into the child without the
reference, rmap and counter that vmf_insert_folio_pud() took, so the
child's unmap takes them from the parent. fork copies a device DAX VMA
once it has a guard region, so it takes no more than:

1. map a devdax instance with 1 GiB alignment and fault in a PUD;
2. MADV_GUARD_INSTALL a page elsewhere in the VMA;
3. fork, and let the child exit.

Patch 1 is the fix, patch 2 a selftest for it. I found it while
reworking copy_huge_pmd() for fork after David's review [1]; it is
independent of that series.

v2 is based on mm-hotfixes-unstable, as patch 1 is a fix for stable.

Testing
=======

* mm-hotfixes-unstable x86_64 KVM guest with CONFIG_DEBUG_VM
* pmem from memmap=3G!4G
* devdax made with "ndctl create-namespace -m devdax -a 1G":

+----------------------+--------------+------------------------------+
| kernel | fork_dax_pud | log |
+----------------------+--------------+------------------------------+
| mm-hotfixes-unstable | not ok | BUG: Bad rss-counter state |
| | | mm:... type:MM_FILEPAGES |
| | | val:-262144 |
+----------------------+--------------+------------------------------+
| + this series | ok | clean |
+----------------------+--------------+------------------------------+

A variant that writes to the device and forks three times also hit,
on mm-hotfixes-unstable:

WARNING: ./include/linux/rmap.h:159 at
__folio_large_mapcount_sanity_checks+0x90/0x150

With the series it is clean, and the guard-regions selftest passes.

The selftest only runs on a device given in FORK_DAX_PUD_DEVICE or
argv[1], as on an unfixed kernel it leaves that device's folio with a
mapcount below zero. On pmem emulated in RAM, with
CONFIG_X86_PMEM_LEGACY and CONFIG_DEV_DAX_PMEM:

boot with memmap=3G!4G
ndctl create-namespace -f -e namespace0.0 -m devdax -a 1G
FORK_DAX_PUD_DEVICE=/dev/dax0.0 ./fork_dax_pud

[1] https://lore.kernel.org/linux-mm/20261014-b4-prep-vstor-149847-copy_huge_pmd-recheck-special-pmd-v3-0-85eaec8417f6@xxxxxxxxxxxxx/

Assisted-by: LLM
Signed-off-by: Konstantin Khorenko <khorenko@xxxxxxxxxxxxx>
---
Changes in v2:
- Patch 1: copy_huge_pud() takes only the VMAs, and the TODO moves next
to the rmap duplication, as in David's fix for the same bug:
https://lore.kernel.org/all/26862633-c3d1-4b82-8ca2-346cb78570d7@xxxxxxxxxx/
- Patch 2: read_sysfs() and a new rss_file() in vm_util instead of local
helpers (Sashiko).
- Assisted-by moved from the patches to this cover letter.
- Rebased onto mm-hotfixes-unstable.
- Link to v1: https://patch.msgid.link/20261021-vstor-150143-copy_huge_pud-folio-refcount-v1-0-8bd88551f9be@xxxxxxxxxxxxx

---
Konstantin Khorenko (2):
mm/huge_memory: take a reference on a folio PUD copied by fork
selftests/mm: test fork of a device DAX PUD

MAINTAINERS | 1 +
include/linux/huge_mm.h | 5 +-
include/linux/rmap.h | 22 ++++++
mm/huge_memory.c | 27 ++++---
mm/memory.c | 4 +-
tools/testing/selftests/mm/Makefile | 1 +
tools/testing/selftests/mm/fork_dax_pud.c | 114 ++++++++++++++++++++++++++++++
tools/testing/selftests/mm/run_vmtests.sh | 1 +
tools/testing/selftests/mm/vm_util.c | 21 ++++++
tools/testing/selftests/mm/vm_util.h | 1 +
10 files changed, 183 insertions(+), 14 deletions(-)
---
base-commit: af05d765a4476d2e48099148c80f9b13f462e309
change-id: 20261021-vstor-150143-copy_huge_pud-folio-refcount-ea269e668270

Best regards,
--
Konstantin Khorenko,
Virtuozzo Linux Kernel Team