[Devel] [PATCH RH7] memcg leak due to missing css_put on last kmem uncharge
Vasily Averin
vvs at virtuozzo.com
Wed Feb 24 18:22:21 MSK 2021
On 2/24/21 5:38 PM, Vasily Averin wrote:
> On 2/24/21 11:47 AM, Kirill Tkhai wrote:
>> On 22.02.2021 21:40, Vasily Averin wrote:
>>> When mem_cgroup is removes mem_cgroup_css_offline() calls
>>> memcg_deactivate_kmem() which disables kmem accounting.
>>> If memcg still have some charged kmem final css_put is not called,
>>> and delayed till last kmem will be uncharged.
>>>
>>> Usually kmem is uncharged by using memcg_uncharge_kmem() which have
>>> according checks and if required calls final css_put().
>>>
>>> Though patch added to vz7.162.14 kernel
>>> "mm/memcg: Use per-cpu stock charges for ->kmem and ->cache counters"
>>> enabled kmem charge/uncharge in refill_stock()/drain_stock()
>>> without using of memcg_uncharge_kmem(), as result nobody called
>>> final css_put() after last kmem uncharge.
>>>
>>> This patch adds css_get/put for safe access to memcg in drain_stock(),
>>> and calls an additional css_put() after last kmem uncharge.
>>>
>>> Fixes: "mm/memcg: Use per-cpu stock charges for ->kmem and ->cache counters"
>>> https://bugs.openvz.org/browse/OVZ-7250
>>> Signed-off-by: Vasily Averin <vvs at virtuozzo.com>
>>> ---
>>> mm/memcontrol.c | 20 ++++++++++++++++----
>>> 1 file changed, 16 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
>>> index e0a4309..24e3bd7 100644
>>> --- a/mm/memcontrol.c
>>> +++ b/mm/memcontrol.c
>>> @@ -439,6 +439,8 @@ enum {
>>> KMEM_ACCOUNTED_DEAD, /* dead memcg with pending kmem charges */
>>> };
>>>
>>> +static void memcg_kmem_release_css(struct mem_cgroup *memcg);
>>> +
>>> static struct mem_cgroup_per_node *
>>> mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid)
>>> {
>>> @@ -2928,11 +2930,15 @@ static void drain_stock(struct memcg_stock_pcp *stock)
>>> {
>>> struct mem_cgroup *old = stock->cached;
>>> unsigned long nr_pages = stock->nr_pages + stock->cache_nr_pages + stock->kmem_nr_pages;
>>> + u64 kmem = 1;
>>> +
>>> + if (!old)
>>> + return;
>>>
>>> if (stock->cache_nr_pages)
>>> page_counter_uncharge(&old->cache, stock->cache_nr_pages);
>>> if (stock->kmem_nr_pages)
>>> - page_counter_uncharge(&old->kmem, stock->kmem_nr_pages);
>>> + kmem = page_counter_uncharge(&old->kmem, stock->kmem_nr_pages);
>>>
>>> if (nr_pages) {
>>> page_counter_uncharge(&old->memory, nr_pages);
>>> @@ -2942,6 +2948,9 @@ static void drain_stock(struct memcg_stock_pcp *stock)
>>> stock->kmem_nr_pages = 0;
>>> stock->cache_nr_pages = 0;
>>> }
>>> + css_put(&old->css);
>>
>> css_put()/css_get() pair looks excess. What is your arguments, why do we need them?
>> We have a problem with kmem only, while the rest of accounting looks safe:
>> they are safely uncharged from css_offline->mem_cgroup_reparent_charges(), and they
>> never own css counter.
>
> We know that kmem can be uncharged after mem_cgroup_css_offline() -> memcg_deactivate_kmem()
> because kmem was not 0 inside memcg_deactivate_kmem and according css_put() was not called.
>
> I did not investigated how is called drain_stock uncharged last kmem,
> and I do not see who keeps memcg refcount here.
> Please explain this if you know.
>
> If drain_stock() can be called after end of mem_cgroup_css_offline it is a problem.
> css_get/put present in refill_stock()/drain_stock() long time ago,
> though I did not investigated when and why exactly it was added.
>
> Anyway, I'm not sure that it is really required in vz7 kernel,
> we did not saw any related troubles.
I've found finally
mem_cgroup_css_offline
mem_cgroup_reparent_charges
drain_all_stock_sync()
drain_stock()
So now I'm agree: additional css_get/put in refill_stock/drain_stock() are not required.
More information about the Devel
mailing list