[PATCH 2/3] fs/proc/task_mmu: don't read young/dirty from a non-present PMD in smaps

From: Usama Arif

Date: Wed Nov 11 2026 - 06:42:36 EST


smaps_pmd_entry() passes pmd_young(*pmd) and pmd_dirty(*pmd) to
smaps_account() for every PMD, including migration and device-private
entries, where those bits hold part of the swap offset rather than
accessed/dirty state. smaps_pte_entry() only reads them when the entry
is present.

On x86_64 the offset is stored inverted across bits 9-58, which overlap
_PAGE_SAVED_DIRTY, so pmd_dirty() returns garbage: a clean 2MB
device-private mapping is accounted as 2048 kB dirty, and lazyfree
accounting is suppressed. pgtable_64.h also warns that the hardware can
set the accessed and dirty bits on non-present entries by mistake.

Only read the bits when the PMD is present.

Fixes: c94b6923fa0a ("/proc/PID/smaps: Add PMD migration entry parsing")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Usama Arif <usama.arif@xxxxxxxxx>
---
fs/proc/task_mmu.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 22361607020d1..c0d391186c2b8 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1019,13 +1019,15 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
struct vm_area_struct *vma = walk->vma;
bool locked = !!(vma->vm_flags & VM_LOCKED);
struct page *page = NULL;
- bool present = false;
+ bool present = false, young = false, dirty = false;
struct folio *folio;

if (pmd_none(*pmd))
return;
if (pmd_present(*pmd)) {
page = vm_normal_page_pmd(vma, addr, *pmd);
+ young = pmd_young(*pmd);
+ dirty = pmd_dirty(*pmd);
present = true;
} else if (unlikely(thp_migration_supported())) {
const softleaf_t entry = softleaf_from_pmd(*pmd);
@@ -1045,8 +1047,7 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
else
mss->file_thp += HPAGE_PMD_SIZE;

- smaps_account(mss, page, true, pmd_young(*pmd), pmd_dirty(*pmd),
- locked, present);
+ smaps_account(mss, page, true, young, dirty, locked, present);
}
#else
static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
--
2.53.0-Meta