aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2006-09-26 02:31:29 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:48:48 -0400
commit50ec3bbffbe8a96347c54832d48110a5bc9e9ff8 (patch)
tree3941902b1c68525472ea3a502e76faa7fe675cd1 /mm
parent7887a3da753e1ba8244556cc9a2b38c815bfe256 (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>
Diffstat (limited to 'mm')
-rw-r--r--mm/oom_kill.c35
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);