aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2013-10-16 16:46:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-10-17 00:35:53 -0400
commit4942642080ea82d99ab5b653abb9a12b7ba31f4a (patch)
tree7ec12b61f0bfdd1f1466e5233b67432828b25c33 /include
parentc88b05b2cd07221cdefd56f7f7422c1459eb60c9 (diff)
mm: memcg: handle non-error OOM situations more gracefully
Commit 3812c8c8f395 ("mm: memcg: do not trap chargers with full callstack on OOM") assumed that only a few places that can trigger a memcg OOM situation do not return VM_FAULT_OOM, like optional page cache readahead. But there are many more and it's impractical to annotate them all. First of all, we don't want to invoke the OOM killer when the failed allocation is gracefully handled, so defer the actual kill to the end of the fault handling as well. This simplifies the code quite a bit for added bonus. Second, since a failed allocation might not be the abrupt end of the fault, the memcg OOM handler needs to be re-entrant until the fault finishes for subsequent allocation attempts. If an allocation is attempted after the task already OOMed, allow it to bypass the limit so that it can quickly finish the fault and invoke the OOM killer. Reported-by: azurIt <azurit@pobox.sk> Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@suse.cz> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/memcontrol.h50
-rw-r--r--include/linux/sched.h7
2 files changed, 14 insertions, 43 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index ecc82b37c4cc..b3e7a667e03c 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -137,47 +137,24 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
137extern void mem_cgroup_replace_page_cache(struct page *oldpage, 137extern void mem_cgroup_replace_page_cache(struct page *oldpage,
138 struct page *newpage); 138 struct page *newpage);
139 139
140/** 140static inline void mem_cgroup_oom_enable(void)
141 * mem_cgroup_toggle_oom - toggle the memcg OOM killer for the current task
142 * @new: true to enable, false to disable
143 *
144 * Toggle whether a failed memcg charge should invoke the OOM killer
145 * or just return -ENOMEM. Returns the previous toggle state.
146 *
147 * NOTE: Any path that enables the OOM killer before charging must
148 * call mem_cgroup_oom_synchronize() afterward to finalize the
149 * OOM handling and clean up.
150 */
151static inline bool mem_cgroup_toggle_oom(bool new)
152{ 141{
153 bool old; 142 WARN_ON(current->memcg_oom.may_oom);
154 143 current->memcg_oom.may_oom = 1;
155 old = current->memcg_oom.may_oom;
156 current->memcg_oom.may_oom = new;
157
158 return old;
159} 144}
160 145
161static inline void mem_cgroup_enable_oom(void) 146static inline void mem_cgroup_oom_disable(void)
162{ 147{
163 bool old = mem_cgroup_toggle_oom(true); 148 WARN_ON(!current->memcg_oom.may_oom);
164 149 current->memcg_oom.may_oom = 0;
165 WARN_ON(old == true);
166}
167
168static inline void mem_cgroup_disable_oom(void)
169{
170 bool old = mem_cgroup_toggle_oom(false);
171
172 WARN_ON(old == false);
173} 150}
174 151
175static inline bool task_in_memcg_oom(struct task_struct *p) 152static inline bool task_in_memcg_oom(struct task_struct *p)
176{ 153{
177 return p->memcg_oom.in_memcg_oom; 154 return p->memcg_oom.memcg;
178} 155}
179 156
180bool mem_cgroup_oom_synchronize(void); 157bool mem_cgroup_oom_synchronize(bool wait);
181 158
182#ifdef CONFIG_MEMCG_SWAP 159#ifdef CONFIG_MEMCG_SWAP
183extern int do_swap_account; 160extern int do_swap_account;
@@ -402,16 +379,11 @@ static inline void mem_cgroup_end_update_page_stat(struct page *page,
402{ 379{
403} 380}
404 381
405static inline bool mem_cgroup_toggle_oom(bool new) 382static inline void mem_cgroup_oom_enable(void)
406{
407 return false;
408}
409
410static inline void mem_cgroup_enable_oom(void)
411{ 383{
412} 384}
413 385
414static inline void mem_cgroup_disable_oom(void) 386static inline void mem_cgroup_oom_disable(void)
415{ 387{
416} 388}
417 389
@@ -420,7 +392,7 @@ static inline bool task_in_memcg_oom(struct task_struct *p)
420 return false; 392 return false;
421} 393}
422 394
423static inline bool mem_cgroup_oom_synchronize(void) 395static inline bool mem_cgroup_oom_synchronize(bool wait)
424{ 396{
425 return false; 397 return false;
426} 398}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 6682da36b293..e27baeeda3f4 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1394,11 +1394,10 @@ struct task_struct {
1394 } memcg_batch; 1394 } memcg_batch;
1395 unsigned int memcg_kmem_skip_account; 1395 unsigned int memcg_kmem_skip_account;
1396 struct memcg_oom_info { 1396 struct memcg_oom_info {
1397 struct mem_cgroup *memcg;
1398 gfp_t gfp_mask;
1399 int order;
1397 unsigned int may_oom:1; 1400 unsigned int may_oom:1;
1398 unsigned int in_memcg_oom:1;
1399 unsigned int oom_locked:1;
1400 int wakeups;
1401 struct mem_cgroup *wait_on_memcg;
1402 } memcg_oom; 1401 } memcg_oom;
1403#endif 1402#endif
1404#ifdef CONFIG_UPROBES 1403#ifdef CONFIG_UPROBES