From: Hongfu Li <hongfu.li@linux.dev>
To: Muchun Song <muchun.song@linux.dev>, Hongfu Li <lihongfu@kylinos.cn>
Cc: hongfu.li@linux.dev, Chris Down <chris@chrisdown.name>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
cgroups@vger.kernel.org, stable@vger.kernel.org,
Oscar Salvador <osalvador@suse.de>,
David Hildenbrand <david@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
Shakeel Butt <shakeel.butt@linux.dev>,
Michal Hocko <mhocko@suse.com>,
Johannes Weiner <hannes@cmpxchg.org>,
Joshua Hahn <joshua.hahnjy@gmail.com>,
Nhat Pham <nphamcs@gmail.com>, Michal Hocko <mhocko@kernel.org>,
Roman Gushchin <roman.gushchin@linux.dev>
Subject: Re: [PATCH v2 2/2] mm/memcg: migrate per-node hugetlb lruvec stat together with hugetlb folio
Date: Wed, 23 Sep 2026 11:40:55 +0800 [thread overview]
Message-ID: <1835413c-e2de-41b0-8225-161afa50676a@linux.dev> (raw)
In-Reply-To: <15ac7069-d687-4985-90bd-25bc900b4bdd@linux.dev>
On 9/23/26 10:40 AM, Muchun Song wrote:
>
>
> On 2026/9/23 10:05, Hongfu Li wrote:
>> From: Hongfu Li <lihongfu@kylinos.cn>
>>
>> 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@vger.kernel.org
>> Signed-off-by: Hongfu Li <lihongfu@kylinos.cn>
>> Tested-by: Joshua Hahn <joshua.hahnjy@gmail.com>
>> Reviewed-by: Joshua Hahn <joshua.hahnjy@gmail.com>
>> Reviewed-by: Oscar Salvador <osalvador@suse.de>
>> ---
>> include/linux/memcontrol.h | 8 ++++++++
>> mm/hugetlb.c | 25 +++++++++++++++++++++++++
>> mm/memcontrol.c | 5 ++---
>> 3 files changed, 35 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
>> index a8358f297b65..74110a324f9e 100644
>> --- a/include/linux/memcontrol.h
>> +++ b/include/linux/memcontrol.h
>> @@ -984,6 +984,9 @@ unsigned long lruvec_page_state_monotonic(const
>> struct lruvec *lruvec,
>> unsigned long lruvec_page_state_local(const struct lruvec *lruvec,
>> enum node_stat_item idx);
>> +void mod_memcg_lruvec_state(struct lruvec *lruvec,
>> + enum node_stat_item idx, int val);
>> +
>> void mem_cgroup_flush_stats(struct mem_cgroup *memcg);
>> void mem_cgroup_flush_stats_ratelimited(struct mem_cgroup *memcg);
>> @@ -1452,6 +1455,11 @@ static inline unsigned long
>> lruvec_page_state_local(const struct lruvec *lruvec,
>> return node_page_state(lruvec_pgdat(lruvec), idx);
>> }
>> +static inline void mod_memcg_lruvec_state(struct lruvec *lruvec,
>> + enum node_stat_item idx, int val)
>> +{
>> +}
>> +
>> static inline void mem_cgroup_flush_stats(struct mem_cgroup *memcg)
>> {
>> }
>> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
>> index 519c30b338a8..76d019594b39 100644
>> --- a/mm/hugetlb.c
>> +++ b/mm/hugetlb.c
>> @@ -23,6 +23,7 @@
>> #include <linux/mmdebug.h>
>> #include <linux/sched/signal.h>
>> #include <linux/rmap.h>
>> +#include <linux/rcupdate.h>
>> #include <linux/string_choices.h>
>> #include <linux/string_helpers.h>
>> #include <linux/swap.h>
>> @@ -7378,12 +7379,36 @@ void folio_putback_hugetlb(struct folio *folio)
>> folio_put(folio);
>> }
>> +static void move_hugetlb_lruvec_stat(struct folio *old_folio,
>> + struct folio *new_folio)
>> +{
>> + struct mem_cgroup *memcg;
>> + long nr_pages = folio_nr_pages(old_folio);
>> + int old_nid = folio_nid(old_folio);
>> + int new_nid = folio_nid(new_folio);
>> +
>> + if (old_nid == new_nid)
>> + return;
>> +
>> + guard(rcu)();
>> +
>> + memcg = folio_memcg(new_folio);
>> + if (!memcg)
>> + return;
>> +
>> + mod_memcg_lruvec_state(mem_cgroup_lruvec(memcg,
>> NODE_DATA(old_nid)),
>> + NR_HUGETLB, -nr_pages);
>
> Why not use mod_lruvec_state? mod_memcg_lruvec_state is an internal
> API for memcg, I don't want it to be exported.
Thank you for the review.
mod_lruvec_state() would update the node counter a second time. It calls
mod_node_page_state() as well, and the target's node counter is already
updated in alloc_hugetlb_folio_nodemask() (patch 1/2):
lruvec_stat_mod_folio(folio, NR_HUGETLB, folio_nr_pages(folio));
For an uncharged folio lruvec_stat_mod_folio() only updates the node
counter. The target folio is not charged to any memcg at that point; its
charge only appears later in mem_cgroup_migrate(). So the node side is
already covered and only the per-memcg attribution has to follow the
charge here.
>
> Thanks.
>
>> + mod_memcg_lruvec_state(mem_cgroup_lruvec(memcg, NODE_DATA(new_nid)),
>> + NR_HUGETLB, nr_pages);
>> +}
>> +
>> void move_hugetlb_state(struct folio *old_folio, struct folio
>> *new_folio,
>> enum migrate_reason reason)
>> {
>> struct hstate *h = folio_hstate(old_folio);
>> hugetlb_cgroup_migrate(old_folio, new_folio);
>> + move_hugetlb_lruvec_stat(old_folio, new_folio);
>> folio_set_owner_migrate_reason(new_folio, reason);
>> /*
>> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
>> index 88824f783571..a5335da5d425 100644
>> --- a/mm/memcontrol.c
>> +++ b/mm/memcontrol.c
>> @@ -1015,9 +1015,8 @@ static void __mod_memcg_lruvec_state(struct
>> mem_cgroup_per_node *pn,
>> put_cpu();
>> }
>> -static void mod_memcg_lruvec_state(struct lruvec *lruvec,
>> - enum node_stat_item idx,
>> - int val)
>> +void mod_memcg_lruvec_state(struct lruvec *lruvec,
>> + enum node_stat_item idx, int val)
>> {
>> struct pglist_data *pgdat = lruvec_pgdat(lruvec);
>> struct mem_cgroup_per_node *pn;
>>
>
--
Best regards,
Hongfu
next prev parent reply other threads:[~2026-09-23 3:41 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-23 2:05 [PATCH v2 0/2] mm: fix hugetlb NR_HUGETLB accounting on folio migration Hongfu Li
2026-09-23 2:05 ` [PATCH v2 1/2] mm/hugetlb: account migration target folio in per-node NR_HUGETLB vmstat Hongfu Li
2026-09-23 2:05 ` [PATCH v2 2/2] mm/memcg: migrate per-node hugetlb lruvec stat together with hugetlb folio Hongfu Li
2026-09-23 2:40 ` Muchun Song
2026-09-23 3:40 ` Hongfu Li [this message]
2026-09-23 7:56 ` Muchun Song
2026-09-23 9:55 ` Hongfu Li
2026-09-23 11:31 ` Muchun Song
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1835413c-e2de-41b0-8225-161afa50676a@linux.dev \
--to=hongfu.li@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=cgroups@vger.kernel.org \
--cc=chris@chrisdown.name \
--cc=david@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=joshua.hahnjy@gmail.com \
--cc=lihongfu@kylinos.cn \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@kernel.org \
--cc=mhocko@suse.com \
--cc=muchun.song@linux.dev \
--cc=nphamcs@gmail.com \
--cc=osalvador@suse.de \
--cc=roman.gushchin@linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.