diff options
author | Oleg Nesterov <oleg@redhat.com> | 2010-03-05 16:44:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-06 14:26:46 -0500 |
commit | 5c99cbf49a6e1a1efd25b11f4604c65c455e1612 (patch) | |
tree | e2a3451cc87f83b15f23a0472339be81770e12da /fs/exec.c | |
parent | 30736a4d43f4af7f1a7836d6a266be17082195c4 (diff) |
coredump: set ->group_exit_code for other CLONE_VM tasks too
User visible change.
do_coredump() kills all threads which share the same ->mm but only the
coredumping process gets the proper exit_code. Other tasks which share
the same ->mm die "silently" and return status == 0 to parent.
This is historical behaviour, not actually a bug. But I think Frank
Heckenbach rightly dislikes the current behaviour. Simple test-case:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
int main(void)
{
int stat;
if (!fork()) {
if (!vfork())
kill(getpid(), SIGQUIT);
}
wait(&stat);
printf("stat=%x\n", stat);
return 0;
}
Before this patch it prints "stat=0" despite the fact the child was killed
by SIGQUIT. After this patch the output is "stat=3" which obviously makes
more sense.
Even with this patch, only the task which originates the coredumping gets
"|= 0x80" if the core was actually dumped, but at least the coredumping
signal is visible to do_wait/etc.
Reported-by: Frank Heckenbach <f.heckenbach@fh-soft.de>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: WANG Cong <xiyou.wangcong@gmail.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 8 |
1 files changed, 4 insertions, 4 deletions
@@ -1561,12 +1561,13 @@ out: | |||
1561 | return ispipe; | 1561 | return ispipe; |
1562 | } | 1562 | } |
1563 | 1563 | ||
1564 | static int zap_process(struct task_struct *start) | 1564 | static int zap_process(struct task_struct *start, int exit_code) |
1565 | { | 1565 | { |
1566 | struct task_struct *t; | 1566 | struct task_struct *t; |
1567 | int nr = 0; | 1567 | int nr = 0; |
1568 | 1568 | ||
1569 | start->signal->flags = SIGNAL_GROUP_EXIT; | 1569 | start->signal->flags = SIGNAL_GROUP_EXIT; |
1570 | start->signal->group_exit_code = exit_code; | ||
1570 | start->signal->group_stop_count = 0; | 1571 | start->signal->group_stop_count = 0; |
1571 | 1572 | ||
1572 | t = start; | 1573 | t = start; |
@@ -1591,8 +1592,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, | |||
1591 | spin_lock_irq(&tsk->sighand->siglock); | 1592 | spin_lock_irq(&tsk->sighand->siglock); |
1592 | if (!signal_group_exit(tsk->signal)) { | 1593 | if (!signal_group_exit(tsk->signal)) { |
1593 | mm->core_state = core_state; | 1594 | mm->core_state = core_state; |
1594 | tsk->signal->group_exit_code = exit_code; | 1595 | nr = zap_process(tsk, exit_code); |
1595 | nr = zap_process(tsk); | ||
1596 | } | 1596 | } |
1597 | spin_unlock_irq(&tsk->sighand->siglock); | 1597 | spin_unlock_irq(&tsk->sighand->siglock); |
1598 | if (unlikely(nr < 0)) | 1598 | if (unlikely(nr < 0)) |
@@ -1641,7 +1641,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, | |||
1641 | if (p->mm) { | 1641 | if (p->mm) { |
1642 | if (unlikely(p->mm == mm)) { | 1642 | if (unlikely(p->mm == mm)) { |
1643 | lock_task_sighand(p, &flags); | 1643 | lock_task_sighand(p, &flags); |
1644 | nr += zap_process(p); | 1644 | nr += zap_process(p, exit_code); |
1645 | unlock_task_sighand(p, &flags); | 1645 | unlock_task_sighand(p, &flags); |
1646 | } | 1646 | } |
1647 | break; | 1647 | break; |