diff options
Diffstat (limited to 'kernel/exit.c')
-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); |