Re: [PATCH] mm/mglru: Fix young counter undercount for large folios

Barry Song <[email protected]>
Newsgroups org.kvack.linux-mm,org.kernel.vger.linux-kernel
Message-ID <CAGsJ_4wE7E2G8H4ugwSWbQMF+5ecx+mrYQxXa1U6HY3utuQz0w@mail.gmail.com>
On Wed, Aug 12, 2026 at 6:17 PM Baolin Wang
<[email protected]> wrote:
>
>
>
> On 8/12/26 2:59 PM, Hui Zhu wrote:
> > From: Hui Zhu <[email protected]>
> >
> > In lru_gen_look_around(), the young counter tracks the number of young
> > PTEs.  The original folio's contribution is represented by the initial
> > value of young: test_and_clear_young_ptes_notify() is called on it at
> > function entry, and the function returns early if it is not young.  In
> > the subsequent loop, the original folio is skipped (its accessed bits
> > were already cleared), so it is not double-counted.
> >
> > However, young is initialized to 1 regardless of the folio size.  When
> > the original folio is a large folio with nr PTEs, its young count is
> > underestimated by nr - 1.  This inconsistency can cause
> > suitable_to_scan() to return false, preventing the PMD from being added
> > to the bloom filter and reducing aging accuracy for mTHP workloads.
> >
> > Initialize young to nr so the original folio is accounted the same way
> > as other young folios in the loop (young += nr).
> >
> > Signed-off-by: Hui Zhu <[email protected]>
> > ---
>
> Good catch. Please also add the Fixes tag:
>
> Fixes: 56e5b60b2114 ("mm: support batched checking of the young flag for
> MGLRU")
>
> With that,
> Reviewed-by: Baolin Wang <[email protected]>

Hi Baolin, Hui,

I am not convinced this is the correct patch. test_and_clear_young_ptes_notify()
only indicates that there is at least one young PTE among the nr PTEs;
it does not mean that all of the PTEs are young.

Am I missing something?

bool contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
                unsigned long addr, pte_t *ptep, unsigned int nr)
{
        ...
        unsigned long end = addr + nr * PAGE_SIZE;
        bool young = false;

        ptep = contpte_align_addr_ptep(&addr, &end, ptep, nr);
        for (; addr != end; ptep++, addr += PAGE_SIZE)
                young |= __ptep_test_and_clear_young(vma, addr, ptep);

        return young;
}
EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);

>
> >   mm/vmscan.c | 2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/mm/vmscan.c b/mm/vmscan.c
> > index bc324e37c5f1..264017850a55 100644
> > --- a/mm/vmscan.c
> > +++ b/mm/vmscan.c
> > @@ -4192,7 +4192,7 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)
> >       unsigned long end;
> >       struct lru_gen_mm_walk *walk;
> >       struct folio *last = NULL;
> > -     int young = 1;
> > +     int young = nr;
> >       pte_t *pte = pvmw->pte;
> >       unsigned long addr = pvmw->address;
> >       struct vm_area_struct *vma = pvmw->vma;
>

Thanks
Barry
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.