diff options
author | Pavel Emelianov <xemul@openvz.org> | 2008-02-07 03:13:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 11:42:19 -0500 |
commit | c7ba5c9e8176704bfac0729875fa62798037584d (patch) | |
tree | 00df1c4cb67e313cdb66233381b4cee275fd46c0 | |
parent | 0eea10301708c64a6b793894c156e21ddd15eb64 (diff) |
Memory controller: OOM handling
Out of memory handling for cgroups over their limit. A task from the
cgroup over limit is chosen using the existing OOM logic and killed.
TODO:
1. As discussed in the OLS BOF session, consider implementing a user
space policy for OOM handling.
[akpm@linux-foundation.org: fix build due to oom-killer changes]
Signed-off-by: Pavel Emelianov <xemul@openvz.org>
Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: Paul Menage <menage@google.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Kirill Korotaev <dev@sw.ru>
Cc: Herbert Poetzl <herbert@13thfloor.at>
Cc: David Rientjes <rientjes@google.com>
Cc: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/memcontrol.h | 1 | ||||
-rw-r--r-- | mm/memcontrol.c | 1 | ||||
-rw-r--r-- | mm/oom_kill.c | 43 |
3 files changed, 41 insertions, 4 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 9c3c1c97c197..9bbbf524ba8f 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h | |||
@@ -39,6 +39,7 @@ extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan, | |||
39 | int mode, struct zone *z, | 39 | int mode, struct zone *z, |
40 | struct mem_cgroup *mem_cont, | 40 | struct mem_cgroup *mem_cont, |
41 | int active); | 41 | int active); |
42 | extern void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask); | ||
42 | 43 | ||
43 | static inline void mem_cgroup_uncharge_page(struct page *page) | 44 | static inline void mem_cgroup_uncharge_page(struct page *page) |
44 | { | 45 | { |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d73692279ab1..5260658c90aa 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -329,6 +329,7 @@ retry: | |||
329 | } | 329 | } |
330 | 330 | ||
331 | css_put(&mem->css); | 331 | css_put(&mem->css); |
332 | mem_cgroup_out_of_memory(mem, GFP_KERNEL); | ||
332 | goto free_pc; | 333 | goto free_pc; |
333 | } | 334 | } |
334 | 335 | ||
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index c1850bf991cd..64751dc9d997 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/cpuset.h> | 25 | #include <linux/cpuset.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/notifier.h> | 27 | #include <linux/notifier.h> |
28 | #include <linux/memcontrol.h> | ||
28 | 29 | ||
29 | int sysctl_panic_on_oom; | 30 | int sysctl_panic_on_oom; |
30 | int sysctl_oom_kill_allocating_task; | 31 | int sysctl_oom_kill_allocating_task; |
@@ -50,7 +51,8 @@ static DEFINE_SPINLOCK(zone_scan_mutex); | |||
50 | * of least surprise ... (be careful when you change it) | 51 | * of least surprise ... (be careful when you change it) |
51 | */ | 52 | */ |
52 | 53 | ||
53 | unsigned long badness(struct task_struct *p, unsigned long uptime) | 54 | unsigned long badness(struct task_struct *p, unsigned long uptime, |
55 | struct mem_cgroup *mem) | ||
54 | { | 56 | { |
55 | unsigned long points, cpu_time, run_time, s; | 57 | unsigned long points, cpu_time, run_time, s; |
56 | struct mm_struct *mm; | 58 | struct mm_struct *mm; |
@@ -63,6 +65,13 @@ unsigned long badness(struct task_struct *p, unsigned long uptime) | |||
63 | return 0; | 65 | return 0; |
64 | } | 66 | } |
65 | 67 | ||
68 | #ifdef CONFIG_CGROUP_MEM_CONT | ||
69 | if (mem != NULL && mm->mem_cgroup != mem) { | ||
70 | task_unlock(p); | ||
71 | return 0; | ||
72 | } | ||
73 | #endif | ||
74 | |||
66 | /* | 75 | /* |
67 | * The memory size of the process is the basis for the badness. | 76 | * The memory size of the process is the basis for the badness. |
68 | */ | 77 | */ |
@@ -193,7 +202,8 @@ static inline enum oom_constraint constrained_alloc(struct zonelist *zonelist, | |||
193 | * | 202 | * |
194 | * (not docbooked, we don't want this one cluttering up the manual) | 203 | * (not docbooked, we don't want this one cluttering up the manual) |
195 | */ | 204 | */ |
196 | static struct task_struct *select_bad_process(unsigned long *ppoints) | 205 | static struct task_struct *select_bad_process(unsigned long *ppoints, |
206 | struct mem_cgroup *mem) | ||
197 | { | 207 | { |
198 | struct task_struct *g, *p; | 208 | struct task_struct *g, *p; |
199 | struct task_struct *chosen = NULL; | 209 | struct task_struct *chosen = NULL; |
@@ -247,7 +257,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) | |||
247 | if (p->oomkilladj == OOM_DISABLE) | 257 | if (p->oomkilladj == OOM_DISABLE) |
248 | continue; | 258 | continue; |
249 | 259 | ||
250 | points = badness(p, uptime.tv_sec); | 260 | points = badness(p, uptime.tv_sec, mem); |
251 | if (points > *ppoints || !chosen) { | 261 | if (points > *ppoints || !chosen) { |
252 | chosen = p; | 262 | chosen = p; |
253 | *ppoints = points; | 263 | *ppoints = points; |
@@ -368,6 +378,31 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
368 | return oom_kill_task(p); | 378 | return oom_kill_task(p); |
369 | } | 379 | } |
370 | 380 | ||
381 | #ifdef CONFIG_CGROUP_MEM_CONT | ||
382 | void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask) | ||
383 | { | ||
384 | unsigned long points = 0; | ||
385 | struct task_struct *p; | ||
386 | |||
387 | cgroup_lock(); | ||
388 | rcu_read_lock(); | ||
389 | retry: | ||
390 | p = select_bad_process(&points, mem); | ||
391 | if (PTR_ERR(p) == -1UL) | ||
392 | goto out; | ||
393 | |||
394 | if (!p) | ||
395 | p = current; | ||
396 | |||
397 | if (oom_kill_process(p, gfp_mask, 0, points, | ||
398 | "Memory cgroup out of memory")) | ||
399 | goto retry; | ||
400 | out: | ||
401 | rcu_read_unlock(); | ||
402 | cgroup_unlock(); | ||
403 | } | ||
404 | #endif | ||
405 | |||
371 | static BLOCKING_NOTIFIER_HEAD(oom_notify_list); | 406 | static BLOCKING_NOTIFIER_HEAD(oom_notify_list); |
372 | 407 | ||
373 | int register_oom_notifier(struct notifier_block *nb) | 408 | int register_oom_notifier(struct notifier_block *nb) |
@@ -484,7 +519,7 @@ retry: | |||
484 | * Rambo mode: Shoot down a process and hope it solves whatever | 519 | * Rambo mode: Shoot down a process and hope it solves whatever |
485 | * issues we may have. | 520 | * issues we may have. |
486 | */ | 521 | */ |
487 | p = select_bad_process(&points); | 522 | p = select_bad_process(&points, NULL); |
488 | 523 | ||
489 | if (PTR_ERR(p) == -1UL) | 524 | if (PTR_ERR(p) == -1UL) |
490 | goto out; | 525 | goto out; |