diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2005-10-30 15:02:54 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-30 17:37:25 -0800 |
commit | 1291cf4163d21f1b4999d697cbf68d38e7151c28 (patch) | |
tree | 0e1c3e3970216c769f91f6077b0e23d47d6fd333 | |
parent | f7232056bff5fe2d3bfeab35252a66ebaeb5bbde (diff) |
[PATCH] fix de_thread() vs do_coredump() deadlock
de_thread() sends SIGKILL to all sub-threads and waits them to die in 'D'
state. It is possible that one of the threads already dequeued coredump
signal. When de_thread() unlocks ->sighand->lock that thread can enter
do_coredump()->coredump_wait() and cause a deadlock.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/exec.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/fs/exec.c b/fs/exec.c index 6d9521636aa..10d493fea7c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1460,11 +1460,21 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) current->fsuid = 0; /* Dump root private */ } mm->dumpable = 0; - init_completion(&mm->core_done); + + retval = -EAGAIN; spin_lock_irq(¤t->sighand->siglock); - current->signal->flags = SIGNAL_GROUP_EXIT; - current->signal->group_exit_code = exit_code; + if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) { + current->signal->flags = SIGNAL_GROUP_EXIT; + current->signal->group_exit_code = exit_code; + retval = 0; + } spin_unlock_irq(¤t->sighand->siglock); + if (retval) { + up_write(&mm->mmap_sem); + goto fail; + } + + init_completion(&mm->core_done); coredump_wait(mm); /* |