diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2008-07-25 04:47:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:40 -0400 |
commit | b564daf806d492dd4f7afe9b6c83b8d35d137669 (patch) | |
tree | fbd6d186035b9a0a270fca97887da5d6b106a60c /kernel | |
parent | 9d5b327bf198d2720666de958dcc2ae219d86952 (diff) |
coredump: construct the list of coredumping threads at startup time
binfmt->core_dump() has to iterate over the all threads in system in order
to find the coredumping threads and construct the list using the
GFP_ATOMIC allocations.
With this patch each thread allocates the list node on exit_mm()'s stack and
adds itself to the list.
This allows us to do further changes:
- simplify ->core_dump()
- change exit_mm() to clear ->mm first, then wait for ->core_done.
this makes the coredumping process visible to oom_kill
- kill mm->core_done
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Acked-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/exit.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 63d82957baae..b66f0d55c791 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -664,6 +664,7 @@ assign_new_owner: | |||
664 | static void exit_mm(struct task_struct * tsk) | 664 | static void exit_mm(struct task_struct * tsk) |
665 | { | 665 | { |
666 | struct mm_struct *mm = tsk->mm; | 666 | struct mm_struct *mm = tsk->mm; |
667 | struct core_state *core_state; | ||
667 | 668 | ||
668 | mm_release(tsk, mm); | 669 | mm_release(tsk, mm); |
669 | if (!mm) | 670 | if (!mm) |
@@ -676,11 +677,19 @@ static void exit_mm(struct task_struct * tsk) | |||
676 | * group with ->mm != NULL. | 677 | * group with ->mm != NULL. |
677 | */ | 678 | */ |
678 | down_read(&mm->mmap_sem); | 679 | down_read(&mm->mmap_sem); |
679 | if (mm->core_state) { | 680 | core_state = mm->core_state; |
681 | if (core_state) { | ||
682 | struct core_thread self; | ||
680 | up_read(&mm->mmap_sem); | 683 | up_read(&mm->mmap_sem); |
681 | 684 | ||
682 | if (atomic_dec_and_test(&mm->core_state->nr_threads)) | 685 | self.task = tsk; |
683 | complete(&mm->core_state->startup); | 686 | self.next = xchg(&core_state->dumper.next, &self); |
687 | /* | ||
688 | * Implies mb(), the result of xchg() must be visible | ||
689 | * to core_state->dumper. | ||
690 | */ | ||
691 | if (atomic_dec_and_test(&core_state->nr_threads)) | ||
692 | complete(&core_state->startup); | ||
684 | 693 | ||
685 | wait_for_completion(&mm->core_done); | 694 | wait_for_completion(&mm->core_done); |
686 | down_read(&mm->mmap_sem); | 695 | down_read(&mm->mmap_sem); |