Re: [PATCH v4 12/17] mm/huge_memory: mark folio as accessed more accurately on split
From: Barry Song
Date: Sun Nov 08 2026 - 17:16:05 EST
On Fri, Oct 16, 2026 at 2:16 AM Kairui Song via B4 Relay
<devnull+kasong.tencent.com@xxxxxxxxxx> wrote:
>
> From: Kairui Song <kasong@xxxxxxxxxxx>
>
> The behavior of updating the folio's access info isn't consistent for
> huge mapping splitting or ordinary unmapping. The page table's young
> flag has to be translated into folio's access info.
>
> Right now it only check and set folio's referenced flag, which isn't
> enough since folio flags update on access have its rules. Ordinary
> unmapping (zapping) calls folio_mark_accessed(), and it also checks
> if the VMA has recency to avoid false updates.
This might be a bit off-topic, but I once proposed
recency fading for the zapping case in Android workloads:
https://lore.kernel.org/linux-mm/20250514070820.51793-1-21cnbao@xxxxxxxxx/
folio_mark_accessed() might not be ideal for Android
apps that are being killed, as we expect them to be
relaunched only after a long period of time.
But for the splitting case, I guess there is no doubt
that the accessed state should be set.
>
> So first just use the right helper here to be more consistent.
>
> Tested-by: zhaozhengzhuo <zhaozhengzhuo@xxxxxxxxxxxxx>
> Signed-off-by: Kairui Song <kasong@xxxxxxxxxxx>
> ---
> mm/huge_memory.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index bd44d58e8684..1e2b6448c010 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -3093,8 +3093,8 @@ static void __split_huge_pud_locked(struct vm_area_struct *vma, pud_t *pud,
>
> if (!folio_test_dirty(folio) && pud_dirty(old_pud))
> folio_mark_dirty(folio);
> - if (!folio_test_referenced(folio) && pud_young(old_pud))
> - folio_set_referenced(folio);
> + if (pud_young(old_pud) && vma_has_recency(vma))
> + folio_mark_accessed(folio);
> folio_remove_rmap_pud(folio, page, vma);
> add_mm_counter(vma->vm_mm, mm_counter_file(folio),
> -HPAGE_PUD_NR);
> @@ -3216,8 +3216,8 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> folio = page_folio(page);
> if (!folio_test_dirty(folio) && pmd_dirty(old_pmd))
> folio_mark_dirty(folio);
> - if (!folio_test_referenced(folio) && pmd_young(old_pmd))
> - folio_set_referenced(folio);
> + if (pmd_young(old_pmd) && vma_has_recency(vma))
> + folio_mark_accessed(folio);
We now have two inc_refs paths:
- folio_inc_lru_refs_walk() for mapped folios;
- folio_inc_lru_refs() for syscall accesses, or possibly
mapped folios with the appropriate flags such as
LRU_REF_MAPPED, LRU_REF_EXEC, LRU_REF_FORCE, etc.
The interface is:
void folio_inc_lru_refs(struct folio *folio, unsigned int flags);
Here we call folio_mark_accessed(folio), which is the
syscall path with flags = 0:
folio_inc_lru_refs(folio, 0);
Are we somehow applying the syscall access policy to
folios accessed through the page table?
This seems a bit strange to me, no?
> folio_remove_rmap_pmd(folio, page, vma);
> add_mm_counter(mm, mm_counter_file(folio), -HPAGE_PMD_NR);
> folio_put(folio);
>
> --
> 2.56.0
Thanks,
Barry