From: Kairui Song The xarray node allocations in __folio_freeze_split_unmap_file() need to be charged to the folio's memcg, so move the memcg switch from __folio_split() into the helper. The anon split helper and the after-split folio freeing perform no chargeable allocations, so no memcg handling is left in __folio_split(). Rename its out_no_memcg label to out. Acked-by: Zi Yan Signed-off-by: Kairui Song --- mm/huge_memory.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 1a3ca2606c60..29b46f039d1e 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -4076,6 +4076,7 @@ static int __folio_split_unmap_and_freeze_file(struct folio *folio, unsigned int struct address_space *mapping = folio->mapping; XA_STATE(xas, &mapping->i_pages, folio->index); struct folio *end_folio = folio_next(folio); + struct mem_cgroup *memcg, *old_memcg; struct folio *new_folio, *next; int nr_shmem_dropped = 0; unsigned int min_order; @@ -4088,9 +4089,18 @@ static int __folio_split_unmap_and_freeze_file(struct folio *folio, unsigned int if (new_order < min_order) return -EINVAL; + /* + * Switch to folio's memcg as xarray node allocation can happen and + * needs to charge to it. + */ + memcg = get_mem_cgroup_from_folio(folio); + old_memcg = set_active_memcg(memcg); + gfp = current_gfp_context(mapping_gfp_mask(mapping) & GFP_RECLAIM_MASK); - if (!filemap_release_folio(folio, gfp)) - return -EBUSY; + if (!filemap_release_folio(folio, gfp)) { + ret = -EBUSY; + goto fail_free; + } mapping_set_update(&xas, mapping); @@ -4223,6 +4233,9 @@ static int __folio_split_unmap_and_freeze_file(struct folio *folio, unsigned int */ i_mmap_unlock_read(mapping); fail_free: + /* Restore the previously active memcg */ + set_active_memcg(old_memcg); + mem_cgroup_put(memcg); xas_destroy(&xas); return ret; } @@ -4254,7 +4267,6 @@ static int __folio_split(struct folio *folio, unsigned int new_order, { struct folio *end_folio = folio_next(folio); bool is_anon = folio_test_anon(folio); - struct mem_cgroup *memcg, *old_memcg; int old_order = folio_order(folio); struct folio *new_folio, *next; int ret; @@ -4264,27 +4276,20 @@ static int __folio_split(struct folio *folio, unsigned int new_order, if (folio != page_folio(split_at) || folio != page_folio(lock_at)) { ret = -EINVAL; - goto out_no_memcg; + goto out; } if (new_order >= old_order) { ret = -EINVAL; - goto out_no_memcg; + goto out; } ret = folio_check_splittable(folio, new_order, split_type); if (ret) { VM_WARN_ONCE(ret == -EINVAL, "Tried to split an unsplittable folio"); - goto out_no_memcg; + goto out; } - /* - * switch to folio's memcg as xarray node allocation can happen and - * needs to charge to it. - */ - memcg = get_mem_cgroup_from_folio(folio); - old_memcg = set_active_memcg(memcg); - if (is_anon) ret = __folio_split_unmap_and_freeze_anon(folio, new_order, split_at, true, true, list, split_type); @@ -4311,10 +4316,7 @@ static int __folio_split(struct folio *folio, unsigned int new_order, free_folio_and_swap_cache(new_folio); } - /* restore to caller's old_memcg */ - set_active_memcg(old_memcg); - mem_cgroup_put(memcg); -out_no_memcg: +out: if (is_pmd_order(old_order)) count_vm_event(!ret ? THP_SPLIT_PAGE : THP_SPLIT_PAGE_FAILED); count_mthp_stat(old_order, !ret ? MTHP_STAT_SPLIT : MTHP_STAT_SPLIT_FAILED); -- 2.55.0