[PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables
Dev Jain
dev.jain at arm.com
Tue Oct 27 00:20:19 PDT 2026
On 27/10/26 4:47 am, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef at toxicpanda.com>
>
> MGLRU passes stack copies of page-table entries in walk_pud_range() and
> walk_pmd_range() when walking to the next level. These copies can become
> stale when khugepaged or MADV_DONTNEED (CONFIG_PT_RECLAIM) removes a PTE
> table concurrently.
>
> This pattern dates back to commit bd74fdaea146 ("mm: multi-gen LRU:
> support page table walks"). Likely, earlier locking masked the latent
> bug. Later changes exposed it: commit 1d65b771bc08 ("mm/khugepaged:
> retract_page_tables() without mmap or vma lock") allowed concurrent
> retraction, and commit cf4a65539c13 ("memcg-v1: no need for memcg locking
> for MGLRU") dropped the walker's outer RCU protection.
>
> The fix is simple, so just fix the original commit so we don't have to
> speculate. To fix it, pass the actual PMD/PUD pointers. This restores the
> RCU-protected lookup and validation against the live PMD. Note that the PUD
> handling is required as well to handle folded page tables correctly in all
> cases.
>
> Fix generated by an LLM and sent by Josef Bacik in private.
>
> Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks")
> Cc: stable at vger.kernel.org
> Signed-off-by: Josef Bacik <josef at toxicpanda.com>
> [ david: handle walk_pud_range() as well, clarify+simplify description,
> adjust Fixes: ]
> Signed-off-by: David Hildenbrand (Arm) <david at kernel.org>
> ---
Reviewed-by: Dev Jain <dev.jain at arm.com>
> mm/vmscan.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index 9959ca158ce83..6a1af9b92349f 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -3911,7 +3911,7 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end,
>
> walk->mm_stats[MM_NONLEAF_FOUND]++;
>
> - if (!walk_pte_range(&val, addr, next, args))
> + if (!walk_pte_range(pmd + i, addr, next, args))
> continue;
>
> walk->mm_stats[MM_NONLEAF_ADDED]++;
> @@ -3947,7 +3947,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end,
> if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val)))
> continue;
>
> - walk_pmd_range(&val, addr, next, args);
> + walk_pmd_range(pud + i, addr, next, args);
>
> if (need_resched() || walk->batched >= MAX_LRU_BATCH) {
> end = (addr | ~PUD_MASK) + 1;
>
More information about the kexec
mailing list