aboutsummaryrefslogtreecommitdiffstats
path: root/mm/oom_kill.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/oom_kill.c')
-rw-r--r--mm/oom_kill.c71
1 files changed, 41 insertions, 30 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 78747afad6b0..042e6436c3ee 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -46,15 +46,25 @@
46unsigned long badness(struct task_struct *p, unsigned long uptime) 46unsigned long badness(struct task_struct *p, unsigned long uptime)
47{ 47{
48 unsigned long points, cpu_time, run_time, s; 48 unsigned long points, cpu_time, run_time, s;
49 struct list_head *tsk; 49 struct mm_struct *mm;
50 struct task_struct *child;
50 51
51 if (!p->mm) 52 task_lock(p);
53 mm = p->mm;
54 if (!mm) {
55 task_unlock(p);
52 return 0; 56 return 0;
57 }
53 58
54 /* 59 /*
55 * The memory size of the process is the basis for the badness. 60 * The memory size of the process is the basis for the badness.
56 */ 61 */
57 points = p->mm->total_vm; 62 points = mm->total_vm;
63
64 /*
65 * After this unlock we can no longer dereference local variable `mm'
66 */
67 task_unlock(p);
58 68
59 /* 69 /*
60 * Processes which fork a lot of child processes are likely 70 * Processes which fork a lot of child processes are likely
@@ -64,11 +74,11 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
64 * child is eating the vast majority of memory, adding only half 74 * child is eating the vast majority of memory, adding only half
65 * to the parents will make the child our kill candidate of choice. 75 * to the parents will make the child our kill candidate of choice.
66 */ 76 */
67 list_for_each(tsk, &p->children) { 77 list_for_each_entry(child, &p->children, sibling) {
68 struct task_struct *chld; 78 task_lock(child);
69 chld = list_entry(tsk, struct task_struct, sibling); 79 if (child->mm != mm && child->mm)
70 if (chld->mm != p->mm && chld->mm) 80 points += child->mm->total_vm/2 + 1;
71 points += chld->mm->total_vm/2 + 1; 81 task_unlock(child);
72 } 82 }
73 83
74 /* 84 /*
@@ -244,17 +254,24 @@ static void __oom_kill_task(task_t *p, const char *message)
244 force_sig(SIGKILL, p); 254 force_sig(SIGKILL, p);
245} 255}
246 256
247static struct mm_struct *oom_kill_task(task_t *p, const char *message) 257static int oom_kill_task(task_t *p, const char *message)
248{ 258{
249 struct mm_struct *mm = get_task_mm(p); 259 struct mm_struct *mm;
250 task_t * g, * q; 260 task_t * g, * q;
251 261
252 if (!mm) 262 mm = p->mm;
253 return NULL; 263
254 if (mm == &init_mm) { 264 /* WARNING: mm may not be dereferenced since we did not obtain its
255 mmput(mm); 265 * value from get_task_mm(p). This is OK since all we need to do is
256 return NULL; 266 * compare mm to q->mm below.
257 } 267 *
268 * Furthermore, even if mm contains a non-NULL value, p->mm may
269 * change to NULL at any time since we do not hold task_lock(p).
270 * However, this is of no concern to us.
271 */
272
273 if (mm == NULL || mm == &init_mm)
274 return 1;
258 275
259 __oom_kill_task(p, message); 276 __oom_kill_task(p, message);
260 /* 277 /*
@@ -266,13 +283,12 @@ static struct mm_struct *oom_kill_task(task_t *p, const char *message)
266 __oom_kill_task(q, message); 283 __oom_kill_task(q, message);
267 while_each_thread(g, q); 284 while_each_thread(g, q);
268 285
269 return mm; 286 return 0;
270} 287}
271 288
272static struct mm_struct *oom_kill_process(struct task_struct *p, 289static int oom_kill_process(struct task_struct *p, unsigned long points,
273 unsigned long points, const char *message) 290 const char *message)
274{ 291{
275 struct mm_struct *mm;
276 struct task_struct *c; 292 struct task_struct *c;
277 struct list_head *tsk; 293 struct list_head *tsk;
278 294
@@ -283,9 +299,8 @@ static struct mm_struct *oom_kill_process(struct task_struct *p,
283 c = list_entry(tsk, struct task_struct, sibling); 299 c = list_entry(tsk, struct task_struct, sibling);
284 if (c->mm == p->mm) 300 if (c->mm == p->mm)
285 continue; 301 continue;
286 mm = oom_kill_task(c, message); 302 if (!oom_kill_task(c, message))
287 if (mm) 303 return 0;
288 return mm;
289 } 304 }
290 return oom_kill_task(p, message); 305 return oom_kill_task(p, message);
291} 306}
@@ -300,7 +315,6 @@ static struct mm_struct *oom_kill_process(struct task_struct *p,
300 */ 315 */
301void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order) 316void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order)
302{ 317{
303 struct mm_struct *mm = NULL;
304 task_t *p; 318 task_t *p;
305 unsigned long points = 0; 319 unsigned long points = 0;
306 320
@@ -320,12 +334,12 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order)
320 */ 334 */
321 switch (constrained_alloc(zonelist, gfp_mask)) { 335 switch (constrained_alloc(zonelist, gfp_mask)) {
322 case CONSTRAINT_MEMORY_POLICY: 336 case CONSTRAINT_MEMORY_POLICY:
323 mm = oom_kill_process(current, points, 337 oom_kill_process(current, points,
324 "No available memory (MPOL_BIND)"); 338 "No available memory (MPOL_BIND)");
325 break; 339 break;
326 340
327 case CONSTRAINT_CPUSET: 341 case CONSTRAINT_CPUSET:
328 mm = oom_kill_process(current, points, 342 oom_kill_process(current, points,
329 "No available memory in cpuset"); 343 "No available memory in cpuset");
330 break; 344 break;
331 345
@@ -347,8 +361,7 @@ retry:
347 panic("Out of memory and no killable processes...\n"); 361 panic("Out of memory and no killable processes...\n");
348 } 362 }
349 363
350 mm = oom_kill_process(p, points, "Out of memory"); 364 if (oom_kill_process(p, points, "Out of memory"))
351 if (!mm)
352 goto retry; 365 goto retry;
353 366
354 break; 367 break;
@@ -357,8 +370,6 @@ retry:
357out: 370out:
358 read_unlock(&tasklist_lock); 371 read_unlock(&tasklist_lock);
359 cpuset_unlock(); 372 cpuset_unlock();
360 if (mm)
361 mmput(mm);
362 373
363 /* 374 /*
364 * Give "p" a good chance of killing itself before we 375 * Give "p" a good chance of killing itself before we