diff options
author | David Rientjes <rientjes@google.com> | 2015-09-08 18:00:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 18:35:28 -0400 |
commit | 6e0fc46dc2152d3e2d25a5d5b640ae3586c247c6 (patch) | |
tree | 9e519cc7a04ee878c53a045514c83c079bdefa7a | |
parent | 2c0b80d463c6ade539d51ad03bc7c41849fb37e8 (diff) |
mm, oom: organize oom context into struct
There are essential elements to an oom context that are passed around to
multiple functions.
Organize these elements into a new struct, struct oom_control, that
specifies the context for an oom condition.
This patch introduces no functional change.
Signed-off-by: David Rientjes <rientjes@google.com>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/tty/sysrq.c | 12 | ||||
-rw-r--r-- | include/linux/oom.h | 25 | ||||
-rw-r--r-- | mm/memcontrol.c | 16 | ||||
-rw-r--r-- | mm/oom_kill.c | 115 | ||||
-rw-r--r-- | mm/page_alloc.c | 10 |
5 files changed, 98 insertions, 80 deletions
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index b5b427888b24..ed3e258f4ee9 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c | |||
@@ -353,9 +353,17 @@ static struct sysrq_key_op sysrq_term_op = { | |||
353 | 353 | ||
354 | static void moom_callback(struct work_struct *ignored) | 354 | static void moom_callback(struct work_struct *ignored) |
355 | { | 355 | { |
356 | const gfp_t gfp_mask = GFP_KERNEL; | ||
357 | struct oom_control oc = { | ||
358 | .zonelist = node_zonelist(first_memory_node, gfp_mask), | ||
359 | .nodemask = NULL, | ||
360 | .gfp_mask = gfp_mask, | ||
361 | .order = 0, | ||
362 | .force_kill = true, | ||
363 | }; | ||
364 | |||
356 | mutex_lock(&oom_lock); | 365 | mutex_lock(&oom_lock); |
357 | if (!out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL), | 366 | if (!out_of_memory(&oc)) |
358 | GFP_KERNEL, 0, NULL, true)) | ||
359 | pr_info("OOM request ignored because killer is disabled\n"); | 367 | pr_info("OOM request ignored because killer is disabled\n"); |
360 | mutex_unlock(&oom_lock); | 368 | mutex_unlock(&oom_lock); |
361 | } | 369 | } |
diff --git a/include/linux/oom.h b/include/linux/oom.h index 7deecb7bca5e..cb29085ded37 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h | |||
@@ -12,6 +12,14 @@ struct notifier_block; | |||
12 | struct mem_cgroup; | 12 | struct mem_cgroup; |
13 | struct task_struct; | 13 | struct task_struct; |
14 | 14 | ||
15 | struct oom_control { | ||
16 | struct zonelist *zonelist; | ||
17 | nodemask_t *nodemask; | ||
18 | gfp_t gfp_mask; | ||
19 | int order; | ||
20 | bool force_kill; | ||
21 | }; | ||
22 | |||
15 | /* | 23 | /* |
16 | * Types of limitations to the nodes from which allocations may occur | 24 | * Types of limitations to the nodes from which allocations may occur |
17 | */ | 25 | */ |
@@ -57,21 +65,18 @@ extern unsigned long oom_badness(struct task_struct *p, | |||
57 | 65 | ||
58 | extern int oom_kills_count(void); | 66 | extern int oom_kills_count(void); |
59 | extern void note_oom_kill(void); | 67 | extern void note_oom_kill(void); |
60 | extern void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | 68 | extern void oom_kill_process(struct oom_control *oc, struct task_struct *p, |
61 | unsigned int points, unsigned long totalpages, | 69 | unsigned int points, unsigned long totalpages, |
62 | struct mem_cgroup *memcg, nodemask_t *nodemask, | 70 | struct mem_cgroup *memcg, const char *message); |
63 | const char *message); | ||
64 | 71 | ||
65 | extern void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask, | 72 | extern void check_panic_on_oom(struct oom_control *oc, |
66 | int order, const nodemask_t *nodemask, | 73 | enum oom_constraint constraint, |
67 | struct mem_cgroup *memcg); | 74 | struct mem_cgroup *memcg); |
68 | 75 | ||
69 | extern enum oom_scan_t oom_scan_process_thread(struct task_struct *task, | 76 | extern enum oom_scan_t oom_scan_process_thread(struct oom_control *oc, |
70 | unsigned long totalpages, const nodemask_t *nodemask, | 77 | struct task_struct *task, unsigned long totalpages); |
71 | bool force_kill); | ||
72 | 78 | ||
73 | extern bool out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, | 79 | extern bool out_of_memory(struct oom_control *oc); |
74 | int order, nodemask_t *mask, bool force_kill); | ||
75 | 80 | ||
76 | extern void exit_oom_victim(void); | 81 | extern void exit_oom_victim(void); |
77 | 82 | ||
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 1af057575ce9..573d90347aa2 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1545,6 +1545,13 @@ static unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg) | |||
1545 | static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, | 1545 | static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, |
1546 | int order) | 1546 | int order) |
1547 | { | 1547 | { |
1548 | struct oom_control oc = { | ||
1549 | .zonelist = NULL, | ||
1550 | .nodemask = NULL, | ||
1551 | .gfp_mask = gfp_mask, | ||
1552 | .order = order, | ||
1553 | .force_kill = false, | ||
1554 | }; | ||
1548 | struct mem_cgroup *iter; | 1555 | struct mem_cgroup *iter; |
1549 | unsigned long chosen_points = 0; | 1556 | unsigned long chosen_points = 0; |
1550 | unsigned long totalpages; | 1557 | unsigned long totalpages; |
@@ -1563,7 +1570,7 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, | |||
1563 | goto unlock; | 1570 | goto unlock; |
1564 | } | 1571 | } |
1565 | 1572 | ||
1566 | check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, order, NULL, memcg); | 1573 | check_panic_on_oom(&oc, CONSTRAINT_MEMCG, memcg); |
1567 | totalpages = mem_cgroup_get_limit(memcg) ? : 1; | 1574 | totalpages = mem_cgroup_get_limit(memcg) ? : 1; |
1568 | for_each_mem_cgroup_tree(iter, memcg) { | 1575 | for_each_mem_cgroup_tree(iter, memcg) { |
1569 | struct css_task_iter it; | 1576 | struct css_task_iter it; |
@@ -1571,8 +1578,7 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, | |||
1571 | 1578 | ||
1572 | css_task_iter_start(&iter->css, &it); | 1579 | css_task_iter_start(&iter->css, &it); |
1573 | while ((task = css_task_iter_next(&it))) { | 1580 | while ((task = css_task_iter_next(&it))) { |
1574 | switch (oom_scan_process_thread(task, totalpages, NULL, | 1581 | switch (oom_scan_process_thread(&oc, task, totalpages)) { |
1575 | false)) { | ||
1576 | case OOM_SCAN_SELECT: | 1582 | case OOM_SCAN_SELECT: |
1577 | if (chosen) | 1583 | if (chosen) |
1578 | put_task_struct(chosen); | 1584 | put_task_struct(chosen); |
@@ -1610,8 +1616,8 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, | |||
1610 | 1616 | ||
1611 | if (chosen) { | 1617 | if (chosen) { |
1612 | points = chosen_points * 1000 / totalpages; | 1618 | points = chosen_points * 1000 / totalpages; |
1613 | oom_kill_process(chosen, gfp_mask, order, points, totalpages, | 1619 | oom_kill_process(&oc, chosen, points, totalpages, memcg, |
1614 | memcg, NULL, "Memory cgroup out of memory"); | 1620 | "Memory cgroup out of memory"); |
1615 | } | 1621 | } |
1616 | unlock: | 1622 | unlock: |
1617 | mutex_unlock(&oom_lock); | 1623 | mutex_unlock(&oom_lock); |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index dff991e0681e..80a7cbd89d66 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -196,27 +196,26 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg, | |||
196 | * Determine the type of allocation constraint. | 196 | * Determine the type of allocation constraint. |
197 | */ | 197 | */ |
198 | #ifdef CONFIG_NUMA | 198 | #ifdef CONFIG_NUMA |
199 | static enum oom_constraint constrained_alloc(struct zonelist *zonelist, | 199 | static enum oom_constraint constrained_alloc(struct oom_control *oc, |
200 | gfp_t gfp_mask, nodemask_t *nodemask, | 200 | unsigned long *totalpages) |
201 | unsigned long *totalpages) | ||
202 | { | 201 | { |
203 | struct zone *zone; | 202 | struct zone *zone; |
204 | struct zoneref *z; | 203 | struct zoneref *z; |
205 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); | 204 | enum zone_type high_zoneidx = gfp_zone(oc->gfp_mask); |
206 | bool cpuset_limited = false; | 205 | bool cpuset_limited = false; |
207 | int nid; | 206 | int nid; |
208 | 207 | ||
209 | /* Default to all available memory */ | 208 | /* Default to all available memory */ |
210 | *totalpages = totalram_pages + total_swap_pages; | 209 | *totalpages = totalram_pages + total_swap_pages; |
211 | 210 | ||
212 | if (!zonelist) | 211 | if (!oc->zonelist) |
213 | return CONSTRAINT_NONE; | 212 | return CONSTRAINT_NONE; |
214 | /* | 213 | /* |
215 | * Reach here only when __GFP_NOFAIL is used. So, we should avoid | 214 | * Reach here only when __GFP_NOFAIL is used. So, we should avoid |
216 | * to kill current.We have to random task kill in this case. | 215 | * to kill current.We have to random task kill in this case. |
217 | * Hopefully, CONSTRAINT_THISNODE...but no way to handle it, now. | 216 | * Hopefully, CONSTRAINT_THISNODE...but no way to handle it, now. |
218 | */ | 217 | */ |
219 | if (gfp_mask & __GFP_THISNODE) | 218 | if (oc->gfp_mask & __GFP_THISNODE) |
220 | return CONSTRAINT_NONE; | 219 | return CONSTRAINT_NONE; |
221 | 220 | ||
222 | /* | 221 | /* |
@@ -224,17 +223,18 @@ static enum oom_constraint constrained_alloc(struct zonelist *zonelist, | |||
224 | * the page allocator means a mempolicy is in effect. Cpuset policy | 223 | * the page allocator means a mempolicy is in effect. Cpuset policy |
225 | * is enforced in get_page_from_freelist(). | 224 | * is enforced in get_page_from_freelist(). |
226 | */ | 225 | */ |
227 | if (nodemask && !nodes_subset(node_states[N_MEMORY], *nodemask)) { | 226 | if (oc->nodemask && |
227 | !nodes_subset(node_states[N_MEMORY], *oc->nodemask)) { | ||
228 | *totalpages = total_swap_pages; | 228 | *totalpages = total_swap_pages; |
229 | for_each_node_mask(nid, *nodemask) | 229 | for_each_node_mask(nid, *oc->nodemask) |
230 | *totalpages += node_spanned_pages(nid); | 230 | *totalpages += node_spanned_pages(nid); |
231 | return CONSTRAINT_MEMORY_POLICY; | 231 | return CONSTRAINT_MEMORY_POLICY; |
232 | } | 232 | } |
233 | 233 | ||
234 | /* Check this allocation failure is caused by cpuset's wall function */ | 234 | /* Check this allocation failure is caused by cpuset's wall function */ |
235 | for_each_zone_zonelist_nodemask(zone, z, zonelist, | 235 | for_each_zone_zonelist_nodemask(zone, z, oc->zonelist, |
236 | high_zoneidx, nodemask) | 236 | high_zoneidx, oc->nodemask) |
237 | if (!cpuset_zone_allowed(zone, gfp_mask)) | 237 | if (!cpuset_zone_allowed(zone, oc->gfp_mask)) |
238 | cpuset_limited = true; | 238 | cpuset_limited = true; |
239 | 239 | ||
240 | if (cpuset_limited) { | 240 | if (cpuset_limited) { |
@@ -246,20 +246,18 @@ static enum oom_constraint constrained_alloc(struct zonelist *zonelist, | |||
246 | return CONSTRAINT_NONE; | 246 | return CONSTRAINT_NONE; |
247 | } | 247 | } |
248 | #else | 248 | #else |
249 | static enum oom_constraint constrained_alloc(struct zonelist *zonelist, | 249 | static enum oom_constraint constrained_alloc(struct oom_control *oc, |
250 | gfp_t gfp_mask, nodemask_t *nodemask, | 250 | unsigned long *totalpages) |
251 | unsigned long *totalpages) | ||
252 | { | 251 | { |
253 | *totalpages = totalram_pages + total_swap_pages; | 252 | *totalpages = totalram_pages + total_swap_pages; |
254 | return CONSTRAINT_NONE; | 253 | return CONSTRAINT_NONE; |
255 | } | 254 | } |
256 | #endif | 255 | #endif |
257 | 256 | ||
258 | enum oom_scan_t oom_scan_process_thread(struct task_struct *task, | 257 | enum oom_scan_t oom_scan_process_thread(struct oom_control *oc, |
259 | unsigned long totalpages, const nodemask_t *nodemask, | 258 | struct task_struct *task, unsigned long totalpages) |
260 | bool force_kill) | ||
261 | { | 259 | { |
262 | if (oom_unkillable_task(task, NULL, nodemask)) | 260 | if (oom_unkillable_task(task, NULL, oc->nodemask)) |
263 | return OOM_SCAN_CONTINUE; | 261 | return OOM_SCAN_CONTINUE; |
264 | 262 | ||
265 | /* | 263 | /* |
@@ -267,7 +265,7 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task, | |||
267 | * Don't allow any other task to have access to the reserves. | 265 | * Don't allow any other task to have access to the reserves. |
268 | */ | 266 | */ |
269 | if (test_tsk_thread_flag(task, TIF_MEMDIE)) { | 267 | if (test_tsk_thread_flag(task, TIF_MEMDIE)) { |
270 | if (!force_kill) | 268 | if (!oc->force_kill) |
271 | return OOM_SCAN_ABORT; | 269 | return OOM_SCAN_ABORT; |
272 | } | 270 | } |
273 | if (!task->mm) | 271 | if (!task->mm) |
@@ -280,7 +278,7 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task, | |||
280 | if (oom_task_origin(task)) | 278 | if (oom_task_origin(task)) |
281 | return OOM_SCAN_SELECT; | 279 | return OOM_SCAN_SELECT; |
282 | 280 | ||
283 | if (task_will_free_mem(task) && !force_kill) | 281 | if (task_will_free_mem(task) && !oc->force_kill) |
284 | return OOM_SCAN_ABORT; | 282 | return OOM_SCAN_ABORT; |
285 | 283 | ||
286 | return OOM_SCAN_OK; | 284 | return OOM_SCAN_OK; |
@@ -289,12 +287,9 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task, | |||
289 | /* | 287 | /* |
290 | * Simple selection loop. We chose the process with the highest | 288 | * Simple selection loop. We chose the process with the highest |
291 | * number of 'points'. Returns -1 on scan abort. | 289 | * number of 'points'. Returns -1 on scan abort. |
292 | * | ||
293 | * (not docbooked, we don't want this one cluttering up the manual) | ||
294 | */ | 290 | */ |
295 | static struct task_struct *select_bad_process(unsigned int *ppoints, | 291 | static struct task_struct *select_bad_process(struct oom_control *oc, |
296 | unsigned long totalpages, const nodemask_t *nodemask, | 292 | unsigned int *ppoints, unsigned long totalpages) |
297 | bool force_kill) | ||
298 | { | 293 | { |
299 | struct task_struct *g, *p; | 294 | struct task_struct *g, *p; |
300 | struct task_struct *chosen = NULL; | 295 | struct task_struct *chosen = NULL; |
@@ -304,8 +299,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, | |||
304 | for_each_process_thread(g, p) { | 299 | for_each_process_thread(g, p) { |
305 | unsigned int points; | 300 | unsigned int points; |
306 | 301 | ||
307 | switch (oom_scan_process_thread(p, totalpages, nodemask, | 302 | switch (oom_scan_process_thread(oc, p, totalpages)) { |
308 | force_kill)) { | ||
309 | case OOM_SCAN_SELECT: | 303 | case OOM_SCAN_SELECT: |
310 | chosen = p; | 304 | chosen = p; |
311 | chosen_points = ULONG_MAX; | 305 | chosen_points = ULONG_MAX; |
@@ -318,7 +312,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, | |||
318 | case OOM_SCAN_OK: | 312 | case OOM_SCAN_OK: |
319 | break; | 313 | break; |
320 | }; | 314 | }; |
321 | points = oom_badness(p, NULL, nodemask, totalpages); | 315 | points = oom_badness(p, NULL, oc->nodemask, totalpages); |
322 | if (!points || points < chosen_points) | 316 | if (!points || points < chosen_points) |
323 | continue; | 317 | continue; |
324 | /* Prefer thread group leaders for display purposes */ | 318 | /* Prefer thread group leaders for display purposes */ |
@@ -380,13 +374,13 @@ static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask) | |||
380 | rcu_read_unlock(); | 374 | rcu_read_unlock(); |
381 | } | 375 | } |
382 | 376 | ||
383 | static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, | 377 | static void dump_header(struct oom_control *oc, struct task_struct *p, |
384 | struct mem_cgroup *memcg, const nodemask_t *nodemask) | 378 | struct mem_cgroup *memcg) |
385 | { | 379 | { |
386 | task_lock(current); | 380 | task_lock(current); |
387 | pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, " | 381 | pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, " |
388 | "oom_score_adj=%hd\n", | 382 | "oom_score_adj=%hd\n", |
389 | current->comm, gfp_mask, order, | 383 | current->comm, oc->gfp_mask, oc->order, |
390 | current->signal->oom_score_adj); | 384 | current->signal->oom_score_adj); |
391 | cpuset_print_task_mems_allowed(current); | 385 | cpuset_print_task_mems_allowed(current); |
392 | task_unlock(current); | 386 | task_unlock(current); |
@@ -396,7 +390,7 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, | |||
396 | else | 390 | else |
397 | show_mem(SHOW_MEM_FILTER_NODES); | 391 | show_mem(SHOW_MEM_FILTER_NODES); |
398 | if (sysctl_oom_dump_tasks) | 392 | if (sysctl_oom_dump_tasks) |
399 | dump_tasks(memcg, nodemask); | 393 | dump_tasks(memcg, oc->nodemask); |
400 | } | 394 | } |
401 | 395 | ||
402 | /* | 396 | /* |
@@ -487,10 +481,9 @@ void oom_killer_enable(void) | |||
487 | * Must be called while holding a reference to p, which will be released upon | 481 | * Must be called while holding a reference to p, which will be released upon |
488 | * returning. | 482 | * returning. |
489 | */ | 483 | */ |
490 | void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | 484 | void oom_kill_process(struct oom_control *oc, struct task_struct *p, |
491 | unsigned int points, unsigned long totalpages, | 485 | unsigned int points, unsigned long totalpages, |
492 | struct mem_cgroup *memcg, nodemask_t *nodemask, | 486 | struct mem_cgroup *memcg, const char *message) |
493 | const char *message) | ||
494 | { | 487 | { |
495 | struct task_struct *victim = p; | 488 | struct task_struct *victim = p; |
496 | struct task_struct *child; | 489 | struct task_struct *child; |
@@ -514,7 +507,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
514 | task_unlock(p); | 507 | task_unlock(p); |
515 | 508 | ||
516 | if (__ratelimit(&oom_rs)) | 509 | if (__ratelimit(&oom_rs)) |
517 | dump_header(p, gfp_mask, order, memcg, nodemask); | 510 | dump_header(oc, p, memcg); |
518 | 511 | ||
519 | task_lock(p); | 512 | task_lock(p); |
520 | pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n", | 513 | pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n", |
@@ -537,7 +530,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
537 | /* | 530 | /* |
538 | * oom_badness() returns 0 if the thread is unkillable | 531 | * oom_badness() returns 0 if the thread is unkillable |
539 | */ | 532 | */ |
540 | child_points = oom_badness(child, memcg, nodemask, | 533 | child_points = oom_badness(child, memcg, oc->nodemask, |
541 | totalpages); | 534 | totalpages); |
542 | if (child_points > victim_points) { | 535 | if (child_points > victim_points) { |
543 | put_task_struct(victim); | 536 | put_task_struct(victim); |
@@ -600,8 +593,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
600 | /* | 593 | /* |
601 | * Determines whether the kernel must panic because of the panic_on_oom sysctl. | 594 | * Determines whether the kernel must panic because of the panic_on_oom sysctl. |
602 | */ | 595 | */ |
603 | void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask, | 596 | void check_panic_on_oom(struct oom_control *oc, enum oom_constraint constraint, |
604 | int order, const nodemask_t *nodemask, | ||
605 | struct mem_cgroup *memcg) | 597 | struct mem_cgroup *memcg) |
606 | { | 598 | { |
607 | if (likely(!sysctl_panic_on_oom)) | 599 | if (likely(!sysctl_panic_on_oom)) |
@@ -615,7 +607,7 @@ void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask, | |||
615 | if (constraint != CONSTRAINT_NONE) | 607 | if (constraint != CONSTRAINT_NONE) |
616 | return; | 608 | return; |
617 | } | 609 | } |
618 | dump_header(NULL, gfp_mask, order, memcg, nodemask); | 610 | dump_header(oc, NULL, memcg); |
619 | panic("Out of memory: %s panic_on_oom is enabled\n", | 611 | panic("Out of memory: %s panic_on_oom is enabled\n", |
620 | sysctl_panic_on_oom == 2 ? "compulsory" : "system-wide"); | 612 | sysctl_panic_on_oom == 2 ? "compulsory" : "system-wide"); |
621 | } | 613 | } |
@@ -635,22 +627,16 @@ int unregister_oom_notifier(struct notifier_block *nb) | |||
635 | EXPORT_SYMBOL_GPL(unregister_oom_notifier); | 627 | EXPORT_SYMBOL_GPL(unregister_oom_notifier); |
636 | 628 | ||
637 | /** | 629 | /** |
638 | * __out_of_memory - kill the "best" process when we run out of memory | 630 | * out_of_memory - kill the "best" process when we run out of memory |
639 | * @zonelist: zonelist pointer | 631 | * @oc: pointer to struct oom_control |
640 | * @gfp_mask: memory allocation flags | ||
641 | * @order: amount of memory being requested as a power of 2 | ||
642 | * @nodemask: nodemask passed to page allocator | ||
643 | * @force_kill: true if a task must be killed, even if others are exiting | ||
644 | * | 632 | * |
645 | * If we run out of memory, we have the choice between either | 633 | * If we run out of memory, we have the choice between either |
646 | * killing a random task (bad), letting the system crash (worse) | 634 | * killing a random task (bad), letting the system crash (worse) |
647 | * OR try to be smart about which process to kill. Note that we | 635 | * OR try to be smart about which process to kill. Note that we |
648 | * don't have to be perfect here, we just have to be good. | 636 | * don't have to be perfect here, we just have to be good. |
649 | */ | 637 | */ |
650 | bool out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, | 638 | bool out_of_memory(struct oom_control *oc) |
651 | int order, nodemask_t *nodemask, bool force_kill) | ||
652 | { | 639 | { |
653 | const nodemask_t *mpol_mask; | ||
654 | struct task_struct *p; | 640 | struct task_struct *p; |
655 | unsigned long totalpages; | 641 | unsigned long totalpages; |
656 | unsigned long freed = 0; | 642 | unsigned long freed = 0; |
@@ -684,30 +670,29 @@ bool out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, | |||
684 | * Check if there were limitations on the allocation (only relevant for | 670 | * Check if there were limitations on the allocation (only relevant for |
685 | * NUMA) that may require different handling. | 671 | * NUMA) that may require different handling. |
686 | */ | 672 | */ |
687 | constraint = constrained_alloc(zonelist, gfp_mask, nodemask, | 673 | constraint = constrained_alloc(oc, &totalpages); |
688 | &totalpages); | 674 | if (constraint != CONSTRAINT_MEMORY_POLICY) |
689 | mpol_mask = (constraint == CONSTRAINT_MEMORY_POLICY) ? nodemask : NULL; | 675 | oc->nodemask = NULL; |
690 | check_panic_on_oom(constraint, gfp_mask, order, mpol_mask, NULL); | 676 | check_panic_on_oom(oc, constraint, NULL); |
691 | 677 | ||
692 | if (sysctl_oom_kill_allocating_task && current->mm && | 678 | if (sysctl_oom_kill_allocating_task && current->mm && |
693 | !oom_unkillable_task(current, NULL, nodemask) && | 679 | !oom_unkillable_task(current, NULL, oc->nodemask) && |
694 | current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) { | 680 | current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) { |
695 | get_task_struct(current); | 681 | get_task_struct(current); |
696 | oom_kill_process(current, gfp_mask, order, 0, totalpages, NULL, | 682 | oom_kill_process(oc, current, 0, totalpages, NULL, |
697 | nodemask, | ||
698 | "Out of memory (oom_kill_allocating_task)"); | 683 | "Out of memory (oom_kill_allocating_task)"); |
699 | goto out; | 684 | goto out; |
700 | } | 685 | } |
701 | 686 | ||
702 | p = select_bad_process(&points, totalpages, mpol_mask, force_kill); | 687 | p = select_bad_process(oc, &points, totalpages); |
703 | /* Found nothing?!?! Either we hang forever, or we panic. */ | 688 | /* Found nothing?!?! Either we hang forever, or we panic. */ |
704 | if (!p) { | 689 | if (!p) { |
705 | dump_header(NULL, gfp_mask, order, NULL, mpol_mask); | 690 | dump_header(oc, NULL, NULL); |
706 | panic("Out of memory and no killable processes...\n"); | 691 | panic("Out of memory and no killable processes...\n"); |
707 | } | 692 | } |
708 | if (p != (void *)-1UL) { | 693 | if (p != (void *)-1UL) { |
709 | oom_kill_process(p, gfp_mask, order, points, totalpages, NULL, | 694 | oom_kill_process(oc, p, points, totalpages, NULL, |
710 | nodemask, "Out of memory"); | 695 | "Out of memory"); |
711 | killed = 1; | 696 | killed = 1; |
712 | } | 697 | } |
713 | out: | 698 | out: |
@@ -728,13 +713,21 @@ out: | |||
728 | */ | 713 | */ |
729 | void pagefault_out_of_memory(void) | 714 | void pagefault_out_of_memory(void) |
730 | { | 715 | { |
716 | struct oom_control oc = { | ||
717 | .zonelist = NULL, | ||
718 | .nodemask = NULL, | ||
719 | .gfp_mask = 0, | ||
720 | .order = 0, | ||
721 | .force_kill = false, | ||
722 | }; | ||
723 | |||
731 | if (mem_cgroup_oom_synchronize(true)) | 724 | if (mem_cgroup_oom_synchronize(true)) |
732 | return; | 725 | return; |
733 | 726 | ||
734 | if (!mutex_trylock(&oom_lock)) | 727 | if (!mutex_trylock(&oom_lock)) |
735 | return; | 728 | return; |
736 | 729 | ||
737 | if (!out_of_memory(NULL, 0, 0, NULL, false)) { | 730 | if (!out_of_memory(&oc)) { |
738 | /* | 731 | /* |
739 | * There shouldn't be any user tasks runnable while the | 732 | * There shouldn't be any user tasks runnable while the |
740 | * OOM killer is disabled, so the current task has to | 733 | * OOM killer is disabled, so the current task has to |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index badc7d3bde43..96536144185c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -2693,6 +2693,13 @@ static inline struct page * | |||
2693 | __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, | 2693 | __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, |
2694 | const struct alloc_context *ac, unsigned long *did_some_progress) | 2694 | const struct alloc_context *ac, unsigned long *did_some_progress) |
2695 | { | 2695 | { |
2696 | struct oom_control oc = { | ||
2697 | .zonelist = ac->zonelist, | ||
2698 | .nodemask = ac->nodemask, | ||
2699 | .gfp_mask = gfp_mask, | ||
2700 | .order = order, | ||
2701 | .force_kill = false, | ||
2702 | }; | ||
2696 | struct page *page; | 2703 | struct page *page; |
2697 | 2704 | ||
2698 | *did_some_progress = 0; | 2705 | *did_some_progress = 0; |
@@ -2744,8 +2751,7 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, | |||
2744 | goto out; | 2751 | goto out; |
2745 | } | 2752 | } |
2746 | /* Exhausted what can be done so it's blamo time */ | 2753 | /* Exhausted what can be done so it's blamo time */ |
2747 | if (out_of_memory(ac->zonelist, gfp_mask, order, ac->nodemask, false) | 2754 | if (out_of_memory(&oc) || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) |
2748 | || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) | ||
2749 | *did_some_progress = 1; | 2755 | *did_some_progress = 1; |
2750 | out: | 2756 | out: |
2751 | mutex_unlock(&oom_lock); | 2757 | mutex_unlock(&oom_lock); |