diff options
author | KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> | 2010-08-19 17:13:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-20 12:34:55 -0400 |
commit | b52723c5607f7684c2c0c075f86f86da0d7fb6d0 (patch) | |
tree | 97db08ef9d74c8fcacff6a96070854a5bc276419 | |
parent | be71cf2202971e50ce4953d473649c724799eb8a (diff) |
oom: fix tasklist_lock leak
Commit 0aad4b3124 ("oom: fold __out_of_memory into out_of_memory")
introduced a tasklist_lock leak. Then it caused following obvious
danger warnings and panic.
================================================
[ BUG: lock held when returning to user space! ]
------------------------------------------------
rsyslogd/1422 is leaving the kernel with locks still held!
1 lock held by rsyslogd/1422:
#0: (tasklist_lock){.+.+.+}, at: [<ffffffff810faf64>] out_of_memory+0x164/0x3f0
BUG: scheduling while atomic: rsyslogd/1422/0x00000002
INFO: lockdep is turned off.
This patch fixes it.
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Reviewed-by: Minchan Kim <minchan.kim@gmail.com>
Acked-by: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | mm/oom_kill.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 17d48a67e7b7..c48c5ef3ccfd 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -646,6 +646,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, | |||
646 | unsigned long freed = 0; | 646 | unsigned long freed = 0; |
647 | unsigned int points; | 647 | unsigned int points; |
648 | enum oom_constraint constraint = CONSTRAINT_NONE; | 648 | enum oom_constraint constraint = CONSTRAINT_NONE; |
649 | int killed = 0; | ||
649 | 650 | ||
650 | blocking_notifier_call_chain(&oom_notify_list, 0, &freed); | 651 | blocking_notifier_call_chain(&oom_notify_list, 0, &freed); |
651 | if (freed > 0) | 652 | if (freed > 0) |
@@ -683,7 +684,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, | |||
683 | if (!oom_kill_process(current, gfp_mask, order, 0, totalpages, | 684 | if (!oom_kill_process(current, gfp_mask, order, 0, totalpages, |
684 | NULL, nodemask, | 685 | NULL, nodemask, |
685 | "Out of memory (oom_kill_allocating_task)")) | 686 | "Out of memory (oom_kill_allocating_task)")) |
686 | return; | 687 | goto out; |
687 | } | 688 | } |
688 | 689 | ||
689 | retry: | 690 | retry: |
@@ -691,7 +692,7 @@ retry: | |||
691 | constraint == CONSTRAINT_MEMORY_POLICY ? nodemask : | 692 | constraint == CONSTRAINT_MEMORY_POLICY ? nodemask : |
692 | NULL); | 693 | NULL); |
693 | if (PTR_ERR(p) == -1UL) | 694 | if (PTR_ERR(p) == -1UL) |
694 | return; | 695 | goto out; |
695 | 696 | ||
696 | /* Found nothing?!?! Either we hang forever, or we panic. */ | 697 | /* Found nothing?!?! Either we hang forever, or we panic. */ |
697 | if (!p) { | 698 | if (!p) { |
@@ -703,13 +704,15 @@ retry: | |||
703 | if (oom_kill_process(p, gfp_mask, order, points, totalpages, NULL, | 704 | if (oom_kill_process(p, gfp_mask, order, points, totalpages, NULL, |
704 | nodemask, "Out of memory")) | 705 | nodemask, "Out of memory")) |
705 | goto retry; | 706 | goto retry; |
707 | killed = 1; | ||
708 | out: | ||
706 | read_unlock(&tasklist_lock); | 709 | read_unlock(&tasklist_lock); |
707 | 710 | ||
708 | /* | 711 | /* |
709 | * Give "p" a good chance of killing itself before we | 712 | * Give "p" a good chance of killing itself before we |
710 | * retry to allocate memory unless "p" is current | 713 | * retry to allocate memory unless "p" is current |
711 | */ | 714 | */ |
712 | if (!test_thread_flag(TIF_MEMDIE)) | 715 | if (killed && !test_thread_flag(TIF_MEMDIE)) |
713 | schedule_timeout_uninterruptible(1); | 716 | schedule_timeout_uninterruptible(1); |
714 | } | 717 | } |
715 | 718 | ||