[PATCH v2 0/2] mm: fix hugetlb NR_HUGETLB accounting on folio migration

Hongfu Li posted 2 patches 1 day, 11 hours ago
include/linux/memcontrol.h |  8 +++++++
mm/hugetlb.c               | 60 ++++++++++++++++++++++++++++++++++++----------
mm/memcontrol.c            |  5 ++--
3 files changed, 58 insertions(+), 15 deletions(-)
[PATCH v2 0/2] mm: fix hugetlb NR_HUGETLB accounting on folio migration
Posted by Hongfu Li 1 day, 11 hours ago
The hugeTLB counters added by 05d4532b60e3 ("memcg/hugetlb: add hugeTLB
counters to memcg") are maintained in two per-node places:
  - the per-node vmstat counter NR_HUGETLB, exposed as nr_hugetlb in
    /proc/vmstat;
  - the per-node memcg lruvec stat, exposed via memory.numa_stat.

Both are accounted against the folio's node, and both drift when a
hugetlb folio is migrated, though in different ways.

A migration target folio is allocated by alloc_hugetlb_folio_nodemask()
and inherits the old folio's state without ever being accounted, while
the old folio is freed right after and its free is accounted. That
alone loses vmstat accounting: the target node has no matching increment
for the decrement on the old node, so /proc/vmstat's nr_hugetlb shrinks
by nr_pages per migration. Patch 1 accounts the folio where it is
obtained, so the increment pairs with the free in free_huge_folio() on
the successful as well as the failed migration path. The memfd page
cache preallocation helper has the same asymmetry and is fixed in the
same patch.

The per-node lruvec stat breaks differently. mem_cgroup_migrate()
moves the charge to the new folio and drops the old folio's memcg data,
so the old folio's free right after migration skips the memcg per-node
decrement; the count stays attributed to the old node for the rest of
the charge's life, and the target folio never gets an increment on its
new node. Patch 2 moves that per-node accounting along with the charge,
in move_hugetlb_state().

---
Changes in v2:
- In patch 2/2, move_hugetlb_lruvec_stat() no longer takes the objcg
  parameter; it takes the memcg from the new folio and uses guard(rcu)().
- In patch 2/2, move_hugetlb_lruvec_stat() is moved to mm/hugetlb.c and is
  now called from move_hugetlb_state() instead of mem_cgroup_migrate().
- In patch 2/2, make mod_memcg_lruvec_state() non-static (declared in
  include/linux/memcontrol.h).
- Collected tags on both patches.

To: Muchun Song <muchun.song@linux.dev>
To: Oscar Salvador <osalvador@suse.de>
To: David Hildenbrand <david@kernel.org>
To: Andrew Morton <akpm@linux-foundation.org>
To: Chris Down <chris@chrisdown.name>
To: Johannes Weiner <hannes@cmpxchg.org>
To: Shakeel Butt <shakeel.butt@linux.dev>
To: Nhat Pham <nphamcs@gmail.com>
To: Michal Hocko <mhocko@kernel.org>
To: Roman Gushchin <roman.gushchin@linux.dev>
Cc: hongfu.li@linux.dev
Cc: Michal Hocko <mhocko@suse.com>
Cc: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: cgroups@vger.kernel.org

---
Hongfu Li (2):
      mm/hugetlb: account migration target folio in per-node NR_HUGETLB vmstat
      mm/memcg: migrate per-node hugetlb lruvec stat together with hugetlb folio

 include/linux/memcontrol.h |  8 +++++++
 mm/hugetlb.c               | 60 ++++++++++++++++++++++++++++++++++++----------
 mm/memcontrol.c            |  5 ++--
 3 files changed, 58 insertions(+), 15 deletions(-)
---
base-commit: 8d29b5365d528da545c1fe0768a55babadee95d0
change-id: 20260922-for-hugetlb_state3-573f27215d4e

Best regards,
--  
Hongfu Li <lihongfu@kylinos.cn>