* [PATCH] mm/hugetlb: charge folios to the target mm's memcg
@ 2026-09-03 7:50 Jinmeng Zhou
2026-09-03 11:09 ` Muchun Song
2026-09-04 2:27 ` Hongfu Li
0 siblings, 2 replies; 3+ messages in thread
From: Jinmeng Zhou @ 2026-09-03 7:50 UTC (permalink / raw)
To: Muchun Song, Oscar Salvador, David Hildenbrand, Johannes Weiner,
Michal Hocko, Roman Gushchin, Shakeel Butt, Andrew Morton,
Nhat Pham
Cc: linux-mm, linux-kernel, cgroups, Jinmeng Zhou, stable
HugeTLB folios are currently charged to the memcg of the allocating
task. This gives the wrong result when a userfaultfd handler populates a
HugeTLB VMA that belongs to another process. The UFFDIO_COPY ioctl
operates on the userfaultfd context's mm, but get_mem_cgroup_from_current()
charges the folio to the handler's memcg instead.
This can be reproduced by placing the faulting process and its userfaultfd
handler in different memory cgroups. Have the target process register a
HugeTLB mapping with userfaultfd, trigger a missing fault, and let the
handler resolve it with UFFDIO_COPY. The hugepage usage is then reported
in the handler's memory.current instead of the target's.
The generic userfaultfd population path avoids this problem by charging
folios to dst_vma->vm_mm.
Pass the target mm through hugetlb_alloc_folio() and charge the folio by
using get_mem_cgroup_from_mm(). This preserves the existing charge timing
and error handling while making HugeTLB userfaultfd population consistent
with the generic path.
Fixes: 8cba9576df60 ("hugetlb: memcg: account hugetlb-backed memory in memory controller")
Cc: stable@vger.kernel.org
Signed-off-by: Jinmeng Zhou <zhoujinmeng@bytedance.com>
---
include/linux/hugetlb.h | 3 ++-
include/linux/memcontrol.h | 8 +++++---
mm/hugetlb.c | 9 ++++++---
mm/memcontrol.c | 6 ++++--
4 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 16c4c4caa126..45ada75dc04e 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -699,7 +699,8 @@ enum hugetlb_alloc_flag {
#define HUGETLB_ALLOC_USE_GLOBAL_RESERVATIONS BIT(HUGETLB_ALLOC_USE_GLOBAL_RESERVATIONS_BIT)
struct folio *hugetlb_alloc_folio(struct hstate *h,
- struct mempolicy_interpreted *mpoli, u8 alloc_flags);
+ struct mempolicy_interpreted *mpoli, struct mm_struct *mm,
+ u8 alloc_flags);
struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
unsigned long addr, bool cow_from_owner);
struct folio *alloc_hugetlb_folio_nodemask(struct hstate *h, int preferred_nid,
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 7d1c0ce189a8..362af58e50a4 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -662,7 +662,8 @@ static inline int mem_cgroup_charge(struct folio *folio, struct mm_struct *mm,
return __mem_cgroup_charge(folio, mm, gfp);
}
-int mem_cgroup_charge_hugetlb(struct folio* folio, gfp_t gfp);
+int mem_cgroup_charge_hugetlb(struct folio *folio, struct mm_struct *mm,
+ gfp_t gfp);
int mem_cgroup_swapin_charge_folio(struct folio *folio, unsigned short id,
struct mm_struct *mm, gfp_t gfp);
@@ -1156,9 +1157,10 @@ static inline int mem_cgroup_charge(struct folio *folio,
return 0;
}
-static inline int mem_cgroup_charge_hugetlb(struct folio* folio, gfp_t gfp)
+static inline int mem_cgroup_charge_hugetlb(struct folio *folio,
+ struct mm_struct *mm, gfp_t gfp)
{
- return 0;
+ return 0;
}
static inline int mem_cgroup_swapin_charge_folio(struct folio *folio,
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 785772845795..5ab5a5141574 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2816,6 +2816,7 @@ void wait_for_freed_hugetlb_folios(void)
* hugetlb_alloc_folio - Allocate a hugetlb folio.
* @h: Hugetlb state control block.
* @mpoli: Interpreted memory policy to use for allocation.
+ * @mm: Memory descriptor of the allocation target.
* @alloc_flags: Flags controlling the allocation behavior.
*
* Allocates a hugetlb folio and handles cgroup charging and global hstate
@@ -2826,7 +2827,8 @@ void wait_for_freed_hugetlb_folios(void)
* -ENOMEM if mem cgroup charging fails.
*/
struct folio *hugetlb_alloc_folio(struct hstate *h,
- struct mempolicy_interpreted *mpoli, u8 alloc_flags)
+ struct mempolicy_interpreted *mpoli, struct mm_struct *mm,
+ u8 alloc_flags)
{
bool charge_hugetlb_cgroup_rsvd = alloc_flags &
HUGETLB_ALLOC_CHARG_CGROUP_RSVD;
@@ -2881,7 +2883,8 @@ struct folio *hugetlb_alloc_folio(struct hstate *h,
spin_unlock_irq(&hugetlb_lock);
- ret = mem_cgroup_charge_hugetlb(folio, gfp | __GFP_RETRY_MAYFAIL);
+ ret = mem_cgroup_charge_hugetlb(folio, mm,
+ gfp | __GFP_RETRY_MAYFAIL);
/*
* Unconditionally increment NR_HUGETLB here because if
* mem_cgroup_charge_hugetlb failed, freeing the page will
@@ -3020,7 +3023,7 @@ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
.nodemask = nodemask,
};
- folio = hugetlb_alloc_folio(h, &mpoli, alloc_flags);
+ folio = hugetlb_alloc_folio(h, &mpoli, vma->vm_mm, alloc_flags);
mpol_cond_put(mpol);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 1271d390b617..0b795bf1e6cf 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -5233,6 +5233,7 @@ int __mem_cgroup_charge(struct folio *folio, struct mm_struct *mm, gfp_t gfp)
/**
* mem_cgroup_charge_hugetlb - charge the memcg for a hugetlb folio
* @folio: folio being charged
+ * @mm: mm context of the allocation target
* @gfp: reclaim mode
*
* This function is called when allocating a huge page folio, after the page has
@@ -5242,9 +5243,10 @@ int __mem_cgroup_charge(struct folio *folio, struct mm_struct *mm, gfp_t gfp)
* Returns ENOMEM if the memcg is already full.
* Returns 0 if either the charge was successful, or if we skip the charging.
*/
-int mem_cgroup_charge_hugetlb(struct folio *folio, gfp_t gfp)
+int mem_cgroup_charge_hugetlb(struct folio *folio, struct mm_struct *mm,
+ gfp_t gfp)
{
- struct mem_cgroup *memcg = get_mem_cgroup_from_current();
+ struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm);
int ret = 0;
/*
--
2.39.5
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] mm/hugetlb: charge folios to the target mm's memcg
2026-09-03 7:50 [PATCH] mm/hugetlb: charge folios to the target mm's memcg Jinmeng Zhou
@ 2026-09-03 11:09 ` Muchun Song
2026-09-04 2:27 ` Hongfu Li
1 sibling, 0 replies; 3+ messages in thread
From: Muchun Song @ 2026-09-03 11:09 UTC (permalink / raw)
To: Jinmeng Zhou
Cc: Oscar Salvador, David Hildenbrand, Johannes Weiner, Michal Hocko,
Roman Gushchin, Shakeel Butt, Andrew Morton, Nhat Pham, linux-mm,
linux-kernel, cgroups, Jinmeng Zhou, stable
> On Sep 3, 2026, at 15:50, Jinmeng Zhou <jinmengzhou22@gmail.com> wrote:
>
> HugeTLB folios are currently charged to the memcg of the allocating
> task. This gives the wrong result when a userfaultfd handler populates a
> HugeTLB VMA that belongs to another process. The UFFDIO_COPY ioctl
> operates on the userfaultfd context's mm, but get_mem_cgroup_from_current()
> charges the folio to the handler's memcg instead.
>
> This can be reproduced by placing the faulting process and its userfaultfd
> handler in different memory cgroups. Have the target process register a
> HugeTLB mapping with userfaultfd, trigger a missing fault, and let the
> handler resolve it with UFFDIO_COPY. The hugepage usage is then reported
> in the handler's memory.current instead of the target's.
>
> The generic userfaultfd population path avoids this problem by charging
> folios to dst_vma->vm_mm.
>
> Pass the target mm through hugetlb_alloc_folio() and charge the folio by
> using get_mem_cgroup_from_mm(). This preserves the existing charge timing
> and error handling while making HugeTLB userfaultfd population consistent
> with the generic path.
>
> Fixes: 8cba9576df60 ("hugetlb: memcg: account hugetlb-backed memory in memory controller")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jinmeng Zhou <zhoujinmeng@bytedance.com>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Thanks.
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] mm/hugetlb: charge folios to the target mm's memcg
2026-09-03 7:50 [PATCH] mm/hugetlb: charge folios to the target mm's memcg Jinmeng Zhou
2026-09-03 11:09 ` Muchun Song
@ 2026-09-04 2:27 ` Hongfu Li
1 sibling, 0 replies; 3+ messages in thread
From: Hongfu Li @ 2026-09-04 2:27 UTC (permalink / raw)
To: Jinmeng Zhou, Muchun Song, Oscar Salvador, David Hildenbrand,
Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Andrew Morton, Nhat Pham
Cc: linux-mm, linux-kernel, cgroups, Jinmeng Zhou, stable, hongfu.li
On 9/3/26 3:50 PM, Jinmeng Zhou wrote:
> HugeTLB folios are currently charged to the memcg of the allocating
> task. This gives the wrong result when a userfaultfd handler populates a
> HugeTLB VMA that belongs to another process. The UFFDIO_COPY ioctl
> operates on the userfaultfd context's mm, but get_mem_cgroup_from_current()
> charges the folio to the handler's memcg instead.
>
> This can be reproduced by placing the faulting process and its userfaultfd
> handler in different memory cgroups. Have the target process register a
> HugeTLB mapping with userfaultfd, trigger a missing fault, and let the
> handler resolve it with UFFDIO_COPY. The hugepage usage is then reported
> in the handler's memory.current instead of the target's.
>
> The generic userfaultfd population path avoids this problem by charging
> folios to dst_vma->vm_mm.
>
> Pass the target mm through hugetlb_alloc_folio() and charge the folio by
> using get_mem_cgroup_from_mm(). This preserves the existing charge timing
> and error handling while making HugeTLB userfaultfd population consistent
> with the generic path.
>
> Fixes: 8cba9576df60 ("hugetlb: memcg: account hugetlb-backed memory in memory controller")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jinmeng Zhou <zhoujinmeng@bytedance.com>
Reviewed-by: Hongfu Li <lihongfu@kylinos.cn>
--
Best regards,
Hongfu
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-04 2:27 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 7:50 [PATCH] mm/hugetlb: charge folios to the target mm's memcg Jinmeng Zhou
2026-09-03 11:09 ` Muchun Song
2026-09-04 2:27 ` Hongfu Li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox