diff --git a/fs/exec.c b/fs/exec.c index fe2873b8037f295ec536e648191ce5218630de92..bff43aeb235e46e95eaa48571279960ef5185bfb 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1602,7 +1602,6 @@ static int coredump_wait(int exit_code, struct core_state *core_state) struct completion *vfork_done; int core_waiters; - init_completion(&mm->core_done); init_completion(&core_state->startup); core_state->dumper.task = tsk; core_state->dumper.next = NULL; @@ -1628,6 +1627,27 @@ static int coredump_wait(int exit_code, struct core_state *core_state) return core_waiters; } +static void coredump_finish(struct mm_struct *mm) +{ + struct core_thread *curr, *next; + struct task_struct *task; + + next = mm->core_state->dumper.next; + while ((curr = next) != NULL) { + next = curr->next; + task = curr->task; + /* + * see exit_mm(), curr->task must not see + * ->task == NULL before we read ->next. + */ + smp_mb(); + curr->task = NULL; + wake_up_process(task); + } + + mm->core_state = NULL; +} + /* * set_dumpable converts traditional three-value dumpable to two flags and * stores them into mm->flags. It modifies lower two bits of mm->flags, but @@ -1812,8 +1832,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) argv_free(helper_argv); current->fsuid = fsuid; - complete_all(&mm->core_done); - mm->core_state = NULL; + coredump_finish(mm); fail: return retval; } diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 4d0d0abc79fe28875e701444acdd3e701623a7ee..746f975b58ef3a4843b00622dbfa1958f1000074 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -229,9 +229,7 @@ struct mm_struct { unsigned long flags; /* Must use atomic bitops to access the bits */ - /* coredumping support */ - struct core_state *core_state; - struct completion core_done; + struct core_state *core_state; /* coredumping support */ /* aio bits */ rwlock_t ioctx_list_lock; /* aio lock */ diff --git a/kernel/exit.c b/kernel/exit.c index b66f0d55c7919c1eff2fed2284c782ae18f61f03..8a4d4d12e29456701990729d6c7dc7859767b929 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -691,7 +691,13 @@ static void exit_mm(struct task_struct * tsk) if (atomic_dec_and_test(&core_state->nr_threads)) complete(&core_state->startup); - wait_for_completion(&mm->core_done); + for (;;) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!self.task) /* see coredump_finish() */ + break; + schedule(); + } + __set_task_state(tsk, TASK_RUNNING); down_read(&mm->mmap_sem); } atomic_inc(&mm->mm_count);