aboutsummaryrefslogtreecommitdiffstats
path: root/mm/oom_kill.c
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2009-06-16 18:32:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 22:47:43 -0400
commit4d8b9135c30ccbe46e621fefd862969819003fd6 (patch)
tree47674640c8a65b3ba440b2dc224efbab7571c638 /mm/oom_kill.c
parent2ff05b2b4eac2e63d345fc731ea151a060247f53 (diff)
oom: avoid unnecessary mm locking and scanning for OOM_DISABLE
This moves the check for OOM_DISABLE to the badness heuristic so it is only necessary to hold task_lock() once. If the mm is OOM_DISABLE, the score is 0, which is also correctly exported via /proc/pid/oom_score. This requires that tasks with badness scores of 0 are prohibited from being oom killed, which makes sense since they would not allow for future memory freeing anyway. Since the oom_adj value is a characteristic of an mm and not a task, it is no longer necessary to check the oom_adj value for threads sharing the same memory (except when simply issuing SIGKILLs for threads in other thread groups). Cc: Nick Piggin <npiggin@suse.de> Cc: Rik van Riel <riel@redhat.com> Cc: Mel Gorman <mel@csn.ul.ie> Signed-off-by: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/oom_kill.c')
-rw-r--r--mm/oom_kill.c42
1 files changed, 10 insertions, 32 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index b60913520ef3..cdcf89cb9ff2 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -67,6 +67,10 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
67 return 0; 67 return 0;
68 } 68 }
69 oom_adj = mm->oom_adj; 69 oom_adj = mm->oom_adj;
70 if (oom_adj == OOM_DISABLE) {
71 task_unlock(p);
72 return 0;
73 }
70 74
71 /* 75 /*
72 * 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.
@@ -253,15 +257,8 @@ static struct task_struct *select_bad_process(unsigned long *ppoints,
253 *ppoints = ULONG_MAX; 257 *ppoints = ULONG_MAX;
254 } 258 }
255 259
256 task_lock(p);
257 if (p->mm && p->mm->oom_adj == OOM_DISABLE) {
258 task_unlock(p);
259 continue;
260 }
261 task_unlock(p);
262
263 points = badness(p, uptime.tv_sec); 260 points = badness(p, uptime.tv_sec);
264 if (points > *ppoints || !chosen) { 261 if (points > *ppoints) {
265 chosen = p; 262 chosen = p;
266 *ppoints = points; 263 *ppoints = points;
267 } 264 }
@@ -354,32 +351,13 @@ static int oom_kill_task(struct task_struct *p)
354 struct mm_struct *mm; 351 struct mm_struct *mm;
355 struct task_struct *g, *q; 352 struct task_struct *g, *q;
356 353
354 task_lock(p);
357 mm = p->mm; 355 mm = p->mm;
358 356 if (!mm || mm->oom_adj == OOM_DISABLE) {
359 /* WARNING: mm may not be dereferenced since we did not obtain its 357 task_unlock(p);
360 * value from get_task_mm(p). This is OK since all we need to do is
361 * compare mm to q->mm below.
362 *
363 * Furthermore, even if mm contains a non-NULL value, p->mm may
364 * change to NULL at any time since we do not hold task_lock(p).
365 * However, this is of no concern to us.
366 */
367
368 if (mm == NULL)
369 return 1; 358 return 1;
370 359 }
371 /* 360 task_unlock(p);
372 * Don't kill the process if any threads are set to OOM_DISABLE
373 */
374 do_each_thread(g, q) {
375 task_lock(q);
376 if (q->mm == mm && q->mm && q->mm->oom_adj == OOM_DISABLE) {
377 task_unlock(q);
378 return 1;
379 }
380 task_unlock(q);
381 } while_each_thread(g, q);
382
383 __oom_kill_task(p, 1); 361 __oom_kill_task(p, 1);
384 362
385 /* 363 /*