Re: [PATCH 04/11] memcg: add cma charge/uncharge functions for area counters

Eric Chanudet <[email protected]>
Newsgroups dev.linux.lists.sashiko-reviews
Message-ID <[email protected]>
On Fri, Aug 21, 2026 at 07:21:16PM +0000, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] Dynamically disabling memory_cma_accounting via cgroupfs remount prevents previously charged CMA pages from being uncharged, leading to permanent resource leaks and buddy allocator corruption.
> - [High] Hardcoded GFP_KERNEL strips caller allocation constraints, causing unwanted memcg OOM kills and warnings.
> --
> 
> --- Patch [4]: [PATCH 04/11] memcg: add cma charge/uncharge functions for area counters ---
> commit 637000e435d7ad7a20a55418ada4d77115a47082
> Author: Eric Chanudet <[email protected]>
> 
> memcg: add cma charge/uncharge functions for area counters
> 
> Introduce mem_cgroup_charge_cma() and mem_cgroup_uncharge_cma() to
> account CMA allocations under memcg when memory_cma_accounting is
> enabled in cgroupfs. memcg counters to account for allocation in each
> CMA area are kcalloc'd in mem_cgroup_alloc() and added to the
> page-counter hierarchy in mem_cgroup_css_alloc().
> 
> [ ... ]
> 
> > diff --git a/mm/memcontrol.c b/mm/memcontrol.c
> > index 6dc4888a90f3f..8eca00d30fc50 100644
> > --- a/mm/memcontrol.c
> > +++ b/mm/memcontrol.c
> 
> [ ... ]
> 
> > @@ -5213,6 +5233,102 @@ int mem_cgroup_swapin_charge_folio(struct folio *folio, unsigned short id,
> >  	return ret;
> >  }
> >  
> > +#ifdef CONFIG_CMA
> > +static bool memcg_accounts_cma(void)
> > +{
> > +	return cgrp_dfl_root.flags & CGRP_ROOT_MEMORY_CMA_ACCOUNTING;
> > +}
> > +
> > +int mem_cgroup_charge_cma(struct page *page, unsigned long count,
> > +			  struct cma *cma)
> > +{
> > +	struct page_counter *counter, *fail;
> > +	struct obj_cgroup *objcg;
> > +	struct mem_cgroup *memcg;
> > +	unsigned int i;
> > +	int rc = 0;
> > +
> > +	if (mem_cgroup_disabled() || !memcg_accounts_cma())
> > +		return 0;
> > +
> > +	memcg = get_mem_cgroup_from_current();
> > +	if (!memcg)
> > +		return 0;
> > +
> > +	if (mem_cgroup_is_root(memcg))
> > +		goto cgroup_put;
> > +
> > +	rc = try_charge_memcg(memcg, GFP_KERNEL, count);
> 
> [Severity: High]
> Can this hardcoded GFP_KERNEL cause unwanted memcg OOM kills and warnings? By
> stripping the caller's allocation constraints, if the memcg is at its limit and
> the caller requested no warnings or retry constraints, try_charge_memcg() could
> invoke the memcg OOM killer and print allocation failure warnings.
> 
> Is it possible to pass the caller's gfp_t mask to this routine instead of
> hardcoding GFP_KERNEL?
> 

Yes, charge_cma should pass gfp. I don't think CMA allocs will have
other flags that affect try_charge_memcg for now, but still.

> > +	if (rc)
> > +		goto cgroup_put;
> > +
> > +	counter = &memcg->cma_counters[cma_area_index(cma)];
> > +	if (!page_counter_try_charge(counter, count, &fail)) {
> > +		refill_stock(memcg, count);
> > +		rc = -ENOMEM;
> > +		goto cgroup_put;
> > +	}
> > +
> > +	objcg = get_obj_cgroup_from_memcg(memcg);
> > +	if (folio_test_large(page_folio(page))) {
> > +		commit_charge(page_folio(page), objcg);
> > +	} else {
> > +		obj_cgroup_get_many(objcg, count - 1);
> > +		for (i = 0; i < count; i++)
> > +			commit_charge(page_folio(page + i), objcg);
> > +	}
> > +
> > +cgroup_put:
> > +	mem_cgroup_put(memcg);
> > +	return rc;
> > +}
> > +
> > +void mem_cgroup_uncharge_cma(struct page *page, unsigned long count,
> > +			     struct cma *cma)
> > +{
> > +	struct page_counter *counter;
> > +	struct obj_cgroup *objcg;
> > +	struct mem_cgroup *memcg;
> > +	struct folio *folio;
> > +	unsigned int i;
> > +
> > +	if (mem_cgroup_disabled() || !memcg_accounts_cma())
> > +		return;
> 
> [Severity: High]
> Can dynamically disabling memory_cma_accounting via cgroupfs remount cause
> permanent resource leaks and buddy allocator corruption here? 
> 

It does. folio->memcg_data/objcg should be checked instead.

> If a CMA allocation is charged while memory_cma_accounting is enabled, and a
> privileged user later remounts cgroup2 without specifying the
> memory_cma_accounting option, memcg_accounts_cma() will evaluate to false. 
> 
> This early return would skip the uncharge and leave folio->memcg_data
> populated. When the pages are returned to the buddy allocator, wouldn't
> __free_pages_prepare() detect the non-zero memcg_data and fire a bad_page()
> warning, permanently leaking the cgroup and cma_counters?
> 
> > +
> > +	/*
> > +	 * Get the objcg from the first page.
> > +	 * page_objcg() expects MEMCG_DATA_KMEM, but for CMA we used
> > +	 * commit_charge() which sets folio->memcg_data = objcg
> > +	 * without flags, so we cannot use it.
> > +	 */
> 
> [ ... ]
> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
> 

-- 
Eric Chanudet
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.