Re: [PATCH 2/2] mm/memcg: migrate per-node hugetlb lruvec stat together with hugetlb folio
From: Oscar Salvador (SUSE)
Date: Tue Sep 22 2026 - 00:15:33 EST
On Mon, Sep 21, 2026 at 05:12:35PM +0800, Hongfu Li wrote:
> From: Hongfu Li <lihongfu@xxxxxxxxxx>
>
> memory.numa_stat exposes per-node hugetlb counters from per-node lruvec
> stats. These stats are accounted against folio_nid(): incremented on
> the folio's node when handed to a user, decremented when the folio is
> returned to the pool.
>
> During hugetlb folio migration, mem_cgroup_migrate() moves the charge
> to the new folio and drops the memcg data of the old one, so the free
> of the old folio right after the migration skips the memcg per-node
> lruvec decrement. The hugetlb count stays attributed to the old node
> for the rest of the life of the charge, while the target folio gets no
> increment on the new node; its later free decrements a counter that
> was never incremented.
>
> Migrate the per-node lruvec accounting alongside migration. Global
> memcg totals remain balanced because they track resource consumption,
> not node placement.
>
> Fixes: 05d4532b60e3 ("memcg/hugetlb: add hugeTLB counters to memcg")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Hongfu Li <lihongfu@xxxxxxxxxx>
For the fix itself:
Reviewed-by: Oscar Salvador <osalvador@xxxxxxx>
question below:
> ---
> mm/memcontrol.c | 31 +++++++++++++++++++++++++++++++
> 1 file changed, 31 insertions(+)
>
> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
> index 1460cba53588..9c96ebd5436f 100644
> --- a/mm/memcontrol.c
> +++ b/mm/memcontrol.c
> @@ -5598,6 +5598,34 @@ void mem_cgroup_replace_folio(struct folio *old, struct folio *new)
> rcu_read_unlock();
> }
>
> +#ifdef CONFIG_HUGETLB_PAGE
> +static void move_hugetlb_lruvec_stat(struct obj_cgroup *objcg,
> + struct folio *old, struct folio *new)
> +{
> + long nr_pages = folio_nr_pages(old);
> + struct mem_cgroup *memcg;
> + int old_nid = folio_nid(old);
> + int new_nid = folio_nid(new);
> +
> + if (old_nid == new_nid)
> + return;
> +
> + rcu_read_lock();
> + memcg = obj_cgroup_memcg(objcg);
> + mod_memcg_lruvec_state(mem_cgroup_lruvec(memcg, NODE_DATA(old_nid)),
> + NR_HUGETLB, -nr_pages);
> + mod_memcg_lruvec_state(mem_cgroup_lruvec(memcg, NODE_DATA(new_nid)),
> + NR_HUGETLB, nr_pages);
> + rcu_read_unlock();
Why do we need the whole thing to be embraced by rcu?
--
Oscar Salvador
SUSE Labs