diff options
author | Nick Piggin <npiggin@suse.de> | 2006-09-26 02:31:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 11:48:48 -0400 |
commit | 50ec3bbffbe8a96347c54832d48110a5bc9e9ff8 (patch) | |
tree | 3941902b1c68525472ea3a502e76faa7fe675cd1 | |
parent | 7887a3da753e1ba8244556cc9a2b38c815bfe256 (diff) |
[PATCH] oom: handle current exiting
If current *is* exiting, it should actually be allowed to access reserved
memory rather than OOM kill something else. Can't do this via a straight
check in page_alloc.c because that would allow multiple tasks to use up
reserves. Instead cause current to OOM-kill itself which will mark it as
TIF_MEMDIE.
The current procedure of simply aborting the OOM-kill if a task is exiting can
lead to OOM deadlocks.
In the case of killing a PF_EXITING task, don't make a lot of noise about it.
This becomes more important in future patches, where we can "kill" OOM_DISABLE
tasks.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | mm/oom_kill.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 4f815b06ac1b..0131bae2a16d 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -210,11 +210,26 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) | |||
210 | /* | 210 | /* |
211 | * This is in the process of releasing memory so wait for it | 211 | * This is in the process of releasing memory so wait for it |
212 | * to finish before killing some other task by mistake. | 212 | * to finish before killing some other task by mistake. |
213 | * | ||
214 | * However, if p is the current task, we allow the 'kill' to | ||
215 | * go ahead if it is exiting: this will simply set TIF_MEMDIE, | ||
216 | * which will allow it to gain access to memory reserves in | ||
217 | * the process of exiting and releasing its resources. | ||
218 | * Otherwise we could get an OOM deadlock. | ||
213 | */ | 219 | */ |
214 | releasing = test_tsk_thread_flag(p, TIF_MEMDIE) || | 220 | releasing = test_tsk_thread_flag(p, TIF_MEMDIE) || |
215 | p->flags & PF_EXITING; | 221 | p->flags & PF_EXITING; |
216 | if (releasing && !(p->flags & PF_DEAD)) | 222 | if (releasing) { |
223 | /* PF_DEAD tasks have already released their mm */ | ||
224 | if (p->flags & PF_DEAD) | ||
225 | continue; | ||
226 | if (p->flags & PF_EXITING && p == current) { | ||
227 | chosen = p; | ||
228 | *ppoints = ULONG_MAX; | ||
229 | break; | ||
230 | } | ||
217 | return ERR_PTR(-1UL); | 231 | return ERR_PTR(-1UL); |
232 | } | ||
218 | if (p->flags & PF_SWAPOFF) | 233 | if (p->flags & PF_SWAPOFF) |
219 | return p; | 234 | return p; |
220 | 235 | ||
@@ -248,8 +263,11 @@ static void __oom_kill_task(struct task_struct *p, const char *message) | |||
248 | return; | 263 | return; |
249 | } | 264 | } |
250 | task_unlock(p); | 265 | task_unlock(p); |
251 | printk(KERN_ERR "%s: Killed process %d (%s).\n", | 266 | |
267 | if (message) { | ||
268 | printk(KERN_ERR "%s: Killed process %d (%s).\n", | ||
252 | message, p->pid, p->comm); | 269 | message, p->pid, p->comm); |
270 | } | ||
253 | 271 | ||
254 | /* | 272 | /* |
255 | * We give our sacrificial lamb high priority and access to | 273 | * We give our sacrificial lamb high priority and access to |
@@ -300,8 +318,17 @@ static int oom_kill_process(struct task_struct *p, unsigned long points, | |||
300 | struct task_struct *c; | 318 | struct task_struct *c; |
301 | struct list_head *tsk; | 319 | struct list_head *tsk; |
302 | 320 | ||
303 | printk(KERN_ERR "Out of Memory: Kill process %d (%s) score %li and " | 321 | /* |
304 | "children.\n", p->pid, p->comm, points); | 322 | * If the task is already exiting, don't alarm the sysadmin or kill |
323 | * its children or threads, just set TIF_MEMDIE so it can die quickly | ||
324 | */ | ||
325 | if (p->flags & PF_EXITING) { | ||
326 | __oom_kill_task(p, NULL); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | printk(KERN_ERR "Out of Memory: Kill process %d (%s) score %li" | ||
331 | " and children.\n", p->pid, p->comm, points); | ||
305 | /* Try to kill a child first */ | 332 | /* Try to kill a child first */ |
306 | list_for_each(tsk, &p->children) { | 333 | list_for_each(tsk, &p->children) { |
307 | c = list_entry(tsk, struct task_struct, sibling); | 334 | c = list_entry(tsk, struct task_struct, sibling); |