mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
mm/hugetlb: charge folios to the target mm's memcg
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.
Link: https://lore.kernel.org/20260903075048.3316-1-zhoujinmeng@bytedance.com
Fixes: 8cba9576df ("hugetlb: memcg: account hugetlb-backed memory in memory controller")
Signed-off-by: Jinmeng Zhou <zhoujinmeng@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Reviewed-by: Hongfu Li <lihongfu@kylinos.cn>
Cc: David Hildenbrand <david@kernel.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: <stable@vger.kernel.org>
This commit is contained in:
parent
e1e8650302
commit
c2deb1356d
|
|
@ -694,7 +694,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,
|
||||
|
|
|
|||
|
|
@ -647,7 +647,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);
|
||||
|
|
@ -1146,9 +1147,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,
|
||||
|
|
|
|||
|
|
@ -2844,6 +2844,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
|
||||
|
|
@ -2853,7 +2854,8 @@ void wait_for_freed_hugetlb_folios(void)
|
|||
* -ENOSPC if cgroup charging fails or no folio is available.
|
||||
*/
|
||||
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;
|
||||
|
|
@ -2908,7 +2910,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
|
||||
|
|
@ -3051,7 +3054,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -5265,6 +5265,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
|
||||
|
|
@ -5274,9 +5275,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;
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user