diff options
-rw-r--r-- | fs/exec.c | 25 | ||||
-rw-r--r-- | include/linux/mm_types.h | 4 | ||||
-rw-r--r-- | kernel/exit.c | 8 |
3 files changed, 30 insertions, 7 deletions
@@ -1602,7 +1602,6 @@ static int coredump_wait(int exit_code, struct core_state *core_state) | |||
1602 | struct completion *vfork_done; | 1602 | struct completion *vfork_done; |
1603 | int core_waiters; | 1603 | int core_waiters; |
1604 | 1604 | ||
1605 | init_completion(&mm->core_done); | ||
1606 | init_completion(&core_state->startup); | 1605 | init_completion(&core_state->startup); |
1607 | core_state->dumper.task = tsk; | 1606 | core_state->dumper.task = tsk; |
1608 | core_state->dumper.next = NULL; | 1607 | core_state->dumper.next = NULL; |
@@ -1628,6 +1627,27 @@ fail: | |||
1628 | return core_waiters; | 1627 | return core_waiters; |
1629 | } | 1628 | } |
1630 | 1629 | ||
1630 | static void coredump_finish(struct mm_struct *mm) | ||
1631 | { | ||
1632 | struct core_thread *curr, *next; | ||
1633 | struct task_struct *task; | ||
1634 | |||
1635 | next = mm->core_state->dumper.next; | ||
1636 | while ((curr = next) != NULL) { | ||
1637 | next = curr->next; | ||
1638 | task = curr->task; | ||
1639 | /* | ||
1640 | * see exit_mm(), curr->task must not see | ||
1641 | * ->task == NULL before we read ->next. | ||
1642 | */ | ||
1643 | smp_mb(); | ||
1644 | curr->task = NULL; | ||
1645 | wake_up_process(task); | ||
1646 | } | ||
1647 | |||
1648 | mm->core_state = NULL; | ||
1649 | } | ||
1650 | |||
1631 | /* | 1651 | /* |
1632 | * set_dumpable converts traditional three-value dumpable to two flags and | 1652 | * set_dumpable converts traditional three-value dumpable to two flags and |
1633 | * stores them into mm->flags. It modifies lower two bits of mm->flags, but | 1653 | * stores them into mm->flags. It modifies lower two bits of mm->flags, but |
@@ -1812,8 +1832,7 @@ fail_unlock: | |||
1812 | argv_free(helper_argv); | 1832 | argv_free(helper_argv); |
1813 | 1833 | ||
1814 | current->fsuid = fsuid; | 1834 | current->fsuid = fsuid; |
1815 | complete_all(&mm->core_done); | 1835 | coredump_finish(mm); |
1816 | mm->core_state = NULL; | ||
1817 | fail: | 1836 | fail: |
1818 | return retval; | 1837 | return retval; |
1819 | } | 1838 | } |
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 4d0d0abc79fe..746f975b58ef 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h | |||
@@ -229,9 +229,7 @@ struct mm_struct { | |||
229 | 229 | ||
230 | unsigned long flags; /* Must use atomic bitops to access the bits */ | 230 | unsigned long flags; /* Must use atomic bitops to access the bits */ |
231 | 231 | ||
232 | /* coredumping support */ | 232 | struct core_state *core_state; /* coredumping support */ |
233 | struct core_state *core_state; | ||
234 | struct completion core_done; | ||
235 | 233 | ||
236 | /* aio bits */ | 234 | /* aio bits */ |
237 | rwlock_t ioctx_list_lock; /* aio lock */ | 235 | rwlock_t ioctx_list_lock; /* aio lock */ |
diff --git a/kernel/exit.c b/kernel/exit.c index b66f0d55c791..8a4d4d12e294 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -691,7 +691,13 @@ static void exit_mm(struct task_struct * tsk) | |||
691 | if (atomic_dec_and_test(&core_state->nr_threads)) | 691 | if (atomic_dec_and_test(&core_state->nr_threads)) |
692 | complete(&core_state->startup); | 692 | complete(&core_state->startup); |
693 | 693 | ||
694 | wait_for_completion(&mm->core_done); | 694 | for (;;) { |
695 | set_task_state(tsk, TASK_UNINTERRUPTIBLE); | ||
696 | if (!self.task) /* see coredump_finish() */ | ||
697 | break; | ||
698 | schedule(); | ||
699 | } | ||
700 | __set_task_state(tsk, TASK_RUNNING); | ||
695 | down_read(&mm->mmap_sem); | 701 | down_read(&mm->mmap_sem); |
696 | } | 702 | } |
697 | atomic_inc(&mm->mm_count); | 703 | atomic_inc(&mm->mm_count); |