memcg: tcp memcontrol fixes.
Subsystems (6)
cover memcg: tcp memcontrol fixes.
I'm very sorry if you received this e-mail twice.
==
This series is 3 bugfixes for memcg's kmem.tcp memory controller. Maybe this should go via network tree.
(CC akpm for noticing an ugly change in res_counter.)
All patches are generated onto today linus's git tree.
Brief description:
Patch 1/3 .... tcp memcontrol doesn't see memcg's use_hierarchy value. Fix it.
Patch 2/3 and 3/3 ....
Because tcp memcontrol doesn't do any accounting when limit=RESOUCE_MAX, there will be account leakage when limit is changed. This can trigger WARN_ON() in res_counter which checks usage >= 0.
Patch 2/3 .... don't call static_key_slow_dec(&memcg_socket_limit_enabled) until
a cgroup under accounted is destroyed.
Patch 3/3 .... add res_counter_uncharge_nowarn() to ignore leakage.
Thanks,
-Kame
PATCH 1/3 memcg/tcp : fix to see use_hierarchy in tcp memcontrol cgroup
Now, tcp memory control cgroup ignores memcg's use_hierarchy value and act as use_hierarchy=1 always. After this patch, tcp memcontrol will work as memcg is designed.
Note:
I know there is a discussion to remove use_hierarchy but this is BUG, now.
--- include/linux/memcontrol.h | 3 +++ mm/memcontrol.c | 5 +++++ net/ipv4/tcp_memcontrol.c | 2 +- 3 files changed, 9 insertions(+), 1 deletions(-)
include/linux/memcontrol.h +3 -0
@@ -199,6 +199,9 @@ void mem_cgroup_split_huge_fixup(struct page *head);bool mem_cgroup_bad_page_check (struct page *page);void mem_cgroup_print_bad_page (struct page *page);#endif + +bool mem_cgroup_use_hierarchy (struct mem_cgroup *memcg); +#else /* CONFIG_CGROUP_MEM_RES_CTLR */ struct mem_cgroup ;
mm/memcontrol.c +5 -0
@@ -867,6 +867,11 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)return memcg; } +bool mem_cgroup_use_hierarchy (struct mem_cgroup *memcg) +{ +return memcg->use_hierarchy; +} +/** * mem_cgroup_iter - iterate over memory cgroup hierarchy * @root: hierarchy root
net/ipv4/tcp_memcontrol.c +1 -1
@@ -75,7 +75,7 @@ int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) tcp->tcp_memory_pressure =0 ; parent_cg = tcp_prot.proto_cgroup (parent); -if (parent_cg) +if (parent_cg &&mem_cgroup_use_hierarchy (parent)) res_parent = parent_cg->memory_allocated;res_counter_init (&tcp->tcp_memory_allocated, res_parent);
Signature · 1 line
1.7.4.1
Re: [PATCH 1/3] [BUGFIX] memcg/tcp : fix to see use_hierarchy in tcp memcontrol cgroup
Quoted 8 lines · KAMEZAWA Hiroyuki
Now, tcp memory control cgroup ignores memcg's
use_hierarchyvalue and act as use_hierarchy=1 always. After this patch, tcp memcontrol will work as memcg is designed.Note:
I know there is a discussion to removeuse_hierarchybut this is BUG, now.
Kame,
Are you sure about that?
I just tried it myself, and it seems to work:
root@inf5072-11:~/glommer-temporary/a/b# cat memory.kmem.tcp.usage_in_bytes 724992 root@inf5072-11:~/glommer-temporary/a/b# cat ../memory.kmem.tcp.usage_in_bytes 0
Did you got this conclusion through testing or code inspection?
As a matter of fact, that's why I believe the current behavior is indeed correct:
the res_counter is initialized as:
parent_cg = tcp_prot.proto_cgroup(parent);
if (parent_cg)
res_parent = parent_cg->memory_allocated;
res_counter_init(&tcp->tcp_memory_allocated, res_parent);now, parent is drawn from parent_mem_cgroup(), that reads as follows:
struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg)
{
if (!memcg->res.parent)
return NULL;
return mem_cgroup_from_res_counter(memcg->res.parent, res);
}so if we have use_hierarchy = 0, res.parent should be NULL (because that is the way we initialize it)
Re: [PATCH 1/3] [BUGFIX] memcg/tcp : fix to see use_hierarchy in tcp memcontrol cgroup
Quoted 46 lines · Glauber Costa
Quoted 8 lines · KAMEZAWA Hiroyuki
Now, tcp memory control cgroup ignores memcg's
use_hierarchyvalue and act as use_hierarchy=1 always. After this patch, tcp memcontrol will work as memcg is designed.Note:
I know there is a discussion to removeuse_hierarchybut this is BUG, now.Kame,
Are you sure about that?
I just tried it myself, and it seems to work:
root@inf5072-11:~/glommer-temporary/a/b# cat memory.kmem.tcp.usage_in_bytes 724992 root@inf5072-11:~/glommer-temporary/a/b# cat ../memory.kmem.tcp.usage_in_bytes 0Did you got this conclusion through testing or code inspection?
As a matter of fact, that's why I believe the current behavior is indeed correct:
the
res_counteris initialized as:parent_cg = tcp_prot.proto_cgroup(parent); if (parent_cg) res_parent = parent_cg->memory_allocated; res_counter_init(&tcp->tcp_memory_allocated, res_parent);now, parent is drawn from
parent_mem_cgroup(), that reads as follows:struct
mem_cgroup*parent_mem_cgroup(structmem_cgroup*memcg){ if (!memcg->res.parent) return NULL; return mem_cgroup_from_res_counter(memcg->res.parent, res); }
Quoted 3 lines
so if we have
use_hierarchy= 0, res.parent should be NULL (because that is the way we initialize it)
Ah, sorry. you're right. please forget this patch.
To be honest, I wrote this after seeing WARN_ON in patch 2 and 3 and misunderstood the code at writing patch 2 and 3.
Thanks,
-Kame
PATCH 2/3 memcg/tcp: remove static_branch_slow_dec() at changing limit
In reply to KAMEZAWA Hiroyukitcp memcontrol uses static_branch to optimize limit=RESOURCE_MAX case. If all cgroup's limit=RESOUCE_MAX, resource usage is not accounted. But it's buggy now.
For example, do following
# while sleep 1;do echo 9223372036854775807 > /cgroup/memory/A/memory.kmem.tcp.limit_in_bytes; echo 300M > /cgroup/memory/A/memory.kmem.tcp.limit_in_bytes; done
and run network application under A. tcp's usage is sometimes accounted and sometimes not accounted because of frequent changes of static_branch. Then, finally, you can see broken tcp.usage_in_bytes.WARN_ON() is printed because res_counter->usage goes below 0.
==
kernel: ------------[ cut here ]----------
kernel: WARNING: at kernel/res_counter.c:96 res_counter_uncharge_locked+0x37/0x40()
<snip>
kernel: Pid: 17753, comm: bash Tainted: G W 3.3.0+ #99
kernel: Call Trace:
kernel: <IRQ> [<ffffffff8104cc9f>] warn_slowpath_common+0x7f/0xc0
kernel: [<ffffffff810d7e88>] ? rb_reserve__next_event+0x68/0x470
kernel: [<ffffffff8104ccfa>] warn_slowpath_null+0x1a/0x20
kernel: [<ffffffff810b4e37>] res_counter_uncharge_locked+0x37/0x40
...
==
This patch removes static_branch_slow_dec() at changing res_counter's limit to RESOUCE_MAX. By this, once accounting started, the accountting will continue until the tcp cgroup is destroyed.
I think this will not be problem in real use.
--- include/net/tcp_memcontrol.h | 1 + net/ipv4/tcp_memcontrol.c | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-)
include/net/tcp_memcontrol.h +1 -0
@@ -9,6 +9,7 @@ struct tcp_memcontrol {/* those two are read-mostly, leave them at the end */ long tcp_prot_mem[3 ];int tcp_memory_pressure; +bool accounting; };struct cg_proto *tcp_proto_cgroup (struct mem_cgroup *memcg);
net/ipv4/tcp_memcontrol.c +18 -6
@@ -49,6 +49,20 @@ static void memcg_tcp_enter_memory_pressure(struct sock *sk) }EXPORT_SYMBOL (memcg_tcp_enter_memory_pressure); +static void tcp_start_accounting (struct tcp_memcontrol *tcp) +{ +if (tcp->accounting) +return ; + tcp->accounting = true; +static_key_slow_inc (&memcg_socket_limit_enabled); +} + +static void tcp_end_accounting (struct tcp_memcontrol *tcp) +{ +if (tcp->accounting) +static_key_slow_dec (&memcg_socket_limit_enabled); +} +int tcp_init_cgroup (struct cgroup *cgrp,struct cgroup_subsys *ss) {/*
@@ -73,6 +87,7 @@ int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) tcp->tcp_prot_mem[1 ] = net->ipv4.sysctl_tcp_mem[1 ]; tcp->tcp_prot_mem[2 ] = net->ipv4.sysctl_tcp_mem[2 ]; tcp->tcp_memory_pressure =0 ; + tcp->accounting = false; parent_cg = tcp_prot.proto_cgroup (parent);if (parent_cg &&mem_cgroup_use_hierarchy (parent))
@@ -110,8 +125,7 @@ void tcp_destroy_cgroup(struct cgroup *cgrp) val =res_counter_read_u64 (&tcp->tcp_memory_allocated,RES_LIMIT ); -if (val !=RESOURCE_MAX ) -static_key_slow_dec (&memcg_socket_limit_enabled); +tcp_end_accounting (tcp); }EXPORT_SYMBOL (tcp_destroy_cgroup);
@@ -142,10 +156,8 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) tcp->tcp_prot_mem[i] =min_t (long, val >>PAGE_SHIFT , net->ipv4.sysctl_tcp_mem[i]); -if (val ==RESOURCE_MAX && old_lim !=RESOURCE_MAX ) -static_key_slow_dec (&memcg_socket_limit_enabled); -else if (old_lim ==RESOURCE_MAX && val !=RESOURCE_MAX ) -static_key_slow_inc (&memcg_socket_limit_enabled); +if (old_lim ==RESOURCE_MAX && val !=RESOURCE_MAX ) +tcp_start_accounting (tcp);return 0 ; }
Signature · 1 line
1.7.4.1
Re: [BUGFIX][PATCH 2/3] memcg/tcp: remove static_branch_slow_dec() at changing limit
Quoted 27 lines · KAMEZAWA Hiroyuki
tcp memcontrol uses
static_branchto optimize limit=RESOURCE_MAX case. If all cgroup's limit=RESOUCE_MAX, resource usage is not accounted. But it's buggy now.For example, do following
# while sleep 1;do echo 9223372036854775807> /cgroup/memory/A/memory.kmem.tcp.limit_in_bytes; echo 300M> /cgroup/memory/A/memory.kmem.tcp.limit_in_bytes; doneand run network application under A. tcp's usage is sometimes accounted and sometimes not accounted because of frequent changes of
static_branch. Then, finally, you can see broken tcp.usage_in_bytes.WARN_ON()is printed becauseres_counter->usagegoes below 0.
==
kernel: ------------[ cut here ]----------
kernel: WARNING: atkernel/res_counter.c:96res_counter_uncharge_locked+0x37/0x40()
<snip>
kernel: Pid: 17753, comm: bash Tainted: G W 3.3.0+ #99
kernel: Call Trace:
kernel:<IRQ> [<ffffffff8104cc9f>]warn_slowpath_common+0x7f/0xc0
kernel: [<ffffffff810d7e88>] ?rb_reserve__next_event+0x68/0x470
kernel: [<ffffffff8104ccfa>]warn_slowpath_null+0x1a/0x20
kernel: [<ffffffff810b4e37>]res_counter_uncharge_locked+0x37/0x40
...
==
Quoted 6 lines
This patch removes
static_branch_slow_dec()at changing res_counter's limit toRESOUCE_MAX. By this, once accounting started, the accountting will continue until the tcp cgroup is destroyed.I think this will not be problem in real use.
So...
Are the warnings still there if you have your other patch in this series? Maybe what we should do is, flush the resource counters so they go back to 0 besides decrementing the static branch. This way we get a more consistent behavior.
Another thing to keep in mind, is that the static branch will only be inactive if we turn off *all* controllers. You see this happening because you are only testing with one.
So even if we go to the route you're proposing, we could probably try doing something on the
global level, instead of a per-memcg boolean flat.
Re: [BUGFIX][PATCH 2/3] memcg/tcp: remove static_branch_slow_dec() at changing limit
Quoted 32 lines · Glauber Costa
Quoted 31 lines · KAMEZAWA Hiroyuki
tcp memcontrol uses
static_branchto optimize limit=RESOURCE_MAX case. If all cgroup's limit=RESOUCE_MAX, resource usage is not accounted. But it's buggy now.For example, do following
# while sleep 1;do echo 9223372036854775807> /cgroup/memory/A/memory.kmem.tcp.limit_in_bytes; echo 300M> /cgroup/memory/A/memory.kmem.tcp.limit_in_bytes; doneand run network application under A. tcp's usage is sometimes accounted and sometimes not accounted because of frequent changes of
static_branch. Then, finally, you can see broken tcp.usage_in_bytes.WARN_ON()is printed becauseres_counter->usagegoes below 0.
==
kernel: ------------[ cut here ]----------
kernel: WARNING: atkernel/res_counter.c:96res_counter_uncharge_locked+0x37/0x40()
<snip>
kernel: Pid: 17753, comm: bash Tainted: G W 3.3.0+ #99
kernel: Call Trace:
kernel:<IRQ> [<ffffffff8104cc9f>]warn_slowpath_common+0x7f/0xc0
kernel: [<ffffffff810d7e88>] ?rb_reserve__next_event+0x68/0x470
kernel: [<ffffffff8104ccfa>]warn_slowpath_null+0x1a/0x20
kernel: [<ffffffff810b4e37>]res_counter_uncharge_locked+0x37/0x40
...
==This patch removes
static_branch_slow_dec()at changing res_counter's limit toRESOUCE_MAX. By this, once accounting started, the accountting will continue until the tcp cgroup is destroyed.
Quoted 6 lines
Quoted 2 lines
I think this will not be problem in real use.
So...
Are the warnings still there if you have your other patch in this series?
I wrote patch 3/3 after 2/3 because I found all case cannot be fixed by this.
So, comparing patch 3/3 this fixes is leaking.
Considering following sequence
enable accounting
tcp allocate buffer
disable accounting
tcp free buffer
The accounted usage nerver disappear. This is the probelem which cannot be covered by patch 3/3. Maybe it's better to change order of patches 3/3 -> 2/3 and describe this explicitly.
Quoted 4 lines
Maybe what we should do is, flush the resource counters so they go back to 0 besides decrementing the static branch. This way we get a more consistent behavior.
set all memcg's usage to be 0 at enable/disable accounting ? But, there is a problem which static_branch() update is slow. So, IIUC, we can't catch all cases because of races.
Quoted 3 lines
Another thing to keep in mind, is that the static branch will only be inactive if we turn off *all* controllers. You see this happening because you are only testing with one.
yes. So, the behavior change by this patch will not affect usual cases.
Quoted 3 lines
So even if we go to the route you're proposing, we could probably try doing something on the
global level, instead of a per-memcg boolean flat.
In global level, static_key's counter handles it.
Thanks,
-Kame
Re: [BUGFIX][PATCH 2/3] memcg/tcp: remove static_branch_slow_dec() at changing limit
Quoted 70 lines · KAMEZAWA Hiroyuki
Quoted 32 lines · Glauber Costa
Quoted 31 lines · KAMEZAWA Hiroyuki
tcp memcontrol uses
static_branchto optimize limit=RESOURCE_MAX case. If all cgroup's limit=RESOUCE_MAX, resource usage is not accounted. But it's buggy now.For example, do following
# while sleep 1;do echo 9223372036854775807> /cgroup/memory/A/memory.kmem.tcp.limit_in_bytes; echo 300M> /cgroup/memory/A/memory.kmem.tcp.limit_in_bytes; doneand run network application under A. tcp's usage is sometimes accounted and sometimes not accounted because of frequent changes of
static_branch. Then, finally, you can see broken tcp.usage_in_bytes.WARN_ON()is printed becauseres_counter->usagegoes below 0.
==
kernel: ------------[ cut here ]----------
kernel: WARNING: atkernel/res_counter.c:96res_counter_uncharge_locked+0x37/0x40()
<snip>
kernel: Pid: 17753, comm: bash Tainted: G W 3.3.0+ #99
kernel: Call Trace:
kernel:<IRQ> [<ffffffff8104cc9f>]warn_slowpath_common+0x7f/0xc0
kernel: [<ffffffff810d7e88>] ?rb_reserve__next_event+0x68/0x470
kernel: [<ffffffff8104ccfa>]warn_slowpath_null+0x1a/0x20
kernel: [<ffffffff810b4e37>]res_counter_uncharge_locked+0x37/0x40
...
==This patch removes
static_branch_slow_dec()at changing res_counter's limit toRESOUCE_MAX. By this, once accounting started, the accountting will continue until the tcp cgroup is destroyed.Quoted 6 lines
Quoted 2 lines
I think this will not be problem in real use.
So...
Are the warnings still there if you have your other patch in this series?
I wrote patch 3/3 after 2/3 because I found all case cannot be fixed by this.
So, comparing patch 3/3 this fixes is leaking.
Considering following sequenceenable accounting
tcp allocate buffer
disable accounting
tcp free bufferThe accounted usage nerver disappear. This is the probelem which cannot be covered by patch 3/3. Maybe it's better to change order of patches 3/3 -> 2/3 and describe this explicitly.
Quoted 4 lines
Maybe what we should do is, flush the resource counters so they go back to 0 besides decrementing the static branch. This way we get a more consistent behavior.
set all memcg's usage to be 0 at enable/disable accounting ? But, there is a problem which
static_branch()update is slow. So, IIUC, we can't catch all cases because of races.Quoted 3 lines
Another thing to keep in mind, is that the static branch will only be inactive if we turn off *all* controllers. You see this happening because you are only testing with one.
Quoted 8 lines
yes. So, the behavior change by this patch will not affect usual cases.
Quoted 3 lines
So even if we go to the route you're proposing, we could probably try doing something on the
global level, instead of a per-memcg boolean flat.In global level, static_key's counter handles it.
I gave it a bit more thought through the night... and I guess your solution is okay.
PATCH 3/3 memcg/tcp: ignore tcp usage before accounting started
In reply to KAMEZAWA Hiroyukitcp memcontrol starts accouting after res->limit is set. So, if a sockets starts before setting res->limit, there are already used resource. After setting res->limit, the resource (already used) will be uncharged and make res_counter below 0 because they are not charged. This causes warning.
This patch fixes that by adding res_counter_uncharge_nowarn(). (*) We cannot avoid this while we have 'account start' switch.
--- include/linux/res_counter.h | 2 ++ include/net/sock.h | 3 ++- kernel/res_counter.c | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletions(-)
include/linux/res_counter.h +2 -0
@@ -134,6 +134,8 @@ int __must_check res_counter_charge_nofail(struct res_counter *counter,void res_counter_uncharge_locked (struct res_counter *counter,unsigned long val);void res_counter_uncharge (struct res_counter *counter,unsigned long val); +void res_counter_uncharge_nowarn (struct res_counter *counter, +unsigned long val);/** * res_counter_margin - calculate chargeable space of a counter
include/net/sock.h +2 -1
@@ -1048,7 +1048,8 @@ static inline void memcg_memory_allocated_add(struct cg_proto *prot,static inline void memcg_memory_allocated_sub (struct cg_proto *prot,unsigned long amt) { -res_counter_uncharge (prot->memory_allocated, amt <<PAGE_SHIFT ); +res_counter_uncharge_nowarn (prot->memory_allocated, + amt <<PAGE_SHIFT ); }static inline u64 memcg_memory_allocated_read (struct cg_proto *prot)
kernel/res_counter.c +18 -0
@@ -113,6 +113,24 @@ void res_counter_uncharge(struct res_counter *counter, unsigned long val)local_irq_restore (flags); } +void res_counter_uncharge_nowarn (struct res_counter *counter, +unsigned long val) +{ +struct res_counter *c; +unsigned long flags; + +local_irq_save (flags); + +for (c = counter; c !=NULL ; c = c->parent) { +spin_lock (&c->lock); +if (c->usage < val) + val = c->usage; +res_counter_uncharge_locked (c, val); +spin_unlock (&c->lock); + } +local_irq_restore (flags); +} +static inline unsigned long long *res_counter_member (struct res_counter *counter,int member)
Signature · 1 line
1.7.4.1
Re: [BUGFIX][PATCH 3/3] memcg/tcp: ignore tcp usage before accounting started
Quoted 9 lines · KAMEZAWA Hiroyuki
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. After settingres->limit, the resource (already used) will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.This patch fixes that by adding
res_counter_uncharge_nowarn(). (*) We cannot avoid this while we have 'account start' switch.Signed-off-by KAMEZAWA Hiroyuki<[email protected]>
Fine by me.
PATCH 1/1 memcg/tcp: fix warning caused b res->usage go to negative.
Maybe what we can do before lsf/mm summit will be this (avoid warning.) This patch is onto linus's git tree. Patch description is updated.
Thanks.
-Kame
==
Quoted 1 line
From
4ab80f84bbcb02a790342426c1de84aeb17fcbe9Mon Sep 17 00:00:00 2001
From: KAMEZAWA Hiroyuki <[email protected]>
Date: Thu, 29 Mar 2012 14:59:04 +0900
Subject: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
tcp memcontrol starts accouting after res->limit is set. So, if a sockets starts before setting res->limit, there are already used resource. At setting res->limit, accounting starts. The resource will be uncharged and make res_counter below 0 because they are not charged. This causes warning.
==
kernel: ------------[ cut here ]----------
kernel: WARNING: at kernel/res_counter.c:96 res_counter_uncharge_locked+0x37/0x40()
<snip>
kernel: Pid: 17753, comm: bash Tainted: G W 3.3.0+ #99
kernel: Call Trace:
kernel: <IRQ> [<ffffffff8104cc9f>] warn_slowpath_common+0x7f/0xc0
kernel: [<ffffffff810d7e88>] ? rb_reserve__next_event+0x68/0x470
kernel: [<ffffffff8104ccfa>] warn_slowpath_null+0x1a/0x20
kernel: [<ffffffff810b4e37>] res_counter_uncharge_locked+0x37/0x40
...
==
This patch fixes that by adding res_counter_uncharge_nowarn() and hide the wrong accounting.
The reason for this fix is :
- For avoid overheads, we don't account tcp usage by a cgroup before setting limit. So, we cannot know the amount of possible error when we start accounting. If we have this on/off switch for performance, this cannot be avoidable.
Consideration:
- As memcg, if some marking to resources as PCG_USED could be used.. ...we don't have problems. But it adds overhead.
TODO:
- When enable/disable tcp accounting frequently, we'll see usage accounting leak. This should be fixed. (still under discussion.)
- sockets_allocated has the same trouble. But it has no warning and never shows negative value even if it's negative.
Changelog:
- updated patch description.
--- include/linux/res_counter.h | 2 ++ include/net/sock.h | 3 ++- kernel/res_counter.c | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletions(-)
include/linux/res_counter.h +2 -0
@@ -134,6 +134,8 @@ int __must_check res_counter_charge_nofail(struct res_counter *counter,void res_counter_uncharge_locked (struct res_counter *counter,unsigned long val);void res_counter_uncharge (struct res_counter *counter,unsigned long val); +void res_counter_uncharge_nowarn (struct res_counter *counter, +unsigned long val);/** * res_counter_margin - calculate chargeable space of a counter
include/net/sock.h +2 -1
@@ -1048,7 +1048,8 @@ static inline void memcg_memory_allocated_add(struct cg_proto *prot,static inline void memcg_memory_allocated_sub (struct cg_proto *prot,unsigned long amt) { -res_counter_uncharge (prot->memory_allocated, amt <<PAGE_SHIFT ); +res_counter_uncharge_nowarn (prot->memory_allocated, + amt <<PAGE_SHIFT ); }static inline u64 memcg_memory_allocated_read (struct cg_proto *prot)
kernel/res_counter.c +18 -0
@@ -113,6 +113,24 @@ void res_counter_uncharge(struct res_counter *counter, unsigned long val)local_irq_restore (flags); } +void res_counter_uncharge_nowarn (struct res_counter *counter, +unsigned long val) +{ +struct res_counter *c; +unsigned long flags; + +local_irq_save (flags); + +for (c = counter; c !=NULL ; c = c->parent) { +spin_lock (&c->lock); +if (c->usage < val) + val = c->usage; +res_counter_uncharge_locked (c, val); +spin_unlock (&c->lock); + } +local_irq_restore (flags); +} +static inline unsigned long long *res_counter_member (struct res_counter *counter,int member)
Signature · 1 line
1.7.4.1
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
Quoted 11 lines · KAMEZAWA Hiroyuki
Maybe what we can do before lsf/mm summit will be this (avoid warning.) This patch is onto linus's git tree. Patch description is updated.
Thanks.
-Kame
==
From4ab80f84bbcb02a790342426c1de84aeb17fcbe9Mon Sep 17 00:00:00 2001
From: KAMEZAWA Hiroyuki<[email protected]>
Date: Thu, 29 Mar 2012 14:59:04 +0900
Subject: [PATCH] memcg/tcp: fix warning caused bres->usagego to negative.
Quoted 6 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. At settingres->limit, accounting starts. The resource will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.
Kame,
Please test the following patch and see if it fixes your problems (I tested locally, and it triggers me no warnings running the test script you provided + an inbound scp -r copy of an iso directory from a remote machine)
When you are reviewing, keep in mind that we're likely to have the same problems with slab jump labels - since the slab pages will outlive the cgroup as well, and it might be worthy to keep this in mind, and provide a central point for the jump labels to be set of on cgroup destruction.
Quoted 1 line
From
c40bbd69cbb655b6389c2398ce89abb06e64910dMon Sep 17 00:00:00 2001
From: Glauber Costa <[email protected]>
Date: Wed, 4 Apr 2012 21:08:38 +0400
Subject: [PATCH] decrement static keys on real destroy time
We call the destroy function when a cgroup starts to be removed, such as by a rmdir event.
However, because of our reference counters, some objects are still inflight. Right now, we are decrementing the static_keys at destroy() time, meaning that if we get rid of the last static_key reference, some objects will still have charges, but the code to properly uncharge them won't be run.
This becomes a problem specially if it is ever enabled again, because now new charges will be added to the staled charges making keeping it pretty much impossible.
--- include/net/tcp_memcontrol.h | 2 ++ mm/memcontrol.c | 15 +++++++++++++++ net/ipv4/tcp_memcontrol.c | 10 ++++------ 3 files changed, 21 insertions(+), 6 deletions(-)
include/net/tcp_memcontrol.h +2 -0
@@ -9,6 +9,8 @@ struct tcp_memcontrol {/* those two are read-mostly, leave them at the end */ long tcp_prot_mem[3 ];int tcp_memory_pressure; +/* if this cgroup was ever limited, having static_keys activated */ +bool limited; };struct cg_proto *tcp_proto_cgroup (struct mem_cgroup *memcg);
mm/memcontrol.c +15 -0
@@ -442,6 +442,15 @@ void sock_release_memcg(struct sock *sk) } } +static void disarm_static_keys (struct mem_cgroup *memcg) +{ +#ifdef CONFIG_INET +if (memcg->tcp_mem.limited) +static_key_slow_dec (&memcg_socket_limit_enabled); +#endif +} + +#ifdef CONFIG_INET struct cg_proto *tcp_proto_cgroup (struct mem_cgroup *memcg) {
@@ -452,6 +461,11 @@ struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg) }EXPORT_SYMBOL (tcp_proto_cgroup);#endif /* CONFIG_INET */ +#else +static inline void disarm_static_keys (struct mem_cgroup *memcg) +{ +} +#endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ static void drain_all_stock_async (struct mem_cgroup *memcg);
@@ -4883,6 +4897,7 @@ static void __mem_cgroup_put(struct mem_cgroup *memcg, int count) {if (atomic_sub_and_test (count, &memcg->refcnt)) {struct mem_cgroup *parent =parent_mem_cgroup (memcg); +disarm_static_keys (memcg);__mem_cgroup_free (memcg);if (parent)mem_cgroup_put (parent);
net/ipv4/tcp_memcontrol.c +4 -6
@@ -41,6 +41,7 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) tcp->tcp_prot_mem[1 ] = net->ipv4.sysctl_tcp_mem[1 ]; tcp->tcp_prot_mem[2 ] = net->ipv4.sysctl_tcp_mem[2 ]; tcp->tcp_memory_pressure =0 ; + tcp->limited = false; parent_cg = tcp_prot.proto_cgroup (parent);if (parent_cg)
@@ -74,9 +75,6 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)percpu_counter_destroy (&tcp->tcp_sockets_allocated); val =res_counter_read_u64 (&tcp->tcp_memory_allocated,RES_LIMIT ); - -if (val !=RESOURCE_MAX ) -static_key_slow_dec (&memcg_socket_limit_enabled); }EXPORT_SYMBOL (tcp_destroy_cgroup);
@@ -107,10 +105,10 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) tcp->tcp_prot_mem[i] =min_t (long, val >>PAGE_SHIFT , net->ipv4.sysctl_tcp_mem[i]); -if (val ==RESOURCE_MAX && old_lim !=RESOURCE_MAX ) -static_key_slow_dec (&memcg_socket_limit_enabled); -else if (old_lim ==RESOURCE_MAX && val !=RESOURCE_MAX ) +if (old_lim ==RESOURCE_MAX && !tcp->limited) {static_key_slow_inc (&memcg_socket_limit_enabled); + tcp->limited = true; + }return 0 ; }
Signature · 1 line
1.7.7.6
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
Quoted 26 lines · Glauber Costa
Quoted 11 lines · KAMEZAWA Hiroyuki
Maybe what we can do before lsf/mm summit will be this (avoid warning.) This patch is onto linus's git tree. Patch description is updated.
Thanks.
-Kame
==
From4ab80f84bbcb02a790342426c1de84aeb17fcbe9Mon Sep 17 00:00:00 2001
From: KAMEZAWA Hiroyuki<[email protected]>
Date: Thu, 29 Mar 2012 14:59:04 +0900
Subject: [PATCH] memcg/tcp: fix warning caused bres->usagego to negative.Quoted 6 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. At settingres->limit, accounting starts. The resource will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.Kame,
Please test the following patch and see if it fixes your problems (I tested locally, and it triggers me no warnings running the test script you provided + an inbound scp -r copy of an iso directory from a remote machine)
Quoted 5 lines
When you are reviewing, keep in mind that we're likely to have the same problems with slab jump labels - since the slab pages will outlive the cgroup as well, and it might be worthy to keep this in mind, and provide a central point for the jump labels to be set of on cgroup destruction.
Hm. What happens in following sequence ?
1. a memcg is created
2. put a task into the memcg, start tcp steam
3. set tcp memory limit
The resource used between 2 and 3 will cause the problem finally.
Then, Dave's request
==
You must either:
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
==
are not satisfied. So, we need to have a state per sockets, it's accounted or not. I'll look into this problem again, today.
Thanks,
-Kame
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
Quoted 7 lines · KAMEZAWA Hiroyuki
Hm. What happens in following sequence ?
1. a memcg is created
2. put a task into the memcg, start tcp steam
3. set tcp memory limitThe resource used between 2 and 3 will cause the problem finally.
I don't get it. if a task is in memcg, but no limit is set, that socket will be assigned null memcg, and will stay like that forever. Only new sockets will have the new memcg pointer.
And previously, we could have the memcg pointer alive, but the jump labels to be disabled. With the patch I posted, this can't happen anymore, since the jump labels are guaranteed to live throughout the whole socket life.
Quoted 4 lines
Then, Dave's request
==
You must either:
Quoted 8 lines
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
==
are not satisfied. So, we need to have a state per sockets, it's accounted or not. I'll look into this problem again, today.
Of course they are.
Every socket created before we set the limit is not accounted. This is 2) that Dave mentioned, and it was *always* this way.
The problem here was the opposite: You could disable the jump labels with sockets still in flight, because we were disabling it based on the limit being set back to unlimited.
What this patch does, is defer that until the last socket limited dies.
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
Quoted 33 lines · Glauber Costa
Quoted 7 lines · KAMEZAWA Hiroyuki
Hm. What happens in following sequence ?
1. a memcg is created
2. put a task into the memcg, start tcp steam
3. set tcp memory limitThe resource used between 2 and 3 will cause the problem finally.
I don't get it. if a task is in memcg, but no limit is set, that socket will be assigned null memcg, and will stay like that forever. Only new sockets will have the new memcg pointer.
And previously, we could have the memcg pointer alive, but the jump labels to be disabled. With the patch I posted, this can't happen anymore, since the jump labels are guaranteed to live throughout the whole socket life.
Quoted 4 lines
Then, Dave's request
==
You must either:Quoted 8 lines
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
==
are not satisfied. So, we need to have a state per sockets, it's accounted or not. I'll look into this problem again, today.Of course they are.
Quoted 9 lines
Every socket created before we set the limit is not accounted. This is 2) that Dave mentioned, and it was *always* this way.
The problem here was the opposite: You could disable the jump labels with sockets still in flight, because we were disabling it based on the limit being set back to unlimited.
What this patch does, is defer that until the last socket limited dies.
Okay, there is an additional thing to be considered here:
Due to the nature of how jump label works, once they are enabled for one of the cgroups, they will be enabled for all of them. So the patch I sent may still break in some scenarios because of the way we record that the limit was set.
However, if my theory behind what is causing the problem is correct, this patch should fix the issue for you. Let me know if it does, and I'll work on the final solution.
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
Quoted 46 lines · Glauber Costa
Quoted 33 lines · Glauber Costa
Quoted 7 lines · KAMEZAWA Hiroyuki
Hm. What happens in following sequence ?
1. a memcg is created
2. put a task into the memcg, start tcp steam
3. set tcp memory limitThe resource used between 2 and 3 will cause the problem finally.
I don't get it. if a task is in memcg, but no limit is set, that socket will be assigned null memcg, and will stay like that forever. Only new sockets will have the new memcg pointer.
And previously, we could have the memcg pointer alive, but the jump labels to be disabled. With the patch I posted, this can't happen anymore, since the jump labels are guaranteed to live throughout the whole socket life.
Quoted 4 lines
Then, Dave's request
==
You must either:Quoted 8 lines
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
==
are not satisfied. So, we need to have a state per sockets, it's accounted or not. I'll look into this problem again, today.Of course they are.
Quoted 9 lines
Every socket created before we set the limit is not accounted. This is 2) that Dave mentioned, and it was *always* this way.
The problem here was the opposite: You could disable the jump labels with sockets still in flight, because we were disabling it based on the limit being set back to unlimited.
What this patch does, is defer that until the last socket limited dies.
Okay, there is an additional thing to be considered here:
Quoted 7 lines
Due to the nature of how jump label works, once they are enabled for one of the cgroups, they will be enabled for all of them. So the patch I sent may still break in some scenarios because of the way we record that the limit was set.
However, if my theory behind what is causing the problem is correct, this patch should fix the issue for you.
Now, our issue is leak of accounting, regardless of warning.
Quoted 4 lines
Let me know if it does, and
I'll work on the final solution.
The problem is that jump_label updating is not atomic_ops.
I'm _not_ sure the update order of the jump_label in sock_update_memcg() and other jump instructions inserted at accounting.
For example, if the jump instruction in sock_update_memcg() is updated 1st and others are updated later, it's unclear whether sockets which has _valid_ sock->sk_cgrp will be accounted or not because accounting jump instruction may not be updated yet.
Hopefully, label in sock_update_memcg should be updated last...
Hm. If I do, I'll add one more key as:
atomic_t sock_should_memcg_aware;
And update 2 keys in following order.
At enable
static_key_slow_inc(&memcg_socket_limit_enabled) atomic_inc(&sock_should_memcg_aware);
At disable
atomic_dec(&sock_should_memcg_aware); static_key_slow_dec(&memcg_socket_limit_enabled)
And
==
void sock_update_memcg(struct sock *sk)
{
if (atomic_read(&sock_should_memcg_aware)) {==
Thanks,
-Kame
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
Quoted 3 lines
The problem is that
jump_labelupdating is notatomic_ops.
That's indeed really bad.
You seem to be right about that... I wonder, however, if we should prevent anything to run in any cpu during the jump_label update? The update can be slow, sure, but it is not expected to be frequent...
Quoted 2 lines
I'm _not_ sure the update order of the
jump_labelinsock_update_memcg()and other jump instructions inserted at accounting.
Any ordering assumptions here would be extremely fragile, even if we could make one.
Quoted 21 lines
For example, if the jump instruction in
sock_update_memcg()is updated 1st and others are updated later, it's unclear whether sockets which has _valid_sock->sk_cgrpwill be accounted or not because accounting jump instruction may not be updated yet.Hopefully, label in
sock_update_memcgshould be updated last...Hm. If I do, I'll add one more key as:
atomic_tsock_should_memcg_aware;And update 2 keys in following order.
At enable
static_key_slow_inc(&memcg_socket_limit_enabled) atomic_inc(&sock_should_memcg_aware);At disable
atomic_dec(&sock_should_memcg_aware); static_key_slow_dec(&memcg_socket_limit_enabled)
Quoted 7 lines
And
==
voidsock_update_memcg(struct sock *sk){ if (atomic_read(&sock_should_memcg_aware)) {==
Problem here is that having an atomic variable here defeats a bit the purpose of the jump labels.
If it is just in the update path, it is not *that* bad.
But unless we go fix the jump labels to prevent such thing from happening, maybe it would be better to have two jump labels here?
One for the writer, that is updated last, and one from the readers. This way we can force the ordering the way we want.
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
In reply to Glauber CostaQuoted 33 lines · Glauber Costa
Quoted 7 lines · KAMEZAWA Hiroyuki
Hm. What happens in following sequence ?
1. a memcg is created
2. put a task into the memcg, start tcp steam
3. set tcp memory limitThe resource used between 2 and 3 will cause the problem finally.
I don't get it. if a task is in memcg, but no limit is set, that socket will be assigned null memcg, and will stay like that forever. Only new sockets will have the new memcg pointer.
And previously, we could have the memcg pointer alive, but the jump labels to be disabled. With the patch I posted, this can't happen anymore, since the jump labels are guaranteed to live throughout the whole socket life.
Quoted 4 lines
Then, Dave's request
==
You must either:Quoted 8 lines
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
==
are not satisfied. So, we need to have a state per sockets, it's accounted or not. I'll look into this problem again, today.Of course they are.
Quoted 9 lines
Every socket created before we set the limit is not accounted. This is 2) that Dave mentioned, and it was *always* this way.
The problem here was the opposite: You could disable the jump labels with sockets still in flight, because we were disabling it based on the limit being set back to unlimited.
What this patch does, is defer that until the last socket limited dies.
Thank you for explanation. Hmm, sk->cgrp check ?
Ah, yes it's updated by sock_update_memcg() under jump_label, which is called by tcp_v4_init_sock().
Hm. and jump_label()'s atomic counter and mutex_lock will be a guard against set/unset race. Ok.
BTW, what will happen in following case ?
Assume that the last memcg is destroyed and call jump_label_dec. And the thread waits for jump_label_mutex for a while.
CPU A CPU B
jump_label_dec() # mutex will be held sock_update_memcg() is called
sk_cgrp is set.
...modify instructions some accounting is done.
mutex_unlock()
I wonder you need some serialization somewhere OR disallow turning off accounting.
Thanks,
-Kame
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
In reply to KAMEZAWA HiroyukiQuoted 47 lines · KAMEZAWA Hiroyuki
Quoted 26 lines · Glauber Costa
Quoted 11 lines · KAMEZAWA Hiroyuki
Maybe what we can do before lsf/mm summit will be this (avoid warning.) This patch is onto linus's git tree. Patch description is updated.
Thanks.
-Kame
==
From4ab80f84bbcb02a790342426c1de84aeb17fcbe9Mon Sep 17 00:00:00 2001
From: KAMEZAWA Hiroyuki<[email protected]>
Date: Thu, 29 Mar 2012 14:59:04 +0900
Subject: [PATCH] memcg/tcp: fix warning caused bres->usagego to negative.Quoted 6 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. At settingres->limit, accounting starts. The resource will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.Kame,
Please test the following patch and see if it fixes your problems (I tested locally, and it triggers me no warnings running the test script you provided + an inbound scp -r copy of an iso directory from a remote machine)
Quoted 5 lines
When you are reviewing, keep in mind that we're likely to have the same problems with slab jump labels - since the slab pages will outlive the cgroup as well, and it might be worthy to keep this in mind, and provide a central point for the jump labels to be set of on cgroup destruction.
Hm. What happens in following sequence ?
1. a memcg is created
2. put a task into the memcg, start tcp steam
3. set tcp memory limitThe resource used between 2 and 3 will cause the problem finally.
Then, Dave's request
==
You must either:
Quoted 8 lines
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
==
are not satisfied. So, we need to have a state per sockets, it's accounted or not. I'll look into this problem again, today.
Kame,
Let me know what you think of the attached fix.
I still need to compile test it in other configs to be sure it doesn't break, etc. But let's agree on it first.
Quoted 1 line
From
cdebff23dceeb9d35fd27e5988748a506bb47985Mon Sep 17 00:00:00 2001
From: Glauber Costa <[email protected]>
Date: Wed, 4 Apr 2012 21:08:38 +0400
Subject: [PATCH] decrement static keys on real destroy time
We call the destroy function when a cgroup starts to be removed, such as by a rmdir event.
However, because of our reference counters, some objects are still inflight. Right now, we are decrementing the static_keys at destroy() time, meaning that if we get rid of the last static_key reference, some objects will still have charges, but the code to properly uncharge them won't be run.
This becomes a problem specially if it is ever enabled again, because now new charges will be added to the staled charges making keeping it pretty much impossible.
We just need to be careful with the static branch activation:
since there is no particular preferred order of their activation, we need to make sure that we only start using it after all call sites are active. This is achieved by having a per-memcg flag that is only updated after static_key_slow_inc() returns. At this time, we are sure all sites are active.
This is made per-memcg, not global, for a reason:
it also has the effect of making socket accounting more consistent. The first memcg to be limited will trigger static_key() activation, therefore, accounting. But all the others will then be accounted no matter what. After this patch, only limited memcgs will have its sockets accounted.
[v2: changed a tcp limited flag for a generic proto limited flag ]
--- include/net/sock.h | 1 + mm/memcontrol.c | 20 ++++++++++++++++++-- net/ipv4/tcp_memcontrol.c | 12 ++++++------ 3 files changed, 25 insertions(+), 8 deletions(-)
include/net/sock.h +1 -0
@@ -913,6 +913,7 @@ struct cg_proto {struct percpu_counter *sockets_allocated;/* Current number of sockets. */ int *memory_pressure;long *sysctl_mem; +bool limited;/* * memcg field is used to find which memcg we belong directly * Each memcg struct can hold more than one cg_proto, so container_of
mm/memcontrol.c +18 -2
@@ -404,6 +404,7 @@ void sock_update_memcg(struct sock *sk) {if (mem_cgroup_sockets_enabled) {struct mem_cgroup *memcg; +struct cg_proto *cg_proto;BUG_ON (!sk->sk_prot->proto_cgroup);
@@ -423,9 +424,10 @@ void sock_update_memcg(struct sock *sk)rcu_read_lock (); memcg =mem_cgroup_from_task (current); -if (!mem_cgroup_is_root (memcg)) { + cg_proto = sk->sk_prot->proto_cgroup (memcg); +if (!mem_cgroup_is_root (memcg) && cg_proto->limited) {mem_cgroup_get (memcg); - sk->sk_cgrp = sk->sk_prot->proto_cgroup (memcg); + sk->sk_cgrp = cg_proto; }rcu_read_unlock (); }
@@ -442,6 +444,14 @@ void sock_release_memcg(struct sock *sk) } } +static void disarm_static_keys (struct mem_cgroup *memcg) +{ +#ifdef CONFIG_INET +if (memcg->tcp_mem.cg_proto.limited) +static_key_slow_dec (&memcg_socket_limit_enabled); +#endif +} +#ifdef CONFIG_INET struct cg_proto *tcp_proto_cgroup (struct mem_cgroup *memcg) {
@@ -452,6 +462,11 @@ struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg) }EXPORT_SYMBOL (tcp_proto_cgroup);#endif /* CONFIG_INET */ +#else +static inline void disarm_static_keys (struct mem_cgroup *memcg) +{ +} +#endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ static void drain_all_stock_async (struct mem_cgroup *memcg);
@@ -4883,6 +4898,7 @@ static void __mem_cgroup_put(struct mem_cgroup *memcg, int count) {if (atomic_sub_and_test (count, &memcg->refcnt)) {struct mem_cgroup *parent =parent_mem_cgroup (memcg); +disarm_static_keys (memcg);__mem_cgroup_free (memcg);if (parent)mem_cgroup_put (parent);
net/ipv4/tcp_memcontrol.c +6 -6
@@ -54,6 +54,7 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) cg_proto->sysctl_mem = tcp->tcp_prot_mem; cg_proto->memory_allocated = &tcp->tcp_memory_allocated; cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated; + cg_proto->limited = false; cg_proto->memcg = memcg;return 0 ;
@@ -74,9 +75,6 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)percpu_counter_destroy (&tcp->tcp_sockets_allocated); val =res_counter_read_u64 (&tcp->tcp_memory_allocated,RES_LIMIT ); - -if (val !=RESOURCE_MAX ) -static_key_slow_dec (&memcg_socket_limit_enabled); }EXPORT_SYMBOL (tcp_destroy_cgroup);
@@ -107,10 +105,12 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) tcp->tcp_prot_mem[i] =min_t (long, val >>PAGE_SHIFT , net->ipv4.sysctl_tcp_mem[i]); -if (val ==RESOURCE_MAX && old_lim !=RESOURCE_MAX ) -static_key_slow_dec (&memcg_socket_limit_enabled); -else if (old_lim ==RESOURCE_MAX && val !=RESOURCE_MAX ) +if (val ==RESOURCE_MAX ) + cg_proto->limited = false; +else if (val !=RESOURCE_MAX && !cg_proto->limited) {static_key_slow_inc (&memcg_socket_limit_enabled); + cg_proto->limited = true; + }return 0 ; }
Signature · 1 line
1.7.7.6
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
Quoted 108 lines · Glauber Costa
Quoted 47 lines · KAMEZAWA Hiroyuki
Quoted 26 lines · Glauber Costa
Quoted 11 lines · KAMEZAWA Hiroyuki
Maybe what we can do before lsf/mm summit will be this (avoid warning.) This patch is onto linus's git tree. Patch description is updated.
Thanks.
-Kame
==
From4ab80f84bbcb02a790342426c1de84aeb17fcbe9Mon Sep 17 00:00:00 2001
From: KAMEZAWA Hiroyuki<[email protected]>
Date: Thu, 29 Mar 2012 14:59:04 +0900
Subject: [PATCH] memcg/tcp: fix warning caused bres->usagego to negative.Quoted 6 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. At settingres->limit, accounting starts. The resource will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.Kame,
Please test the following patch and see if it fixes your problems (I tested locally, and it triggers me no warnings running the test script you provided + an inbound scp -r copy of an iso directory from a remote machine)
Quoted 5 lines
When you are reviewing, keep in mind that we're likely to have the same problems with slab jump labels - since the slab pages will outlive the cgroup as well, and it might be worthy to keep this in mind, and provide a central point for the jump labels to be set of on cgroup destruction.
Hm. What happens in following sequence ?
1. a memcg is created
2. put a task into the memcg, start tcp steam
3. set tcp memory limitThe resource used between 2 and 3 will cause the problem finally.
Then, Dave's request
==
You must either:Quoted 8 lines
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
==
are not satisfied. So, we need to have a state per sockets, it's accounted or not. I'll look into this problem again, today.Kame,
Let me know what you think of the attached fix.
I still need to compile test it in other configs to be sure it doesn't break, etc. But let's agree on it first.Subject: [PATCH] decrement static keys on real destroy time
We call the destroy function when a cgroup starts to be removed, such as by a rmdir event.
However, because of our reference counters, some objects are still inflight. Right now, we are decrementing the
static_keysatdestroy()time, meaning that if we get rid of the laststatic_keyreference, some objects will still have charges, but the code to properly uncharge them won't be run.This becomes a problem specially if it is ever enabled again, because now new charges will be added to the staled charges making keeping it pretty much impossible.
We just need to be careful with the static branch activation:
since there is no particular preferred order of their activation, we need to make sure that we only start using it after all call sites are active. This is achieved by having a per-memcg flag that is only updated afterstatic_key_slow_inc()returns. At this time, we are sure all sites are active.This is made per-memcg, not global, for a reason:
it also has the effect of making socket accounting more consistent. The first memcg to be limited will triggerstatic_key()activation, therefore, accounting. But all the others will then be accounted no matter what. After this patch, only limited memcgs will have its sockets accounted.[v2: changed a tcp limited flag for a generic proto limited flag ]
Signed-off-by Glauber Costa <[email protected]>--- include/net/sock.h | 1 + mm/memcontrol.c | 20 ++++++++++++++++++-- net/ipv4/tcp_memcontrol.c | 12 ++++++------ 3 files changed, 25 insertions(+), 8 deletions(-)include/net/sock.h +0
-0
include/net/sock.h struct cg_proto { · line 916
Quoted 4 lines
include/net/sock.h +1
-0@@ -913,6 +913,7 @@ struct cg_proto {struct percpu_counter *sockets_allocated;/* Current number of sockets. */ int *memory_pressure;long *sysctl_mem; +bool limited;
please add comment somewhere. Hmm, 'limited' is good name ?
Quoted 16 lines
include/net/sock.h +0
-0/* * memcg field is used to find which memcg we belong directly * Each memcg struct can hold more than one cg_proto, so container_of mm/memcontrol.c +1
-0@@ -404,6 +404,7 @@ void sock_update_memcg(struct sock *sk) {if (mem_cgroup_sockets_enabled) {struct mem_cgroup *memcg; +struct cg_proto *cg_proto;BUG_ON (!sk->sk_prot->proto_cgroup);
mm/memcontrol.c void sock_update_memcg(struct sock *sk) · line 431
Quoted 10 lines
mm/memcontrol.c +3
-2@@ -423,9 +424,10 @@ void sock_update_memcg(struct sock *sk)rcu_read_lock (); memcg =mem_cgroup_from_task (current); -if (!mem_cgroup_is_root (memcg)) { + cg_proto = sk->sk_prot->proto_cgroup (memcg); +if (!mem_cgroup_is_root (memcg) && cg_proto->limited) {mem_cgroup_get (memcg); - sk->sk_cgrp = sk->sk_prot->proto_cgroup (memcg); + sk->sk_cgrp = cg_proto; }
Ok, then, sk->sk_cgroup is set only after jump_label is enabled and its memcg has limitation.
Quoted 60 lines
mm/memcontrol.c +14
-0rcu_read_unlock (); }@@ -442,6 +444,14 @@ void sock_release_memcg(struct sock *sk) } } +static void disarm_static_keys (struct mem_cgroup *memcg) +{ +#ifdef CONFIG_INET +if (memcg->tcp_mem.cg_proto.limited) +static_key_slow_dec (&memcg_socket_limit_enabled); +#endif +} +#ifdef CONFIG_INET struct cg_proto *tcp_proto_cgroup (struct mem_cgroup *memcg) {@@ -452,6 +462,11 @@ struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg) }EXPORT_SYMBOL (tcp_proto_cgroup);#endif /* CONFIG_INET */ +#else +static inline void disarm_static_keys (struct mem_cgroup *memcg) +{ +} +#endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ static void drain_all_stock_async (struct mem_cgroup *memcg);@@ -4883,6 +4898,7 @@ static void __mem_cgroup_put(struct mem_cgroup *memcg, int count) {if (atomic_sub_and_test (count, &memcg->refcnt)) {struct mem_cgroup *parent =parent_mem_cgroup (memcg); +disarm_static_keys (memcg);__mem_cgroup_free (memcg);if (parent)mem_cgroup_put (parent);net/ipv4/tcp_memcontrol.c +1
-3@@ -54,6 +54,7 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) cg_proto->sysctl_mem = tcp->tcp_prot_mem; cg_proto->memory_allocated = &tcp->tcp_memory_allocated; cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated; + cg_proto->limited = false; cg_proto->memcg = memcg;return 0 ;@@ -74,9 +75,6 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)percpu_counter_destroy (&tcp->tcp_sockets_allocated); val =res_counter_read_u64 (&tcp->tcp_memory_allocated,RES_LIMIT ); - -if (val !=RESOURCE_MAX ) -static_key_slow_dec (&memcg_socket_limit_enabled); }EXPORT_SYMBOL (tcp_destroy_cgroup);
net/ipv4/tcp_memcontrol.c static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) · line 109
Quoted 8 lines
net/ipv4/tcp_memcontrol.c +2
-3@@ -107,10 +105,12 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) tcp->tcp_prot_mem[i] =min_t (long, val >>PAGE_SHIFT , net->ipv4.sysctl_tcp_mem[i]); -if (val ==RESOURCE_MAX && old_lim !=RESOURCE_MAX ) -static_key_slow_dec (&memcg_socket_limit_enabled); -else if (old_lim ==RESOURCE_MAX && val !=RESOURCE_MAX ) +if (val ==RESOURCE_MAX ) + cg_proto->limited = false;
Why we can reset this to be false ? disarm_static_keys() will not work at destroy()....
net/ipv4/tcp_memcontrol.c static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) · line 114
Quoted 5 lines
net/ipv4/tcp_memcontrol.c +3
-0+else if (val !=RESOURCE_MAX && !cg_proto->limited) {static_key_slow_inc (&memcg_socket_limit_enabled); + cg_proto->limited = true; + }
Hmm. don't we need any mutex ?
Thanks,
-Kame
Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
Quoted 105 lines · KAMEZAWA Hiroyuki
Quoted 103 lines · Glauber Costa
Quoted 47 lines · KAMEZAWA Hiroyuki
Quoted 26 lines · Glauber Costa
Quoted 11 lines · KAMEZAWA Hiroyuki
Maybe what we can do before lsf/mm summit will be this (avoid warning.) This patch is onto linus's git tree. Patch description is updated.
Thanks.
-Kame
==
From4ab80f84bbcb02a790342426c1de84aeb17fcbe9Mon Sep 17 00:00:00 2001
From: KAMEZAWA Hiroyuki<[email protected]>
Date: Thu, 29 Mar 2012 14:59:04 +0900
Subject: [PATCH] memcg/tcp: fix warning caused bres->usagego to negative.Quoted 6 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. At settingres->limit, accounting starts. The resource will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.Kame,
Please test the following patch and see if it fixes your problems (I tested locally, and it triggers me no warnings running the test script you provided + an inbound scp -r copy of an iso directory from a remote machine)
Quoted 5 lines
When you are reviewing, keep in mind that we're likely to have the same problems with slab jump labels - since the slab pages will outlive the cgroup as well, and it might be worthy to keep this in mind, and provide a central point for the jump labels to be set of on cgroup destruction.
Hm. What happens in following sequence ?
1. a memcg is created
2. put a task into the memcg, start tcp steam
3. set tcp memory limitThe resource used between 2 and 3 will cause the problem finally.
Then, Dave's request
==
You must either:Quoted 8 lines
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
==
are not satisfied. So, we need to have a state per sockets, it's accounted or not. I'll look into this problem again, today.Kame,
Let me know what you think of the attached fix.
I still need to compile test it in other configs to be sure it doesn't break, etc. But let's agree on it first.Subject: [PATCH] decrement static keys on real destroy time
We call the destroy function when a cgroup starts to be removed, such as by a rmdir event.
However, because of our reference counters, some objects are still inflight. Right now, we are decrementing the
static_keysatdestroy()time, meaning that if we get rid of the laststatic_keyreference, some objects will still have charges, but the code to properly uncharge them won't be run.This becomes a problem specially if it is ever enabled again, because now new charges will be added to the staled charges making keeping it pretty much impossible.
We just need to be careful with the static branch activation:
since there is no particular preferred order of their activation, we need to make sure that we only start using it after all call sites are active. This is achieved by having a per-memcg flag that is only updated afterstatic_key_slow_inc()returns. At this time, we are sure all sites are active.This is made per-memcg, not global, for a reason:
it also has the effect of making socket accounting more consistent. The first memcg to be limited will triggerstatic_key()activation, therefore, accounting. But all the others will then be accounted no matter what. After this patch, only limited memcgs will have its sockets accounted.[v2: changed a tcp limited flag for a generic proto limited flag ]
Signed-off-by Glauber Costa<[email protected]>--- include/net/sock.h | 1 + mm/memcontrol.c | 20 ++++++++++++++++++-- net/ipv4/tcp_memcontrol.c | 12 ++++++------ 3 files changed, 25 insertions(+), 8 deletions(-)
Quoted 12 lines
include/net/sock.h struct cg_proto { · line 916
Quoted 9 lines
include/net/sock.h +1
-0@@ -913,6 +913,7 @@ struct cg_proto {struct percpu_counter *sockets_allocated;/* Current number of sockets. */ int *memory_pressure;long *sysctl_mem; +bool limited;please add comment somewhere. Hmm, 'limited' is good name ?
I changed it to two fields in the version I am preparing:
accounted - means it was ever triggered
account - means we are currently limited.
It also addresses the problem you mention bellow.
Quoted 34 lines
Quoted 16 lines
include/net/sock.h +0
-0/* * memcg field is used to find which memcg we belong directly * Each memcg struct can hold more than one cg_proto, so container_of mm/memcontrol.c +1
-0@@ -404,6 +404,7 @@ void sock_update_memcg(struct sock *sk) {if (mem_cgroup_sockets_enabled) {struct mem_cgroup *memcg; +struct cg_proto *cg_proto;BUG_ON (!sk->sk_prot->proto_cgroup);mm/memcontrol.c void sock_update_memcg(struct sock *sk) · line 431
Quoted 10 lines
mm/memcontrol.c +3
-2@@ -423,9 +424,10 @@ void sock_update_memcg(struct sock *sk)rcu_read_lock (); memcg =mem_cgroup_from_task (current); -if (!mem_cgroup_is_root (memcg)) { + cg_proto = sk->sk_prot->proto_cgroup (memcg); +if (!mem_cgroup_is_root (memcg)&& cg_proto->limited) {mem_cgroup_get (memcg); - sk->sk_cgrp = sk->sk_prot->proto_cgroup (memcg); + sk->sk_cgrp = cg_proto; }Ok, then,
sk->sk_cgroupis set only afterjump_labelis enabled and its memcg has limitation.
Quoted 2 lines
Why we can reset this to be false ?
disarm_static_keys()will not work atdestroy()....
This is solved by the two booleans. What I want, is achieve consistency, and account only when turned on.
Account after the first is turned on - which is what we have now - is way more confusing.
Quoted 8 lines
mm/memcontrol.c void sock_update_memcg(struct sock *sk)
Quoted 6 lines
mm/memcontrol.c +3
-0+else if (val !=RESOURCE_MAX && !cg_proto->limited) {static_key_slow_inc (&memcg_socket_limit_enabled); + cg_proto->limited = true; + }Hmm. don't we need any mutex ?
I thought no.
But now that you pointed this out, I gave it some time...
What we can't do, is take a mutex in sock_update_memcg(). It will kill us.
I think we only need to protect against two processes writing to the same file (tcp.limit_in_bytes) at the same time.
We don't hold cgroup_mutex for that, so we need locking only if the vfs does not protect us against this concurrency. I will check that to be sure.
David Miller
maintainerRe: [BUGFIX][PATCH 3/3] memcg/tcp: ignore tcp usage before accounting started
In reply to Glauber CostaFrom: Glauber Costa <[email protected]>
Date: Thu, 29 Mar 2012 11:21:07 +0200
Quoted 6 lines · KAMEZAWA Hiroyuki
Quoted 5 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. After settingres->limit, the resource (already used) will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.
Quoted 8 lines
Quoted 4 lines
This patch fixes that by adding
res_counter_uncharge_nowarn(). (*) We cannot avoid this while we have 'account start' switch.Signed-off-by KAMEZAWA Hiroyuki<[email protected]>Fine by me.
Acked-by Glauber Costa <[email protected]>
I'm not applying patches that simply ignore accounting counter underflows.
You must either:
1) Integrate the socket's existing usage when the limit is set.
2) Avoid accounting completely for a socket that started before the limit was set.
No half-way solutions, please. Otherwise it is impossible to design validations of the resource usage for a particular socket or group of sockets, because they can always be potentially "wrong" and over the limit. That's a design for a buggy system.
Re: [BUGFIX][PATCH 3/3] memcg/tcp: ignore tcp usage before accounting started
Quoted 25 lines · David Miller
From: Glauber Costa<[email protected]>
Date: Thu, 29 Mar 2012 11:21:07 +0200Quoted 6 lines · KAMEZAWA Hiroyuki
Quoted 5 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. After settingres->limit, the resource (already used) will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.Quoted 8 lines
Quoted 4 lines
This patch fixes that by adding
res_counter_uncharge_nowarn(). (*) We cannot avoid this while we have 'account start' switch.Signed-off-by KAMEZAWA Hiroyuki<[email protected]>Fine by me.
Acked-by Glauber Costa<[email protected]>I'm not applying patches that simply ignore accounting counter underflows.
You must either:
1) Integrate the socket's existing usage when the limit is set.
Quoted 9 lines
2) Avoid accounting completely for a socket that started before the limit was set.
No half-way solutions, please. Otherwise it is impossible to design validations of the resource usage for a particular socket or group of sockets, because they can always be potentially "wrong" and over the limit. That's a design for a buggy system.
Kame,
I agree with Dave FWIW.
We should be able to do this by dropping the reference count when the cgroup is finally destroyed, instead of from the remove callback. At that point, no more pending sockets should be attached to it.
Prior to increasing the static key, they are all assigned to the global cgroup, so we shouldn't care about them.
Re: [BUGFIX][PATCH 3/3] memcg/tcp: ignore tcp usage before accounting started
Quoted 37 lines · Glauber Costa
Quoted 25 lines · David Miller
From: Glauber Costa<[email protected]>
Date: Thu, 29 Mar 2012 11:21:07 +0200Quoted 6 lines · KAMEZAWA Hiroyuki
Quoted 5 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. After settingres->limit, the resource (already used) will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.Quoted 8 lines
Quoted 4 lines
This patch fixes that by adding
res_counter_uncharge_nowarn(). (*) We cannot avoid this while we have 'account start' switch.Signed-off-by KAMEZAWA Hiroyuki<[email protected]>Fine by me.
Acked-by Glauber Costa<[email protected]>I'm not applying patches that simply ignore accounting counter underflows.
You must either:
1) Integrate the socket's existing usage when the limit is set.
Quoted 9 lines
2) Avoid accounting completely for a socket that started before the limit was set.
No half-way solutions, please. Otherwise it is impossible to design validations of the resource usage for a particular socket or group of sockets, because they can always be potentially "wrong" and over the limit. That's a design for a buggy system.
Kame,
Quoted 9 lines
I agree with Dave FWIW.
We should be able to do this by dropping the reference count when the cgroup is finally destroyed, instead of from the remove callback. At that point, no more pending sockets should be attached to it.
Prior to increasing the static key, they are all assigned to the global cgroup, so we shouldn't care about them.
Could you do the fix ?
Thanks,
-Kame
Re: [BUGFIX][PATCH 3/3] memcg/tcp: ignore tcp usage before accounting started
Quoted 45 lines · KAMEZAWA Hiroyuki
Quoted 43 lines · Glauber Costa
Quoted 25 lines · David Miller
From: Glauber Costa<[email protected]>
Date: Thu, 29 Mar 2012 11:21:07 +0200Quoted 6 lines · KAMEZAWA Hiroyuki
Quoted 5 lines
tcp memcontrol starts accouting after
res->limitis set. So, if a sockets starts before settingres->limit, there are already used resource. After settingres->limit, the resource (already used) will be uncharged and makeres_counterbelow 0 because they are not charged. This causes warning.Quoted 8 lines
Quoted 4 lines
This patch fixes that by adding
res_counter_uncharge_nowarn(). (*) We cannot avoid this while we have 'account start' switch.Signed-off-by KAMEZAWA Hiroyuki<[email protected]>Fine by me.
Acked-by Glauber Costa<[email protected]>I'm not applying patches that simply ignore accounting counter underflows.
You must either:
1) Integrate the socket's existing usage when the limit is set.
Quoted 9 lines
2) Avoid accounting completely for a socket that started before the limit was set.
No half-way solutions, please. Otherwise it is impossible to design validations of the resource usage for a particular socket or group of sockets, because they can always be potentially "wrong" and over the limit. That's a design for a buggy system.
Kame,
I agree with Dave FWIW.
We should be able to do this by dropping the reference count when the cgroup is finally destroyed, instead of from the remove callback. At that point, no more pending sockets should be attached to it.
Quoted 10 lines
Quoted 3 lines
Prior to increasing the static key, they are all assigned to the global cgroup, so we shouldn't care about them.
Could you do the fix ?
Thanks,
-Kame
I sent you a version already. Please just make sure it works for you