memcg: force charge kmem counter too
Subsystems (3)
PATCH 1/1 memcg: force charge kmem counter too
Based on several conditions the kernel can decide to force charge an allocation for a memcg i.e. overcharge memcg->memory and memcg->memsw counters. Do the same for memcg->kmem counter too. In cgroup-v1, this bug can cause a __GFP_NOFAIL kmem allocation fail if an explicit limit on kmem counter is set and reached.
--- mm/memcontrol.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
mm/memcontrol.c +19 -2
@@ -1893,6 +1893,18 @@ void mem_cgroup_handle_over_high(void) current->memcg_nr_pages_over_high =0 ; } +/* +* Based on try_charge() force charge conditions. +*/ +static inline bool should_force_charge (gfp_t gfp_mask) +{ +return (unlikely (tsk_is_oom_victim (current) || +fatal_signal_pending (current) || + current->flags &PF_EXITING || + current->flags &PF_MEMALLOC || + gfp_mask & __GFP_NOFAIL)); +} +static int try_charge (struct mem_cgroup *memcg,gfp_t gfp_mask,unsigned int nr_pages) {
@@ -2008,6 +2020,8 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,* The allocation either can't fail or will lead to more memory * being freed very soon. Allow memory usage go over the limit * temporarily by force charging it. +* +* NOTE: Please keep the should_force_charge() conditions in sync. */ page_counter_charge (&memcg->memory, nr_pages);if (do_memsw_account ())
@@ -2331,8 +2345,11 @@ int memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order,if (!cgroup_subsys_on_dfl (memory_cgrp_subsys) && !page_counter_try_charge (&memcg->kmem, nr_pages, &counter)) { -cancel_charge (memcg, nr_pages); -return -ENOMEM ; +if (!should_force_charge (gfp)) { +cancel_charge (memcg, nr_pages); +return -ENOMEM ; + } +page_counter_charge (&memcg->kmem, nr_pages); } page->mem_cgroup = memcg;
Signature · 1 line
2.17.0.921.gf22659ad46-goog
Quoted 5 lines · Shakeel Butt
Based on several conditions the kernel can decide to force charge an allocation for a memcg i.e. overcharge
memcg->memoryandmemcg->memswcounters. Do the same formemcg->kmemcounter too. In cgroup-v1, this bug can cause a__GFP_NOFAILkmem allocation fail if an explicit limit on kmem counter is set and reached.
memory.kmem.limit is broken and unlikely to ever be fixed as this knob was deprecated in cgroup-v2. The fact that hitting the limit doesn't trigger reclaim can result in unexpected behavior from user's pov, like getting ENOMEM while listing a directory. Bypassing the limit for NOFAIL allocations isn't going to fix those problem. So I'd suggest to avoid setting memory.kmem.limit instead of trying to fix it or, even better, switch to cgroup-v2.
Quoted 52 lines
Signed-off-by Shakeel Butt <[email protected]>--- mm/memcontrol.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)mm/memcontrol.c +19
-2@@ -1893,6 +1893,18 @@ void mem_cgroup_handle_over_high(void) current->memcg_nr_pages_over_high =0 ; } +/* +* Based on try_charge() force charge conditions. +*/ +static inline bool should_force_charge (gfp_t gfp_mask) +{ +return (unlikely (tsk_is_oom_victim (current) || +fatal_signal_pending (current) || + current->flags &PF_EXITING || + current->flags &PF_MEMALLOC || + gfp_mask & __GFP_NOFAIL)); +} +static int try_charge (struct mem_cgroup *memcg,gfp_t gfp_mask,unsigned int nr_pages) {@@ -2008,6 +2020,8 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,* The allocation either can't fail or will lead to more memory * being freed very soon. Allow memory usage go over the limit * temporarily by force charging it. +* +* NOTE: Please keep the should_force_charge() conditions in sync. */ page_counter_charge (&memcg->memory, nr_pages);if (do_memsw_account ())@@ -2331,8 +2345,11 @@ int memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order,if (!cgroup_subsys_on_dfl (memory_cgrp_subsys) && !page_counter_try_charge (&memcg->kmem, nr_pages, &counter)) { -cancel_charge (memcg, nr_pages); -return -ENOMEM ; +if (!should_force_charge (gfp)) { +cancel_charge (memcg, nr_pages); +return -ENOMEM ; + } +page_counter_charge (&memcg->kmem, nr_pages); } page->mem_cgroup = memcg;
Quoted 7 lines · Vladimir Davydov
Quoted 5 lines · Shakeel Butt
Based on several conditions the kernel can decide to force charge an allocation for a memcg i.e. overcharge
memcg->memoryandmemcg->memswcounters. Do the same formemcg->kmemcounter too. In cgroup-v1, this bug can cause a__GFP_NOFAILkmem allocation fail if an explicit limit on kmem counter is set and reached.
Quoted 5 lines
memory.kmem.limit is broken and unlikely to ever be fixed as this knob was deprecated in cgroup-v2. The fact that hitting the limit doesn't trigger reclaim can result in unexpected behavior from user's pov, like getting ENOMEM while listing a directory. Bypassing the limit for NOFAIL allocations isn't going to fix those problem.
I understand that fixing NOFAIL will not fix all other issues but it still is better than current situation. IMHO we should keep fixing kmem bit by bit.
One crazy idea is to just break it completely by force charging all the time.
Michal Hocko
maintainerQuoted 15 lines · Shakeel Butt
Quoted 7 lines · Vladimir Davydov
Quoted 5 lines · Shakeel Butt
Based on several conditions the kernel can decide to force charge an allocation for a memcg i.e. overcharge
memcg->memoryandmemcg->memswcounters. Do the same formemcg->kmemcounter too. In cgroup-v1, this bug can cause a__GFP_NOFAILkmem allocation fail if an explicit limit on kmem counter is set and reached.Quoted 5 lines
memory.kmem.limit is broken and unlikely to ever be fixed as this knob was deprecated in cgroup-v2. The fact that hitting the limit doesn't trigger reclaim can result in unexpected behavior from user's pov, like getting ENOMEM while listing a directory. Bypassing the limit for NOFAIL allocations isn't going to fix those problem.
Quoted 5 lines
I understand that fixing NOFAIL will not fix all other issues but it still is better than current situation. IMHO we should keep fixing kmem bit by bit.
One crazy idea is to just break it completely by force charging all the time.
What is the limit good for then? Accounting?
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 16 lines · Michal Hocko
Quoted 15 lines · Shakeel Butt
Quoted 12 lines · Vladimir Davydov
Quoted 5 lines · Shakeel Butt
Based on several conditions the kernel can decide to force charge an allocation for a memcg i.e. overcharge
memcg->memoryandmemcg->memswcounters. Do the same formemcg->kmemcounter too. In cgroup-v1, this bug can cause a__GFP_NOFAILkmem allocation fail if an explicit limit on kmem counter is set and reached.memory.kmem.limit is broken and unlikely to ever be fixed as this knob was deprecated in cgroup-v2. The fact that hitting the limit doesn't trigger reclaim can result in unexpected behavior from user's pov, like getting ENOMEM while listing a directory. Bypassing the limit for NOFAIL allocations isn't going to fix those problem.
Quoted 8 lines
Quoted 5 lines
I understand that fixing NOFAIL will not fix all other issues but it still is better than current situation. IMHO we should keep fixing kmem bit by bit.
One crazy idea is to just break it completely by force charging all the time.
What is the limit good for then? Accounting?
Unlike tcpmem, the kmem accounting is enabled by default. No need to set the limit to enable accounting.
I think my crazy idea was just wrong and without much thought. Though is there a precedence where the broken feature is not fixed because an alternative is available?
Michal Hocko
maintainerQuoted 3 lines · Shakeel Butt
On Mon, May 28, 2018 at 2:11 AM, Michal Hocko <[email protected]> wrote:
Though is there a precedence where the broken feature is not fixed because an alternative is available?
Well, I can see how breaking GFP_NOFAIL semantic is problematic, on the other hand we keep saying that kmem accounting in v1 is hard usable and strongly discourage people from using it. Sure we can add the code which handles _this_ particular case but that wouldn't make the whole thing more usable I strongly suspect. Maybe I am wrong and you can provide some specific examples. Is GFP_NOFAIL that common to matter?
In any case we should balance between the code maintainability here. Adding more cruft into the allocator path is not free.
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 12 lines · Michal Hocko
Quoted 3 lines · Shakeel Butt
On Mon, May 28, 2018 at 2:11 AM, Michal Hocko <[email protected]> wrote:
Though is there a precedence where the broken feature is not fixed because an alternative is available?Well, I can see how breaking
GFP_NOFAILsemantic is problematic, on the other hand we keep saying that kmem accounting in v1 is hard usable and strongly discourage people from using it. Sure we can add the code which handles _this_ particular case but that wouldn't make the whole thing more usable I strongly suspect. Maybe I am wrong and you can provide some specific examples. IsGFP_NOFAILthat common to matter?
Quoted 3 lines
In any case we should balance between the code maintainability here. Adding more cruft into the allocator path is not free.
We do not use kmem limits internally and this is something I found through code inspection. If this patch is increasing the cost of code maintainability I am fine with dropping it but at least there should a comment saying that kmem limits are broken and no need fix.
Shakeel
Quoted 13 lines · Shakeel Butt
Quoted 12 lines · Michal Hocko
Quoted 3 lines · Shakeel Butt
On Mon, May 28, 2018 at 2:11 AM, Michal Hocko <[email protected]> wrote:
Though is there a precedence where the broken feature is not fixed because an alternative is available?Well, I can see how breaking
GFP_NOFAILsemantic is problematic, on the other hand we keep saying that kmem accounting in v1 is hard usable and strongly discourage people from using it. Sure we can add the code which handles _this_ particular case but that wouldn't make the whole thing more usable I strongly suspect. Maybe I am wrong and you can provide some specific examples. IsGFP_NOFAILthat common to matter?
Quoted 8 lines
Quoted 3 lines
In any case we should balance between the code maintainability here. Adding more cruft into the allocator path is not free.
We do not use kmem limits internally and this is something I found through code inspection. If this patch is increasing the cost of code maintainability I am fine with dropping it but at least there should a comment saying that kmem limits are broken and no need fix.
I agree.
Even, I didn't know kmem is strongly discouraged until now. Then, why is it enabled by default on cgroup v1?
Let's turn if off with comment "It's broken so do not use/fix. Instead, please move to cgroup v2".
Michal Hocko
maintainerQuoted 23 lines · Minchan Kim
Quoted 13 lines · Shakeel Butt
Quoted 12 lines · Michal Hocko
Quoted 3 lines · Shakeel Butt
On Mon, May 28, 2018 at 2:11 AM, Michal Hocko <[email protected]> wrote:
Though is there a precedence where the broken feature is not fixed because an alternative is available?Well, I can see how breaking
GFP_NOFAILsemantic is problematic, on the other hand we keep saying that kmem accounting in v1 is hard usable and strongly discourage people from using it. Sure we can add the code which handles _this_ particular case but that wouldn't make the whole thing more usable I strongly suspect. Maybe I am wrong and you can provide some specific examples. IsGFP_NOFAILthat common to matter?Quoted 8 lines
Quoted 3 lines
In any case we should balance between the code maintainability here. Adding more cruft into the allocator path is not free.
We do not use kmem limits internally and this is something I found through code inspection. If this patch is increasing the cost of code maintainability I am fine with dropping it but at least there should a comment saying that kmem limits are broken and no need fix.
Quoted 4 lines
I agree.
Even, I didn't know kmem is strongly discouraged until now. Then, why is it enabled by default on cgroup v1?
You have to set a non-zero limit to make it active IIRC. The code is compiled in because v2 enables it by default.
Quoted 2 lines
Let's turn if off with comment "It's broken so do not use/fix. Instead, please move to cgroup v2".
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 24 lines · Michal Hocko
Quoted 23 lines · Minchan Kim
Quoted 21 lines · Shakeel Butt
Quoted 12 lines · Michal Hocko
Quoted 3 lines · Shakeel Butt
On Mon, May 28, 2018 at 2:11 AM, Michal Hocko <[email protected]> wrote:
Though is there a precedence where the broken feature is not fixed because an alternative is available?Well, I can see how breaking
GFP_NOFAILsemantic is problematic, on the other hand we keep saying that kmem accounting in v1 is hard usable and strongly discourage people from using it. Sure we can add the code which handles _this_ particular case but that wouldn't make the whole thing more usable I strongly suspect. Maybe I am wrong and you can provide some specific examples. IsGFP_NOFAILthat common to matter?Quoted 3 lines
In any case we should balance between the code maintainability here. Adding more cruft into the allocator path is not free.
We do not use kmem limits internally and this is something I found through code inspection. If this patch is increasing the cost of code maintainability I am fine with dropping it but at least there should a comment saying that kmem limits are broken and no need fix.
Quoted 6 lines
Quoted 4 lines
I agree.
Even, I didn't know kmem is strongly discouraged until now. Then, why is it enabled by default on cgroup v1?
You have to set a non-zero limit to make it active IIRC. The code is
Maybe, no. I didn't set anything. IOW, it was a default without any setting and I hit this as you can remember.
http://lkml.kernel.org/r/<[email protected]>
We don't need to allocate memory for stuff even maintainers discourage.
Quoted 8 lines
compiled in because v2 enables it by default.
Quoted 2 lines
Let's turn if off with comment "It's broken so do not use/fix. Instead, please move to cgroup v2".
Signature · 2 lines
Michal Hocko SUSE Labs
Michal Hocko
maintainerQuoted 30 lines · Minchan Kim
Quoted 29 lines · Michal Hocko
Quoted 27 lines · Minchan Kim
Quoted 13 lines · Shakeel Butt
Quoted 12 lines · Michal Hocko
Quoted 3 lines · Shakeel Butt
On Mon, May 28, 2018 at 2:11 AM, Michal Hocko <[email protected]> wrote:
Though is there a precedence where the broken feature is not fixed because an alternative is available?Well, I can see how breaking
GFP_NOFAILsemantic is problematic, on the other hand we keep saying that kmem accounting in v1 is hard usable and strongly discourage people from using it. Sure we can add the code which handles _this_ particular case but that wouldn't make the whole thing more usable I strongly suspect. Maybe I am wrong and you can provide some specific examples. IsGFP_NOFAILthat common to matter?Quoted 8 lines
Quoted 3 lines
In any case we should balance between the code maintainability here. Adding more cruft into the allocator path is not free.
We do not use kmem limits internally and this is something I found through code inspection. If this patch is increasing the cost of code maintainability I am fine with dropping it but at least there should a comment saying that kmem limits are broken and no need fix.
I agree.
Even, I didn't know kmem is strongly discouraged until now. Then, why is it enabled by default on cgroup v1?
Quoted 6 lines
Quoted 1 line
You have to set a non-zero limit to make it active IIRC. The code is
Maybe, no. I didn't set anything. IOW, it was a default without any setting and I hit this as you can remember.
http://lkml.kernel.org/r/<[email protected]>
We don't need to allocate memory for stuff even maintainers discourage.
Well, you can disable the whole kmem accounting by cgroup.memory=nokmem kernel parameter. I wasn't very happy when we removed the config option which would have put all the tracking aside even when no limit is set but the argument was that the ifdefery was growing into an unmaintainable mess and I have to agree with that. So here we are...
Signature · 2 lines
Michal Hocko SUSE Labs