Unverified. Traced by reading the fault path, not reproduced. Wanted it recorded rather than lost, but it needs a repro before anyone acts on it.
daxfs_file_mmap() (daxfs/file.c:769) sets VM_PFNMAP for every shared mapping:
if (vma->vm_flags & VM_SHARED)
vm_flags_set(vma, VM_PFNMAP);
The read path in daxfs_dax_fault() (daxfs/file.c:671) can nonetheless hand back an ordinary anonymous page, which is the fallback whenever the data is not page-aligned or lives in the pcache:
page = alloc_page(GFP_HIGHUSER_MOVABLE);
...
__SetPageUptodate(page);
lock_page(page);
vmf->page = page;
return VM_FAULT_LOCKED;
For a shared fault the core then runs finish_fault() -> set_pte_range() -> folio_add_file_rmap_ptes(), taking a mapcount reference. On teardown zap_pte_range() calls vm_normal_page(), which returns NULL for a VM_PFNMAP vma, so the page is never unmapped through the normal path and the mapcount and refcount are never dropped.
If that reading is right, every such fault leaks a page with a permanently elevated mapcount, and the pages are invisible to reclaim. A long-running workload doing shared reads of non-aligned or pcache-backed data would leak steadily.
Reasons for doubt: the interaction between VM_PFNMAP and a vmf->page return is subtle, do_shared_fault() does unlock the folio via fault_dirty_shared_page(), and it is possible some path drops the reference that I did not trace.
To verify: mmap a pcache-backed or unaligned region MAP_SHARED, fault a known number of pages, unmap, and watch MemFree or a page-owner trace across repeated cycles.
If confirmed, the fix is probably to not return a struct page into a VM_PFNMAP vma at all: either drop VM_PFNMAP for mappings that can fall back to anonymous pages, or use VM_MIXEDMAP so vm_normal_page() resolves correctly.
Found during the review in #14.
Unverified. Traced by reading the fault path, not reproduced. Wanted it recorded rather than lost, but it needs a repro before anyone acts on it.
daxfs_file_mmap()(daxfs/file.c:769) setsVM_PFNMAPfor every shared mapping:The read path in
daxfs_dax_fault()(daxfs/file.c:671) can nonetheless hand back an ordinary anonymous page, which is the fallback whenever the data is not page-aligned or lives in the pcache:For a shared fault the core then runs
finish_fault()->set_pte_range()->folio_add_file_rmap_ptes(), taking a mapcount reference. On teardownzap_pte_range()callsvm_normal_page(), which returns NULL for aVM_PFNMAPvma, so the page is never unmapped through the normal path and the mapcount and refcount are never dropped.If that reading is right, every such fault leaks a page with a permanently elevated mapcount, and the pages are invisible to reclaim. A long-running workload doing shared reads of non-aligned or pcache-backed data would leak steadily.
Reasons for doubt: the interaction between
VM_PFNMAPand avmf->pagereturn is subtle,do_shared_fault()does unlock the folio viafault_dirty_shared_page(), and it is possible some path drops the reference that I did not trace.To verify: mmap a pcache-backed or unaligned region
MAP_SHARED, fault a known number of pages, unmap, and watchMemFreeor a page-owner trace across repeated cycles.If confirmed, the fix is probably to not return a
struct pageinto aVM_PFNMAPvma at all: either dropVM_PFNMAPfor mappings that can fall back to anonymous pages, or useVM_MIXEDMAPsovm_normal_page()resolves correctly.Found during the review in #14.